diff --git a/docs/jobs-unification.md b/docs/jobs-unification.md index 581a5f88..1c4945d0 100644 --- a/docs/jobs-unification.md +++ b/docs/jobs-unification.md @@ -28,6 +28,11 @@ Favor power-user affordances over guardrails. See memory `sole-user-assume-compe navigates there instead of mounting the modal. One code path, phone-friendly. - **Deep-link:** query params, not hash — `/jobs/new?task=convert-video&root=home&path=&entry=`. - **Phone:** already has a file browser, so it can pick a target path and POST a job. No blocker. +- **`inline` tasks stay in the modal.** A top-level `inline: true` in `TASK.md` marks quick/interactive + tasks that run in the modal (ephemeral) instead of as a job. Default = job. Currently flagged: + `remove-jelly-meta`, `analyze-video`, `clean-playlist-files`. So the modal is **not** retired — it's + the inline path; the shared input form serves both the modal and `/jobs/new`. The flag is plumbed + through the parser + task list/detail endpoints (`task.inline`), so the FileBrowser menu can branch. ## Plan @@ -76,6 +81,8 @@ Favor power-user affordances over guardrails. See memory `sole-user-assume-compe `PipelineJobDetail`). Script jobs are now viewable at `/jobs/:id`. - [ ] 3b `/jobs/new` page — extract the input UI (TaskInputForm + per-group config + folder probing) from `TaskRunnerModal` into a shared component; Run/Queue → `POST /jobs` → navigate. - - [ ] 3c FileBrowser task action navigates to `/jobs/new?...`; retire modal/dialog/useTaskRunner. + - [x] `inline` flag plumbed (parser + list/detail endpoints); 3 quick tasks flagged. + - [ ] 3c FileBrowser task action: `task.inline ? openModal : navigate('/jobs/new?...')`. Modal stays + for inline tasks (not retired); shared input form used by both. - [ ] 3d header running-jobs indicator (`GET /jobs?live=1`). - [ ] 4 push notifications diff --git a/src/servers/api/tasks/task-files.ts b/src/servers/api/tasks/task-files.ts index 94e85d6c..f808e3b1 100644 --- a/src/servers/api/tasks/task-files.ts +++ b/src/servers/api/tasks/task-files.ts @@ -13,6 +13,7 @@ export type TaskFrontmatter = { description: string | null; version: number; mode: string; + inline: boolean; // quick/interactive tasks run in the modal instead of as a background job language: string | null; args: string[] | null; tags: string[] | null; @@ -37,6 +38,7 @@ export type TaskSummary = { name: string; description: string | null; mode: string; + inline: boolean; version: number; trigger: unknown; }; @@ -47,6 +49,7 @@ const FM_KEYS = [ 'description', 'version', 'mode', + 'inline', 'language', 'args', 'tags', @@ -105,6 +108,7 @@ function parseTaskMd(raw: string): { fm: TaskFrontmatter; body: string } { description: parsed.description == null ? null : String(parsed.description), version, mode: parsed.mode == null ? 'agentic' : String(parsed.mode), + inline: parsed.inline === true, language: parsed.language == null ? null : String(parsed.language), args: asArray(parsed.args), tags: asArray(parsed.tags), @@ -160,6 +164,7 @@ export async function listTasks(): Promise { name: fm.name || entry.name, description: fm.description, mode: fm.mode, + inline: fm.inline, version: fm.version, trigger: fm.trigger ?? [], }); @@ -205,6 +210,7 @@ export async function createTask(input: CreateTaskInput): Promise { name: task.name, description: task.description, mode: task.mode, + inline: task.inline, language: task.language, body: task.body, implementation: task.implementation,