@astralyn/pi 0.84.5 → 0.84.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +4 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +11 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/tools/bash.d.ts +5 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/extensions/background/index.d.ts +95 -20
- package/dist/extensions/background/index.d.ts.map +1 -1
- package/dist/extensions/background/index.js +470 -136
- package/dist/extensions/background/index.js.map +1 -1
- package/dist/extensions/background/manager.d.ts +14 -0
- package/dist/extensions/background/manager.d.ts.map +1 -1
- package/dist/extensions/background/manager.js +125 -24
- package/dist/extensions/background/manager.js.map +1 -1
- package/dist/extensions/background/registry.d.ts +82 -0
- package/dist/extensions/background/registry.d.ts.map +1 -1
- package/dist/extensions/background/registry.js +237 -6
- package/dist/extensions/background/registry.js.map +1 -1
- package/dist/extensions/background/render.d.ts +35 -11
- package/dist/extensions/background/render.d.ts.map +1 -1
- package/dist/extensions/background/render.js +172 -30
- package/dist/extensions/background/render.js.map +1 -1
- package/dist/extensions/subagent/activity.d.ts +3 -5
- package/dist/extensions/subagent/activity.d.ts.map +1 -1
- package/dist/extensions/subagent/activity.js +8 -89
- package/dist/extensions/subagent/activity.js.map +1 -1
- package/dist/extensions/subagent/agents-command.d.ts.map +1 -1
- package/dist/extensions/subagent/agents-command.js +40 -94
- package/dist/extensions/subagent/agents-command.js.map +1 -1
- package/dist/extensions/subagent/agents.d.ts +2 -0
- package/dist/extensions/subagent/agents.d.ts.map +1 -1
- package/dist/extensions/subagent/agents.js +7 -1
- package/dist/extensions/subagent/agents.js.map +1 -1
- package/dist/extensions/subagent/budget.d.ts +15 -0
- package/dist/extensions/subagent/budget.d.ts.map +1 -0
- package/dist/extensions/subagent/budget.js +96 -0
- package/dist/extensions/subagent/budget.js.map +1 -0
- package/dist/extensions/subagent/cancellation.d.ts +29 -0
- package/dist/extensions/subagent/cancellation.d.ts.map +1 -0
- package/dist/extensions/subagent/cancellation.js +73 -0
- package/dist/extensions/subagent/cancellation.js.map +1 -0
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +5 -22
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/model-selection.d.ts +16 -0
- package/dist/extensions/subagent/model-selection.d.ts.map +1 -0
- package/dist/extensions/subagent/model-selection.js +51 -0
- package/dist/extensions/subagent/model-selection.js.map +1 -0
- package/dist/extensions/subagent/render.d.ts +6 -1
- package/dist/extensions/subagent/render.d.ts.map +1 -1
- package/dist/extensions/subagent/render.js +23 -12
- package/dist/extensions/subagent/render.js.map +1 -1
- package/dist/extensions/subagent/resolve.d.ts.map +1 -1
- package/dist/extensions/subagent/resolve.js +2 -21
- package/dist/extensions/subagent/resolve.js.map +1 -1
- package/dist/extensions/subagent/runner.d.ts +4 -5
- package/dist/extensions/subagent/runner.d.ts.map +1 -1
- package/dist/extensions/subagent/runner.js +71 -264
- package/dist/extensions/subagent/runner.js.map +1 -1
- package/dist/extensions/subagent/sdk-runner.d.ts +13 -11
- package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
- package/dist/extensions/subagent/sdk-runner.js +167 -148
- package/dist/extensions/subagent/sdk-runner.js.map +1 -1
- package/dist/extensions/subagent/state.d.ts +89 -0
- package/dist/extensions/subagent/state.d.ts.map +1 -0
- package/dist/extensions/subagent/state.js +294 -0
- package/dist/extensions/subagent/state.js.map +1 -0
- package/dist/extensions/subagent/text.d.ts +4 -0
- package/dist/extensions/subagent/text.d.ts.map +1 -1
- package/dist/extensions/subagent/text.js +75 -0
- package/dist/extensions/subagent/text.js.map +1 -1
- package/dist/extensions/subagent/types.d.ts +3 -8
- package/dist/extensions/subagent/types.d.ts.map +1 -1
- package/dist/extensions/subagent/types.js.map +1 -1
- package/dist/extensions/subagent/ui/choices.d.ts +36 -0
- package/dist/extensions/subagent/ui/choices.d.ts.map +1 -0
- package/dist/extensions/subagent/ui/choices.js +54 -0
- package/dist/extensions/subagent/ui/choices.js.map +1 -0
- package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
- package/dist/extensions/subagent/ui/model-list.js +10 -18
- package/dist/extensions/subagent/ui/model-list.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/docs/bundled/README.md +1 -1
- package/docs/bundled/extensions/background.md +55 -20
- package/docs/extensions.md +13 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/extensions/subagent/retry.d.ts +0 -17
- package/dist/extensions/subagent/retry.d.ts.map +0 -1
- package/dist/extensions/subagent/retry.js +0 -41
- package/dist/extensions/subagent/retry.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/background/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * background — run bash commands in the background.\n *\n * Tools: bg_bash starts a task and returns immediately; the result arrives as\n * a <background-task> notification (queued behind the current run while\n * streaming, waking the agent when idle). bg_logs reads a bounded slice of a\n * task's output file; bg_kill stops a single task. /bg opens the interactive\n * task manager. Running counts surface in the footer via ctx.ui.setStatus.\n */\n\nimport { type Static, Type } from \"typebox\";\nimport { getAgentDir } from \"../../config.ts\";\nimport type {\n\tAgentToolResult,\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n} from \"../../core/extensions/types.ts\";\nimport { SettingsManager } from \"../../core/settings-manager.ts\";\nimport { type BashOperations, createLocalBashOperations, resolveSpawnContext } from \"../../core/tools/bash.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize } from \"../../core/tools/truncate.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport { BackgroundTasksMenu } from \"./manager.ts\";\nimport {\n\tBackgroundTaskRegistry,\n\ttype BgTask,\n\ttype BgTaskNotification,\n\ttype BgTaskStatus,\n\tformatDuration,\n\ttype ResolveTaskResult,\n\treadOutputSlice,\n} from \"./registry.ts\";\nimport {\n\tcommandLabel,\n\trenderBackgroundNotification,\n\trenderBgBashCall,\n\trenderBgBashResult,\n\trenderBgKillCall,\n\trenderBgLogsCall,\n} from \"./render.ts\";\n\nexport const BG_NOTIFICATION_TYPE = \"background-task\";\nconst BG_LOGS_DEFAULT_BYTES = 8 * 1024;\nconst BG_LOGS_MIN_BYTES = 256;\n\nconst bgBashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to run in the background\" }),\n\ttimeout: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription:\n\t\t\t\t\"Timeout in seconds (optional, no default; must be positive). On expiry the task is killed and reported as timeout.\",\n\t\t}),\n\t),\n});\n\nconst bgLogsSchema = Type.Object({\n\ttaskId: Type.String({ description: \"Task id; a unique prefix is accepted (e.g. 'bg-3f' or '3f')\" }),\n\tmode: Type.Optional(\n\t\tType.Union([Type.Literal(\"tail\"), Type.Literal(\"head\")], {\n\t\t\tdescription: \"Read from the end (default) or the start of the output\",\n\t\t}),\n\t),\n\tbytes: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription: `Max bytes to return (default ${BG_LOGS_DEFAULT_BYTES}, max ${DEFAULT_MAX_BYTES})`,\n\t\t}),\n\t),\n});\n\nconst bgKillSchema = Type.Object({\n\ttaskId: Type.String({ description: \"Task id; a unique prefix is accepted\" }),\n});\n\nexport type BgBashInput = Static<typeof bgBashSchema>;\nexport type BgLogsInput = Static<typeof bgLogsSchema>;\nexport type BgKillInput = Static<typeof bgKillSchema>;\n\nexport interface BgBashDetails {\n\ttaskId: string;\n\toutputPath: string;\n\tcommand: string;\n}\n\nexport interface BgLogsDetails {\n\ttaskId: string;\n\tmode: \"head\" | \"tail\";\n\tsliceBytes: number;\n\ttotalBytes: number;\n\toutputPath: string;\n}\n\nexport interface BgKillDetails {\n\ttaskId: string;\n\tcommand: string;\n}\n\nexport interface BgNotificationDetails {\n\ttaskId: string;\n\tcommand: string;\n\tstatus: BgTaskStatus;\n\texitCode: number | null | undefined;\n\truntimeMs: number;\n\toutputPath: string;\n\ttotalBytes: number;\n\ttailText: string;\n\ttailTruncated: boolean;\n\terror?: string;\n\ttailError?: string;\n}\n\nexport function escapeXml(text: string): string {\n\treturn text\n\t\t.replaceAll(\"&\", \"&\")\n\t\t.replaceAll(\"<\", \"<\")\n\t\t.replaceAll(\">\", \">\")\n\t\t.replaceAll('\"', \""\")\n\t\t.replaceAll(\"'\", \"'\");\n}\n\nexport function buildNotificationContent(notification: BgTaskNotification): string {\n\tconst task = notification.task;\n\tconst runtime = formatDuration((task.endedAt ?? task.startedAt) - task.startedAt);\n\tconst exitCode = task.exitCode === undefined || task.exitCode === null ? \"\" : ` exitCode=\"${task.exitCode}\"`;\n\tconst lines = [\n\t\t`<background-task id=\"${task.id}\" status=\"${task.status}\"${exitCode} runtime=\"${runtime}\">`,\n\t\t`<command>${escapeXml(task.command)}</command>`,\n\t\t`<output-file>${escapeXml(task.outputPath)}</output-file>`,\n\t];\n\tif (task.error) {\n\t\tlines.push(`<error>${escapeXml(task.error)}</error>`);\n\t}\n\tif (notification.tailError) {\n\t\tlines.push(`<output-tail unavailable=\"${escapeXml(notification.tailError)}\"/>`);\n\t} else {\n\t\tconst attrs = [\n\t\t\t`bytes=\"${notification.tailBytes}\"`,\n\t\t\t`totalBytes=\"${notification.totalBytes}\"`,\n\t\t\tnotification.tailTruncated ? 'truncated=\"true\"' : \"\",\n\t\t\tnotification.tailStartsMidLine ? 'startsMidLine=\"true\"' : \"\",\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\tconst tail = notification.tailText.length > 0 ? escapeXml(notification.tailText) : \"(no output)\";\n\t\tlines.push(`<output-tail ${attrs}>`, tail.trimEnd(), \"</output-tail>\");\n\t}\n\tlines.push(\"</background-task>\");\n\treturn lines.join(\"\\n\");\n}\n\nexport function formatStatusline(counts: { running: number; total: number }): string | undefined {\n\tif (counts.total === 0) return undefined;\n\tconst ended = counts.total - counts.running;\n\tconst parts: string[] = [];\n\tif (counts.running > 0) parts.push(`${counts.running} running`);\n\tif (ended > 0) parts.push(`${ended} done`);\n\treturn `bg ${parts.join(\" · \")}`;\n}\n\nfunction describeResolveFailure(input: string, result: ResolveTaskResult & { ok: false }): string {\n\tif (result.reason === \"ambiguous\") {\n\t\tconst lines = result.candidates.map((task) => ` ${task.id} (${task.status}) ${commandLabel(task.command, 60)}`);\n\t\treturn `Task id \"${input}\" is ambiguous. Candidates:\\n${lines.join(\"\\n\")}`;\n\t}\n\treturn `No background task matches \"${input}\". Check the id returned by bg_bash or open /bg.`;\n}\n\nfunction describeTaskLine(task: BgTask, now: number): string {\n\tconst duration = formatDuration((task.endedAt ?? now) - task.startedAt);\n\tconst exit = task.exitCode !== undefined && task.exitCode !== null ? ` exit ${task.exitCode}` : \"\";\n\treturn ` ${task.id} ${task.status}${exit} ${duration} ${commandLabel(task.command, 40)}`;\n}\n\nfunction toNotificationDetails(notification: BgTaskNotification): BgNotificationDetails {\n\tconst task = notification.task;\n\treturn {\n\t\ttaskId: task.id,\n\t\tcommand: task.command,\n\t\tstatus: task.status,\n\t\texitCode: task.exitCode,\n\t\truntimeMs: (task.endedAt ?? task.startedAt) - task.startedAt,\n\t\toutputPath: task.outputPath,\n\t\ttotalBytes: notification.totalBytes,\n\t\ttailText: notification.tailText,\n\t\ttailTruncated: notification.tailTruncated,\n\t\terror: task.error,\n\t\ttailError: notification.tailError,\n\t};\n}\n\nexport interface BackgroundExtensionOverrides {\n\toperations?: BashOperations;\n\toutputDir?: string;\n\tmaxOutputBytes?: number;\n}\n\n/** Local shell operations honoring the session's configured shell path. */\nfunction createSessionBashOperations(ctx: ExtensionContext): BashOperations {\n\tconst settings = SettingsManager.create(ctx.cwd, getAgentDir(), {\n\t\tprojectTrusted: ctx.isProjectTrusted(),\n\t});\n\treturn createLocalBashOperations({ shellPath: settings.getShellPath() });\n}\n\n/** Factory with injectable seams for tests; the default export uses production wiring. */\nexport function createBackgroundExtension(overrides?: BackgroundExtensionOverrides): (pi: ExtensionAPI) => void {\n\treturn (pi: ExtensionAPI) => {\n\t\tlet registry: BackgroundTaskRegistry | undefined;\n\t\tlet sessionCtx: ExtensionContext | undefined;\n\n\t\tconst requireRegistry = (): BackgroundTaskRegistry => {\n\t\t\tif (!registry) throw new Error(\"Background tasks are not available yet (no active session).\");\n\t\t\treturn registry;\n\t\t};\n\n\t\tconst resolveTaskOrThrow = (taskId: string): BgTask => {\n\t\t\tconst resolved = requireRegistry().resolveTask(taskId);\n\t\t\tif (!resolved.ok) throw new Error(describeResolveFailure(taskId, resolved));\n\t\t\treturn resolved.task;\n\t\t};\n\n\t\tconst updateStatus = () => {\n\t\t\tif (!registry || registry.isShuttingDown) return;\n\t\t\tsessionCtx?.ui.setStatus(\"background\", formatStatusline(registry.counts()));\n\t\t};\n\n\t\tpi.on(\"session_start\", (_event, ctx) => {\n\t\t\tsessionCtx = ctx;\n\t\t\t// Defensive: a leftover registry (session_shutdown not seen) must not leak processes.\n\t\t\tif (registry) void registry.shutdown();\n\t\t\tregistry = new BackgroundTaskRegistry({\n\t\t\t\toperations: overrides?.operations ?? createSessionBashOperations(ctx),\n\t\t\t\toutputDir: overrides?.outputDir,\n\t\t\t\tmaxOutputBytes: overrides?.maxOutputBytes,\n\t\t\t\tonNotify: (notification) => {\n\t\t\t\t\tpi.sendMessage(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcustomType: BG_NOTIFICATION_TYPE,\n\t\t\t\t\t\t\tcontent: buildNotificationContent(notification),\n\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tdetails: toNotificationDetails(notification),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ deliverAs: \"followUp\", triggerTurn: true },\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tonChange: updateStatus,\n\t\t\t});\n\t\t\tupdateStatus();\n\t\t});\n\n\t\tpi.on(\"session_shutdown\", async (_event, ctx) => {\n\t\t\tctx.ui.setStatus(\"background\", undefined);\n\t\t\tsessionCtx = undefined;\n\t\t\tconst active = registry;\n\t\t\tregistry = undefined;\n\t\t\tawait active?.shutdown();\n\t\t});\n\n\t\tpi.registerTool<typeof bgBashSchema, BgBashDetails>({\n\t\t\tname: \"bg_bash\",\n\t\t\tlabel: \"bg bash\",\n\t\t\tdescription:\n\t\t\t\t\"Run a bash command in the background and return immediately with a task id and output file path. \" +\n\t\t\t\t\"The result (status, exit code, output tail) arrives automatically as a <background-task> notification \" +\n\t\t\t\t\"when the task ends. Use for long-running commands such as dev servers, watch builds, or slow tests. \" +\n\t\t\t\t\"Optionally provide a timeout in seconds.\",\n\t\t\tpromptSnippet: \"Run bash commands in the background (bg_bash); results arrive automatically\",\n\t\t\tpromptGuidelines: [\n\t\t\t\t\"Use bg_bash for long-running commands (servers, builds, slow tests). Never poll for completion with sleep loops or repeated bg_logs; the <background-task> notification arrives automatically when the task ends. Use bg_logs for an early peek at a running task and bg_kill to stop one.\",\n\t\t\t],\n\t\t\tparameters: bgBashSchema,\n\t\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx): Promise<AgentToolResult<BgBashDetails>> {\n\t\t\t\tif (params.timeout !== undefined && (!Number.isFinite(params.timeout) || params.timeout <= 0)) {\n\t\t\t\t\tthrow new Error(\"Invalid timeout: must be a positive number of seconds.\");\n\t\t\t\t}\n\t\t\t\t// Same PI_* session variables as the built-in bash tool, snapshotted at start.\n\t\t\t\tconst spawnContext = resolveSpawnContext(params.command, ctx.cwd, undefined, true, ctx);\n\t\t\t\t// Deliberately ignore the turn signal: aborting the current turn must\n\t\t\t\t// not kill the background task (that is what bg_kill is for).\n\t\t\t\tconst task = requireRegistry().startTask({\n\t\t\t\t\tcommand: params.command,\n\t\t\t\t\tcwd: ctx.cwd,\n\t\t\t\t\ttimeoutSeconds: params.timeout,\n\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t});\n\t\t\t\tconst text = [\n\t\t\t\t\t`Started background task ${task.id}.`,\n\t\t\t\t\t`Output file: ${task.outputPath}`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"Do NOT poll for completion (no sleep loops, no repeated bg_logs). A <background-task> \" +\n\t\t\t\t\t\t\"notification with the result and output tail arrives automatically when the task ends — \" +\n\t\t\t\t\t\t\"continue independent work or end the turn. Use bg_logs for an early peek, bg_kill to stop it.\",\n\t\t\t\t].join(\"\\n\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\t\tdetails: { taskId: task.id, outputPath: task.outputPath, command: params.command },\n\t\t\t\t};\n\t\t\t},\n\t\t\trenderCall(args, theme, context) {\n\t\t\t\treturn renderBgBashCall(args, theme, context);\n\t\t\t},\n\t\t\trenderResult(result, options, theme, context) {\n\t\t\t\treturn renderBgBashResult(result, options, theme, context);\n\t\t\t},\n\t\t});\n\n\t\tpi.registerTool<typeof bgLogsSchema, BgLogsDetails>({\n\t\t\tname: \"bg_logs\",\n\t\t\tlabel: \"bg logs\",\n\t\t\tdescription:\n\t\t\t\t`Read a bounded slice of a background task's output file (default: last ${formatSize(BG_LOGS_DEFAULT_BYTES)}, ` +\n\t\t\t\t`max ${formatSize(DEFAULT_MAX_BYTES)}). Works while the task is still running. ` +\n\t\t\t\t\"Do not call this in a polling loop; completion arrives as a notification.\",\n\t\t\tparameters: bgLogsSchema,\n\t\t\tasync execute(_toolCallId, params, _signal, _onUpdate, _ctx): Promise<AgentToolResult<BgLogsDetails>> {\n\t\t\t\tconst task = resolveTaskOrThrow(params.taskId);\n\t\t\t\tconst mode = params.mode ?? \"tail\";\n\t\t\t\tconst maxBytes = Math.min(\n\t\t\t\t\tDEFAULT_MAX_BYTES,\n\t\t\t\t\tMath.max(BG_LOGS_MIN_BYTES, Math.floor(params.bytes ?? BG_LOGS_DEFAULT_BYTES)),\n\t\t\t\t);\n\t\t\t\tlet slice: Awaited<ReturnType<typeof readOutputSlice>>;\n\t\t\t\ttry {\n\t\t\t\t\tslice = await readOutputSlice(task.outputPath, { mode, maxBytes });\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Could not read output for ${task.id} (${task.status}): ${message}\\nOutput file: ${task.outputPath}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst text = sanitizeBinaryOutput(slice.text);\n\t\t\t\tconst noticeParts = slice.truncated\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t`${mode} ${formatSize(slice.sliceBytes)} of ${formatSize(slice.totalBytes)}`,\n\t\t\t\t\t\t\t`task ${task.id} ${task.status}`,\n\t\t\t\t\t\t\t...(slice.startsMidLine ? [\"first line may be partial\"] : []),\n\t\t\t\t\t\t\t`full output: ${task.outputPath}`,\n\t\t\t\t\t\t]\n\t\t\t\t\t: [\n\t\t\t\t\t\t\t`task ${task.id} ${task.status}`,\n\t\t\t\t\t\t\t`${formatSize(slice.totalBytes)} total`,\n\t\t\t\t\t\t\t`output: ${task.outputPath}`,\n\t\t\t\t\t\t];\n\t\t\t\tconst body = text.length > 0 ? text : \"(no output yet)\";\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `[${noticeParts.join(\" · \")}]\\n${body}` }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttaskId: task.id,\n\t\t\t\t\t\tmode,\n\t\t\t\t\t\tsliceBytes: slice.sliceBytes,\n\t\t\t\t\t\ttotalBytes: slice.totalBytes,\n\t\t\t\t\t\toutputPath: task.outputPath,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t},\n\t\t\trenderCall(args, theme) {\n\t\t\t\treturn renderBgLogsCall(args, theme);\n\t\t\t},\n\t\t});\n\n\t\tpi.registerTool<typeof bgKillSchema, BgKillDetails>({\n\t\t\tname: \"bg_kill\",\n\t\t\tlabel: \"bg kill\",\n\t\t\tdescription:\n\t\t\t\t\"Kill a running background task (the whole process tree). The terminal status and output tail \" +\n\t\t\t\t\"still arrive as the task's completion notification.\",\n\t\t\tparameters: bgKillSchema,\n\t\t\tasync execute(_toolCallId, params, _signal, _onUpdate, _ctx): Promise<AgentToolResult<BgKillDetails>> {\n\t\t\t\tconst task = resolveTaskOrThrow(params.taskId);\n\t\t\t\tconst result = requireRegistry().killTask(task.id);\n\t\t\t\tif (!result.killed) {\n\t\t\t\t\tconst exit = task.exitCode !== undefined && task.exitCode !== null ? `, exit ${task.exitCode}` : \"\";\n\t\t\t\t\tthrow new Error(`Task ${task.id} is not running (status: ${task.status}${exit}).`);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Killed task ${task.id}. A completion notification follows once the process tree is reaped.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { taskId: task.id, command: task.command },\n\t\t\t\t};\n\t\t\t},\n\t\t\trenderCall(args, theme) {\n\t\t\t\treturn renderBgKillCall(args, theme);\n\t\t\t},\n\t\t});\n\n\t\tpi.registerMessageRenderer<BgNotificationDetails>(BG_NOTIFICATION_TYPE, renderBackgroundNotification);\n\n\t\tpi.registerCommand(\"bg\", {\n\t\t\tdescription: \"View and manage background tasks\",\n\t\t\thandler: async (_args, ctx: ExtensionCommandContext) => {\n\t\t\t\tconst active = registry;\n\t\t\t\tif (!active || active.counts().total === 0) {\n\t\t\t\t\tctx.ui.notify(\"No background tasks.\", \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (ctx.mode !== \"tui\") {\n\t\t\t\t\t// RPC/print: ctx.ui.custom is unavailable — show a bounded summary.\n\t\t\t\t\tconst lines = active\n\t\t\t\t\t\t.listTasks()\n\t\t\t\t\t\t.slice(0, 10)\n\t\t\t\t\t\t.map((task) => describeTaskLine(task, Date.now()));\n\t\t\t\t\tctx.ui.notify(`Background tasks:\\n${lines.join(\"\\n\")}\\nUse bg_kill <id> to stop a task.`, \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait showBackgroundManager(ctx, active);\n\t\t\t},\n\t\t});\n\t};\n}\n\nasync function showBackgroundManager(ctx: ExtensionCommandContext, registry: BackgroundTaskRegistry): Promise<void> {\n\t// No overlay options: the component mounts inline in the editor slot, like /model.\n\tawait ctx.ui.custom(\n\t\t(tui, theme, keybindings, done) =>\n\t\t\tnew BackgroundTasksMenu({\n\t\t\t\ttui,\n\t\t\t\ttheme,\n\t\t\t\tkeybindings,\n\t\t\t\thost: {\n\t\t\t\t\tlistTasks: () => registry.listTasks(),\n\t\t\t\t\tkillTask: (id) => registry.killTask(id),\n\t\t\t\t\treadSlice: (filePath, options) => readOutputSlice(filePath, options),\n\t\t\t\t},\n\t\t\t\tonClose: () => done(undefined),\n\t\t\t}),\n\t);\n}\n\nexport default createBackgroundExtension();\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/background/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * background — run bash commands in the background.\n *\n * Tools: a single `bg` tool with five actions. create starts a task and\n * returns immediately; the result arrives as a <background-task> notification\n * (queued behind the current run while streaming, waking the agent when\n * idle). read returns a bounded slice of a task's output file; wait blocks\n * (bounded) for a task's completion and delivers it inline — the followUp\n * notification is suppressed so the completion is delivered exactly once;\n * kill stops a single task; list enumerates known tasks. /bg opens the\n * interactive task manager. Running counts surface in the footer via\n * ctx.ui.setStatus.\n */\n\nimport { type Static, Type } from \"typebox\";\nimport { getAgentDir } from \"../../config.ts\";\nimport type {\n\tAgentToolResult,\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n} from \"../../core/extensions/types.ts\";\nimport { SettingsManager } from \"../../core/settings-manager.ts\";\nimport {\n\ttype BashOperations,\n\tcreateLocalBashOperations,\n\tMAX_TIMEOUT_SECONDS,\n\tresolveSpawnContext,\n} from \"../../core/tools/bash.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize } from \"../../core/tools/truncate.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport { BackgroundTasksMenu } from \"./manager.ts\";\nimport {\n\tBackgroundTaskRegistry,\n\tBG_WAIT_DEFAULT_MS,\n\tBG_WAIT_MAX_MS,\n\tBG_WAIT_MIN_MS,\n\ttype BgStallNotification,\n\ttype BgTask,\n\ttype BgTaskNotification,\n\ttype BgTaskStatus,\n\tfirstCommandLine,\n\tformatDuration,\n\ttype ResolveTaskResult,\n\treadOutputSince,\n\treadOutputSlice,\n} from \"./registry.ts\";\nimport {\n\tcommandLabel,\n\trenderBackgroundNotification,\n\trenderBgCall,\n\trenderBgResult,\n\ttype WaitLiveProbe,\n} from \"./render.ts\";\n\nexport const BG_NOTIFICATION_TYPE = \"background-task\";\nconst BG_LOGS_DEFAULT_BYTES = 8 * 1024;\nconst BG_LOGS_MIN_BYTES = 256;\nconst BG_LIST_FINISHED_SHOWN = 5;\n/** Bounded output delta returned by a successful wait. */\nconst BG_WAIT_DELTA_BYTES = 32 * 1024;\n/** Tail peek included in a wait timeout result so progress stays visible. */\nconst BG_WAIT_PEEK_BYTES = 2 * 1024;\n\nconst bgSchema = Type.Object({\n\taction: Type.Union(\n\t\t[Type.Literal(\"create\"), Type.Literal(\"read\"), Type.Literal(\"wait\"), Type.Literal(\"kill\"), Type.Literal(\"list\")],\n\t\t{ description: \"Which background-task operation to perform\" },\n\t),\n\t// — create —\n\tcommand: Type.Optional(\n\t\tType.String({ description: \"Bash command to run in the background (create). Do not append '&'\" }),\n\t),\n\tdescription: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Short label for the task, shown in /bg and notifications, e.g. 'dev server' (create)\",\n\t\t}),\n\t),\n\ttimeout: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription: \"Kill the task after this many seconds; on expiry it is reported as timeout (create)\",\n\t\t}),\n\t),\n\t// — read / wait / kill —\n\ttaskId: Type.Optional(\n\t\tType.String({ description: \"Task id; a unique prefix is accepted, e.g. 'bg-3f' or '3f' (read/wait/kill)\" }),\n\t),\n\t// — read —\n\tmode: Type.Optional(\n\t\tType.Union([Type.Literal(\"tail\"), Type.Literal(\"head\")], {\n\t\t\tdescription: \"Read from the end (default) or the start of the output (read)\",\n\t\t}),\n\t),\n\tbytes: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription: `Max bytes to return (read, default ${formatSize(BG_LOGS_DEFAULT_BYTES)}, max ${formatSize(DEFAULT_MAX_BYTES)})`,\n\t\t}),\n\t),\n\t// — wait —\n\twaitMs: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription: `Max time to wait in ms, default ${BG_WAIT_DEFAULT_MS}, max ${BG_WAIT_MAX_MS} (wait)`,\n\t\t}),\n\t),\n\tsinceBytes: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription:\n\t\t\t\t\"Only return output written after this byte offset — take it from a previous read/wait result (wait)\",\n\t\t}),\n\t),\n});\n\nexport type BgInput = Static<typeof bgSchema>;\n\n/** Per-action inputs: validateAction guarantees the required fields before the cast. */\nexport type BgCreateInput = BgInput & { action: \"create\"; command: string };\nexport type BgReadInput = BgInput & { action: \"read\"; taskId: string };\nexport type BgWaitInput = BgInput & { action: \"wait\"; taskId: string };\nexport type BgKillInput = BgInput & { action: \"kill\"; taskId: string };\n\nexport interface BgCreateDetails {\n\taction: \"create\";\n\ttaskId: string;\n\toutputPath: string;\n\tcommand: string;\n\tdescription?: string;\n}\n\nexport interface BgReadDetails {\n\taction: \"read\";\n\ttaskId: string;\n\tmode: \"head\" | \"tail\";\n\tsliceBytes: number;\n\ttotalBytes: number;\n\toutputPath: string;\n}\n\nexport interface BgWaitDetails {\n\taction: \"wait\";\n\ttaskId: string;\n\t/** True when the wait window expired and the task is still running. */\n\ttimedOut: boolean;\n\tstatus: BgTaskStatus;\n\texitCode: number | null | undefined;\n\twaitedMs: number;\n\tdeltaBytes: number;\n\ttotalBytes: number;\n\tdeltaTruncated: boolean;\n\toutputPath: string;\n}\n\nexport interface BgKillDetails {\n\taction: \"kill\";\n\ttaskId: string;\n\tcommand: string;\n}\n\nexport interface BgListDetails {\n\taction: \"list\";\n\trunning: number;\n\tfinished: number;\n\tshown: number;\n\thidden: number;\n}\n\nexport type BgDetails = BgCreateDetails | BgReadDetails | BgWaitDetails | BgKillDetails | BgListDetails;\n\nexport interface BgNotificationDetails {\n\ttaskId: string;\n\tcommand: string;\n\tdescription?: string;\n\tstatus: BgTaskStatus;\n\t/** True for the one-shot \"waiting for interactive input\" signal; the task keeps running. */\n\tstalled?: true;\n\texitCode: number | null | undefined;\n\truntimeMs: number;\n\toutputPath: string;\n\ttotalBytes: number;\n\ttailText: string;\n\ttailTruncated: boolean;\n\terror?: string;\n\ttailError?: string;\n}\n\nexport function escapeXml(text: string): string {\n\treturn text\n\t\t.replaceAll(\"&\", \"&\")\n\t\t.replaceAll(\"<\", \"<\")\n\t\t.replaceAll(\">\", \">\")\n\t\t.replaceAll('\"', \""\")\n\t\t.replaceAll(\"'\", \"'\");\n}\n\n/**\n * Strip characters XML 1.0 forbids: C0 controls (except \\t \\n \\r), lone\n * surrogates (U+D800–U+DFFF), and the non-characters U+FFFE/U+FFFF.\n * sanitizeBinaryOutput does not remove the latter two classes, so this filter\n * is the authority for every text field in the notification XML.\n */\nexport function filterXmlCharacters(text: string): string {\n\tlet result = \"\";\n\tfor (const char of text) {\n\t\tconst code = char.codePointAt(0) ?? 0;\n\t\tif (\n\t\t\tcode === 0x09 ||\n\t\t\tcode === 0x0a ||\n\t\t\tcode === 0x0d ||\n\t\t\t(code >= 0x20 && code <= 0xd7ff) ||\n\t\t\t(code >= 0xe000 && code <= 0xfffd) ||\n\t\t\tcode >= 0x10000\n\t\t) {\n\t\t\tresult += char;\n\t\t}\n\t}\n\treturn result;\n}\n\nexport function buildNotificationContent(notification: BgTaskNotification): string {\n\tconst task = notification.task;\n\tconst runtime = formatDuration((task.endedAt ?? task.startedAt) - task.startedAt);\n\tconst exitCode = task.exitCode === undefined || task.exitCode === null ? \"\" : ` exitCode=\"${task.exitCode}\"`;\n\t// filterXmlCharacters keeps \\t \\n \\r and every other XML-legal codepoint,\n\t// so each field below is valid XML 1.0 after escaping.\n\tconst xmlText = (text: string) => escapeXml(filterXmlCharacters(text));\n\tconst lines = [\n\t\t`<background-task id=\"${task.id}\" status=\"${task.status}\"${exitCode} runtime=\"${runtime}\">`,\n\t\t`<command>${xmlText(task.command)}</command>`,\n\t];\n\tif (task.description) {\n\t\tlines.push(`<description>${xmlText(task.description)}</description>`);\n\t}\n\tlines.push(`<output-file>${xmlText(task.outputPath)}</output-file>`);\n\tif (task.error) {\n\t\tlines.push(`<error>${xmlText(task.error)}</error>`);\n\t}\n\tif (notification.tailError) {\n\t\tlines.push(`<output-tail unavailable=\"${xmlText(notification.tailError)}\"/>`);\n\t} else {\n\t\tconst attrs = [\n\t\t\t`bytes=\"${notification.tailBytes}\"`,\n\t\t\t`totalBytes=\"${notification.totalBytes}\"`,\n\t\t\tnotification.tailTruncated ? 'truncated=\"true\"' : \"\",\n\t\t\tnotification.tailStartsMidLine ? 'startsMidLine=\"true\"' : \"\",\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\tconst tail = notification.tailText.length > 0 ? xmlText(notification.tailText) : \"(no output)\";\n\t\tlines.push(`<output-tail ${attrs}>`, tail.trimEnd(), \"</output-tail>\");\n\t}\n\tlines.push(\"</background-task>\");\n\treturn lines.join(\"\\n\");\n}\n\nexport function formatStatusline(counts: { running: number; total: number; stalled?: number }): string | undefined {\n\tif (counts.total === 0) return undefined;\n\t// Stalled tasks are running tasks: report them separately so the counts add up.\n\tconst waiting = counts.stalled ?? 0;\n\tconst running = counts.running - waiting;\n\tconst ended = counts.total - counts.running;\n\tconst parts: string[] = [];\n\tif (running > 0) parts.push(`${running} running`);\n\tif (waiting > 0) parts.push(`${waiting} waiting for input`);\n\tif (ended > 0) parts.push(`${ended} done`);\n\treturn `bg ${parts.join(\" · \")}`;\n}\n\nexport function buildStallContent(notification: BgStallNotification): string {\n\tconst task = notification.task;\n\tconst runtime = formatDuration((task.endedAt ?? Date.now()) - task.startedAt);\n\tconst xmlText = (text: string) => escapeXml(filterXmlCharacters(text));\n\tconst lines = [\n\t\t`<background-task id=\"${task.id}\" status=\"running\" waiting-for-input=\"true\" runtime=\"${runtime}\">`,\n\t\t`<command>${xmlText(task.command)}</command>`,\n\t];\n\tif (task.description) {\n\t\tlines.push(`<description>${xmlText(task.description)}</description>`);\n\t}\n\tlines.push(`<output-file>${xmlText(task.outputPath)}</output-file>`);\n\tif (notification.tailError) {\n\t\tlines.push(`<output-tail unavailable=\"${xmlText(notification.tailError)}\"/>`);\n\t} else {\n\t\tconst attrs = [\n\t\t\t`bytes=\"${notification.tailBytes}\"`,\n\t\t\t`totalBytes=\"${notification.totalBytes}\"`,\n\t\t\tnotification.tailTruncated ? 'truncated=\"true\"' : \"\",\n\t\t\tnotification.tailStartsMidLine ? 'startsMidLine=\"true\"' : \"\",\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\tconst tail = notification.tailText.length > 0 ? xmlText(notification.tailText) : \"(no output)\";\n\t\tlines.push(`<output-tail ${attrs}>`, tail.trimEnd(), \"</output-tail>\");\n\t}\n\tlines.push(\n\t\t\"<advice>The command appears blocked waiting for interactive input. Kill it (bg action kill) and \" +\n\t\t\t\"re-run with piped input (e.g. echo y | command) or a non-interactive flag if one exists (e.g. --yes). \" +\n\t\t\t\"The task keeps running until then.</advice>\",\n\t);\n\tlines.push(\"</background-task>\");\n\treturn lines.join(\"\\n\");\n}\n\nfunction toStallDetails(notification: BgStallNotification): BgNotificationDetails {\n\tconst task = notification.task;\n\treturn {\n\t\ttaskId: task.id,\n\t\tcommand: task.command,\n\t\tdescription: task.description,\n\t\tstatus: \"running\",\n\t\tstalled: true,\n\t\texitCode: undefined,\n\t\truntimeMs: Date.now() - task.startedAt,\n\t\toutputPath: task.outputPath,\n\t\ttotalBytes: notification.totalBytes,\n\t\ttailText: notification.tailText,\n\t\ttailTruncated: notification.tailTruncated,\n\t\ttailError: notification.tailError,\n\t};\n}\n\nfunction describeResolveFailure(input: string, result: ResolveTaskResult & { ok: false }): string {\n\tif (result.reason === \"ambiguous\") {\n\t\tconst lines = result.candidates.map(\n\t\t\t(task) => ` ${task.id} (${task.status}) ${commandLabel(taskLabel(task), 60)}`,\n\t\t);\n\t\treturn `Task id \"${input}\" is ambiguous. Candidates:\\n${lines.join(\"\\n\")}`;\n\t}\n\treturn `No background task matches \"${input}\". Check the id returned by bg (action create), or run action list.`;\n}\n\n/** One row of a bounded task listing: the model-facing list and /bg summaries. */\nfunction describeTaskLine(task: BgTask, now: number): string {\n\tconst duration = formatDuration((task.endedAt ?? now) - task.startedAt);\n\tconst exit = task.exitCode !== undefined && task.exitCode !== null ? ` exit ${task.exitCode}` : \"\";\n\treturn ` ${task.id} ${task.status}${exit} ${duration} ${commandLabel(taskLabel(task), 60)}`;\n}\n\n/** Label for listings: the model-provided description over the first command line. */\nfunction taskLabel(task: BgTask): string {\n\treturn task.description ? `${task.description} — ${firstCommandLine(task.command)}` : firstCommandLine(task.command);\n}\n\nfunction toNotificationDetails(notification: BgTaskNotification): BgNotificationDetails {\n\tconst task = notification.task;\n\treturn {\n\t\ttaskId: task.id,\n\t\tcommand: task.command,\n\t\tdescription: task.description,\n\t\tstatus: task.status,\n\t\texitCode: task.exitCode,\n\t\truntimeMs: (task.endedAt ?? task.startedAt) - task.startedAt,\n\t\toutputPath: task.outputPath,\n\t\ttotalBytes: notification.totalBytes,\n\t\ttailText: notification.tailText,\n\t\ttailTruncated: notification.tailTruncated,\n\t\terror: task.error,\n\t\ttailError: notification.tailError,\n\t};\n}\n\n/**\n * Wrap operations so every executed command carries the prefix, mirroring the\n * built-in bash tool. The prefix never reaches task labels or notifications:\n * `BgTask.command` stays the user's original input.\n */\nexport function prependCommandPrefix(operations: BashOperations, prefix: string | undefined): BashOperations {\n\tif (!prefix) return operations;\n\treturn {\n\t\texec: (command, cwd, options) => operations.exec(`${prefix}\\n${command}`, cwd, options),\n\t};\n}\n\nexport interface BackgroundExtensionOverrides {\n\toperations?: BashOperations;\n\toutputDir?: string;\n\tmaxOutputBytes?: number;\n\t/** Stall watchdog tuning; defaults follow Claude Code's CC-1175 (5s/45s/1KB). */\n\tstall?: { pollIntervalMs?: number; thresholdMs?: number; tailBytes?: number };\n}\n\n/** Shell configuration for one bg session: the session's settings win, disk settings are the fallback. */\nexport function resolveSessionShell(\n\tctx: ExtensionContext,\n\treadDiskSettings?: () => { shellPath?: string; commandPrefix?: string },\n): { shellPath?: string; commandPrefix?: string } {\n\treturn ctx.getShellSettings?.() ?? readDiskSettings?.() ?? {};\n}\n\n/** Local shell operations honoring the session's shell settings (shellPath, commandPrefix). */\nfunction createSessionBashOperations(ctx: ExtensionContext): BashOperations {\n\tconst shell = resolveSessionShell(ctx, () => {\n\t\t// Hosts without getShellSettings (older SDK hosts): fall back to reading\n\t\t// settings from disk, matching what the session was configured with.\n\t\tconst settings = SettingsManager.create(ctx.cwd, getAgentDir(), {\n\t\t\tprojectTrusted: ctx.isProjectTrusted(),\n\t\t});\n\t\treturn { shellPath: settings.getShellPath(), commandPrefix: settings.getShellCommandPrefix() };\n\t});\n\treturn prependCommandPrefix(createLocalBashOperations({ shellPath: shell.shellPath }), shell.commandPrefix);\n}\n\n/** Validate per-action required fields; every message names the next step. */\nfunction validateAction(input: BgInput): void {\n\tswitch (input.action) {\n\t\tcase \"create\":\n\t\t\tif (!input.command || input.command.trim().length === 0) {\n\t\t\t\tthrow new Error(\"action 'create' requires 'command' — pass the bash command to run in the background.\");\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"read\":\n\t\tcase \"wait\":\n\t\tcase \"kill\":\n\t\t\tif (!input.taskId || input.taskId.trim().length === 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`action '${input.action}' requires 'taskId' — use the id returned by action create, or action list to find it.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"list\":\n\t\t\tbreak;\n\t}\n}\n\n/** Factory with injectable seams for tests; the default export uses production wiring. */\nexport function createBackgroundExtension(overrides?: BackgroundExtensionOverrides): (pi: ExtensionAPI) => void {\n\treturn (pi: ExtensionAPI) => {\n\t\tlet registry: BackgroundTaskRegistry | undefined;\n\t\tlet sessionCtx: ExtensionContext | undefined;\n\n\t\tconst requireRegistry = (): BackgroundTaskRegistry => {\n\t\t\tif (!registry) throw new Error(\"Background tasks are not available yet (no active session).\");\n\t\t\treturn registry;\n\t\t};\n\n\t\tconst resolveTaskOrThrow = (taskId: string): BgTask => {\n\t\t\tconst resolved = requireRegistry().resolveTask(taskId);\n\t\t\tif (!resolved.ok) throw new Error(describeResolveFailure(taskId, resolved));\n\t\t\treturn resolved.task;\n\t\t};\n\n\t\t/** Read-only live peek for the pending wait renderer; never throws. */\n\t\tconst waitLiveProbe: WaitLiveProbe = (taskId) => {\n\t\t\tif (!registry) return undefined;\n\t\t\tconst resolved = registry.resolveTask(taskId);\n\t\t\treturn resolved.ok ? { status: resolved.task.status, outputBytes: resolved.task.outputBytes } : undefined;\n\t\t};\n\n\t\tconst updateStatus = () => {\n\t\t\tif (!registry || registry.isShuttingDown) return;\n\t\t\tsessionCtx?.ui.setStatus(\"background\", formatStatusline(registry.counts()));\n\t\t};\n\n\t\tpi.on(\"session_start\", (_event, ctx) => {\n\t\t\tsessionCtx = ctx;\n\t\t\t// Defensive: a leftover registry (session_shutdown not seen) must not leak processes.\n\t\t\tif (registry) void registry.shutdown();\n\t\t\tregistry = new BackgroundTaskRegistry({\n\t\t\t\toperations: overrides?.operations ?? createSessionBashOperations(ctx),\n\t\t\t\toutputDir: overrides?.outputDir,\n\t\t\t\tmaxOutputBytes: overrides?.maxOutputBytes,\n\t\t\t\tstall: overrides?.stall,\n\t\t\t\tonNotify: (notification) => {\n\t\t\t\t\tpi.sendMessage(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcustomType: BG_NOTIFICATION_TYPE,\n\t\t\t\t\t\t\tcontent: buildNotificationContent(notification),\n\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tdetails: toNotificationDetails(notification),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ deliverAs: \"followUp\", triggerTurn: true },\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tonStall: (notification) => {\n\t\t\t\t\t// Informational one-shot signal: not a terminal state, so it bypasses\n\t\t\t\t\t// the claim protocol (a waiting model needs to know it is blocked on\n\t\t\t\t\t// input, not merely slow).\n\t\t\t\t\tpi.sendMessage(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcustomType: BG_NOTIFICATION_TYPE,\n\t\t\t\t\t\t\tcontent: buildStallContent(notification),\n\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tdetails: toStallDetails(notification),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ deliverAs: \"followUp\", triggerTurn: true },\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tonChange: updateStatus,\n\t\t\t});\n\t\t\tupdateStatus();\n\t\t});\n\n\t\tpi.on(\"session_shutdown\", async (_event, ctx) => {\n\t\t\tctx.ui.setStatus(\"background\", undefined);\n\t\t\tsessionCtx = undefined;\n\t\t\tconst active = registry;\n\t\t\tregistry = undefined;\n\t\t\tawait active?.shutdown();\n\t\t});\n\n\t\tconst runCreate = async (\n\t\t\tparams: BgCreateInput,\n\t\t\tctx: ExtensionContext,\n\t\t): Promise<AgentToolResult<BgCreateDetails>> => {\n\t\t\tif (params.timeout !== undefined && (!Number.isFinite(params.timeout) || params.timeout <= 0)) {\n\t\t\t\tthrow new Error(\"Invalid timeout: must be a positive number of seconds.\");\n\t\t\t}\n\t\t\tif (params.timeout !== undefined && params.timeout > MAX_TIMEOUT_SECONDS) {\n\t\t\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t\t\t}\n\t\t\t// Same PI_* session variables as the built-in bash tool, snapshotted at start.\n\t\t\tconst spawnContext = resolveSpawnContext(params.command, ctx.cwd, undefined, true, ctx);\n\t\t\t// Deliberately ignore the turn signal: aborting the current turn must\n\t\t\t// not kill the background task (that is what action kill is for).\n\t\t\tconst task = requireRegistry().startTask({\n\t\t\t\tcommand: params.command,\n\t\t\t\tcwd: ctx.cwd,\n\t\t\t\tdescription: params.description,\n\t\t\t\ttimeoutSeconds: params.timeout,\n\t\t\t\tenv: spawnContext.env,\n\t\t\t});\n\t\t\tconst label = task.description ? ` (${task.description})` : \"\";\n\t\t\tconst text = [\n\t\t\t\t`Started background task ${task.id}${label}.`,\n\t\t\t\t`Output file: ${task.outputPath}`,\n\t\t\t\t\"\",\n\t\t\t\t\"A <background-task> notification with the result and output tail arrives automatically when the task \" +\n\t\t\t\t\t\"ends — do NOT poll (no sleep loops, no repeated reads). Use action read for an early peek, \" +\n\t\t\t\t\t\"action wait when the next step depends on the result, action kill to stop it.\",\n\t\t\t].join(\"\\n\");\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\tdetails: {\n\t\t\t\t\taction: \"create\",\n\t\t\t\t\ttaskId: task.id,\n\t\t\t\t\toutputPath: task.outputPath,\n\t\t\t\t\tcommand: params.command,\n\t\t\t\t\tdescription: params.description,\n\t\t\t\t},\n\t\t\t};\n\t\t};\n\n\t\tconst runRead = async (params: BgReadInput): Promise<AgentToolResult<BgReadDetails>> => {\n\t\t\tconst task = resolveTaskOrThrow(params.taskId);\n\t\t\tconst mode = params.mode ?? \"tail\";\n\t\t\tconst maxBytes = Math.min(\n\t\t\t\tDEFAULT_MAX_BYTES,\n\t\t\t\tMath.max(BG_LOGS_MIN_BYTES, Math.floor(params.bytes ?? BG_LOGS_DEFAULT_BYTES)),\n\t\t\t);\n\t\t\tlet slice: Awaited<ReturnType<typeof readOutputSlice>>;\n\t\t\ttry {\n\t\t\t\tslice = await readOutputSlice(task.outputPath, { mode, maxBytes });\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Could not read output for ${task.id} (${task.status}): ${message}\\nOutput file: ${task.outputPath}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst text = sanitizeBinaryOutput(slice.text);\n\t\t\tconst running = task.status === \"running\" ? [\"still running\"] : [];\n\t\t\tconst noticeParts = slice.truncated\n\t\t\t\t? [\n\t\t\t\t\t\t`${mode} ${formatSize(slice.sliceBytes)} of ${formatSize(slice.totalBytes)}`,\n\t\t\t\t\t\t`task ${task.id} ${task.status}`,\n\t\t\t\t\t\t...running,\n\t\t\t\t\t\t...(slice.startsMidLine ? [\"first line may be partial\"] : []),\n\t\t\t\t\t\t`full output: ${task.outputPath}`,\n\t\t\t\t\t]\n\t\t\t\t: [\n\t\t\t\t\t\t`task ${task.id} ${task.status}`,\n\t\t\t\t\t\t...running,\n\t\t\t\t\t\t`${formatSize(slice.totalBytes)} total`,\n\t\t\t\t\t\t`output: ${task.outputPath}`,\n\t\t\t\t\t];\n\t\t\tconst body = text.length > 0 ? text : \"(no output yet)\";\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `[${noticeParts.join(\" · \")}]\\n${body}` }],\n\t\t\t\tdetails: {\n\t\t\t\t\taction: \"read\",\n\t\t\t\t\ttaskId: task.id,\n\t\t\t\t\tmode,\n\t\t\t\t\tsliceBytes: slice.sliceBytes,\n\t\t\t\t\ttotalBytes: slice.totalBytes,\n\t\t\t\t\toutputPath: task.outputPath,\n\t\t\t\t},\n\t\t\t};\n\t\t};\n\n\t\tconst runWait = async (params: BgWaitInput): Promise<AgentToolResult<BgWaitDetails>> => {\n\t\t\tconst task = resolveTaskOrThrow(params.taskId);\n\t\t\tconst waitMs = Math.min(\n\t\t\t\tBG_WAIT_MAX_MS,\n\t\t\t\tMath.max(BG_WAIT_MIN_MS, Math.floor(params.waitMs ?? BG_WAIT_DEFAULT_MS)),\n\t\t\t);\n\t\t\tconst startedWait = Date.now();\n\t\t\tconst result = await requireRegistry().waitForResult(task.id, waitMs);\n\t\t\tconst waitedMs = Date.now() - startedWait;\n\t\t\tconst finalTask = result.task;\n\t\t\tconst exitSuffix =\n\t\t\t\tfinalTask.exitCode !== undefined && finalTask.exitCode !== null ? ` · exit ${finalTask.exitCode}` : \"\";\n\t\t\tconst ran = formatDuration((finalTask.endedAt ?? Date.now()) - finalTask.startedAt);\n\n\t\t\tif (result.outcome === \"timeout\") {\n\t\t\t\t// Still running: keep progress visible with a bounded tail peek.\n\t\t\t\tlet peekText = \"\";\n\t\t\t\tlet peekNote = \"\";\n\t\t\t\tlet totalBytes = finalTask.outputBytes;\n\t\t\t\ttry {\n\t\t\t\t\tconst peek = await readOutputSlice(finalTask.outputPath, { mode: \"tail\", maxBytes: BG_WAIT_PEEK_BYTES });\n\t\t\t\t\tpeekText = sanitizeBinaryOutput(peek.text);\n\t\t\t\t\ttotalBytes = peek.totalBytes;\n\t\t\t\t\tpeekNote = peek.truncated ? ` (last ${formatSize(peek.sliceBytes)})` : \"\";\n\t\t\t\t} catch {\n\t\t\t\t\tpeekNote = \" (output unavailable)\";\n\t\t\t\t}\n\t\t\t\tconst lines = [\n\t\t\t\t\t`[${finalTask.id} still running · waited ${formatDuration(waitedMs)} · ${formatSize(totalBytes)} total]`,\n\t\t\t\t];\n\t\t\t\tconst trimmed = peekText.trimEnd();\n\t\t\t\tif (trimmed.length > 0) lines.push(`Last output${peekNote}:\\n${trimmed}`);\n\t\t\t\tlines.push(\n\t\t\t\t\t\"The task keeps running. Wait again (action wait), peek with action read, or stop it with action kill; \" +\n\t\t\t\t\t\t\"the <background-task> notification still arrives when it ends. Do not sleep-poll.\",\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: lines.join(\"\\n\\n\") }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\taction: \"wait\",\n\t\t\t\t\t\ttaskId: finalTask.id,\n\t\t\t\t\t\ttimedOut: true,\n\t\t\t\t\t\tstatus: finalTask.status,\n\t\t\t\t\t\texitCode: finalTask.exitCode,\n\t\t\t\t\t\twaitedMs,\n\t\t\t\t\t\tdeltaBytes: 0,\n\t\t\t\t\t\ttotalBytes,\n\t\t\t\t\t\tdeltaTruncated: false,\n\t\t\t\t\t\toutputPath: finalTask.outputPath,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Terminal: deliver the bounded delta since the requested offset.\n\t\t\t// The followUp notification was suppressed by the claim protocol —\n\t\t\t// this result is the single delivery of the completion.\n\t\t\tconst since = params.sinceBytes !== undefined ? Math.max(0, Math.floor(params.sinceBytes)) : undefined;\n\t\t\tlet delta: Awaited<ReturnType<typeof readOutputSince>>;\n\t\t\tlet offsetNote: string | undefined;\n\t\t\ttry {\n\t\t\t\tdelta = await readOutputSince(finalTask.outputPath, since ?? 0, BG_WAIT_DELTA_BYTES);\n\t\t\t\tif (since !== undefined && since > delta.totalBytes) {\n\t\t\t\t\t// A stale offset past EOF (the output was truncated at the cap, or\n\t\t\t\t\t// the model is reusing an id from an earlier read): fall back to\n\t\t\t\t\t// the tail and say so. Never an error — the offset is not a bug.\n\t\t\t\t\tdelta = await readOutputSince(finalTask.outputPath, 0, BG_WAIT_DELTA_BYTES);\n\t\t\t\t\toffsetNote = finalTask.outputTruncated\n\t\t\t\t\t\t? \"the given offset is past EOF — output was truncated at the limit; showing the tail\"\n\t\t\t\t\t\t: \"the given offset is past EOF; showing the tail\";\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\t// Deliver the terminal status even when the output file cannot be read.\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `[${finalTask.id} ${finalTask.status}${exitSuffix} · ran ${ran} · waited ${formatDuration(waitedMs)}]\\nerror reading output: ${message}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\taction: \"wait\",\n\t\t\t\t\t\ttaskId: finalTask.id,\n\t\t\t\t\t\ttimedOut: false,\n\t\t\t\t\t\tstatus: finalTask.status,\n\t\t\t\t\t\texitCode: finalTask.exitCode,\n\t\t\t\t\t\twaitedMs,\n\t\t\t\t\t\tdeltaBytes: 0,\n\t\t\t\t\t\ttotalBytes: finalTask.outputBytes,\n\t\t\t\t\t\tdeltaTruncated: false,\n\t\t\t\t\t\toutputPath: finalTask.outputPath,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst lines = [\n\t\t\t\t`[${finalTask.id} ${finalTask.status}${exitSuffix} · ran ${ran} · waited ${formatDuration(waitedMs)} · +${formatSize(delta.sliceBytes)} new output · total ${formatSize(delta.totalBytes)}]`,\n\t\t\t];\n\t\t\tif (offsetNote) lines.push(`[${offsetNote}]`);\n\t\t\tif (finalTask.error) lines.push(`error: ${finalTask.error}`);\n\t\t\tif (delta.truncated) {\n\t\t\t\tlines.push(\n\t\t\t\t\t`[showing ${formatSize(delta.sliceBytes)} of ${formatSize(delta.totalBytes)}; full output: ${finalTask.outputPath}]`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst body = sanitizeBinaryOutput(delta.text).trimEnd();\n\t\t\tlines.push(body.length > 0 ? body : \"(no new output)\");\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: lines.join(\"\\n\") }],\n\t\t\t\tdetails: {\n\t\t\t\t\taction: \"wait\",\n\t\t\t\t\ttaskId: finalTask.id,\n\t\t\t\t\ttimedOut: false,\n\t\t\t\t\tstatus: finalTask.status,\n\t\t\t\t\texitCode: finalTask.exitCode,\n\t\t\t\t\twaitedMs,\n\t\t\t\t\tdeltaBytes: delta.sliceBytes,\n\t\t\t\t\ttotalBytes: delta.totalBytes,\n\t\t\t\t\tdeltaTruncated: delta.truncated,\n\t\t\t\t\toutputPath: finalTask.outputPath,\n\t\t\t\t},\n\t\t\t};\n\t\t};\n\n\t\tconst runKill = (params: BgKillInput): AgentToolResult<BgKillDetails> => {\n\t\t\tconst task = resolveTaskOrThrow(params.taskId);\n\t\t\tconst result = requireRegistry().killTask(task.id);\n\t\t\tif (!result.killed) {\n\t\t\t\tconst exit = task.exitCode !== undefined && task.exitCode !== null ? `, exit ${task.exitCode}` : \"\";\n\t\t\t\tthrow new Error(`Task ${task.id} is not running (status: ${task.status}${exit}).`);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Killed task ${task.id}. If you are waiting on it (action wait) the killed status is delivered there; otherwise a completion notification follows once the process tree is reaped.`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: { action: \"kill\", taskId: task.id, command: task.command },\n\t\t\t};\n\t\t};\n\n\t\tconst runList = (): AgentToolResult<BgListDetails> => {\n\t\t\tconst tasks = requireRegistry().listTasks();\n\t\t\tif (tasks.length === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: \"No background tasks this session. Start one with action create.\" }],\n\t\t\t\t\tdetails: { action: \"list\", running: 0, finished: 0, shown: 0, hidden: 0 },\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst now = Date.now();\n\t\t\tconst running = tasks.filter((task) => task.status === \"running\");\n\t\t\tconst finished = tasks.filter((task) => task.status !== \"running\");\n\t\t\tconst shownFinished = finished.slice(0, BG_LIST_FINISHED_SHOWN);\n\t\t\tconst hidden = finished.length - shownFinished.length;\n\t\t\tconst lines = [`${running.length} running · ${finished.length} finished`];\n\t\t\tfor (const task of [...running, ...shownFinished]) {\n\t\t\t\tlines.push(describeTaskLine(task, now));\n\t\t\t}\n\t\t\tif (hidden > 0) {\n\t\t\t\tlines.push(`(+${hidden} more finished, not shown — action read shows any task's output)`);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: lines.join(\"\\n\") }],\n\t\t\t\tdetails: {\n\t\t\t\t\taction: \"list\",\n\t\t\t\t\trunning: running.length,\n\t\t\t\t\tfinished: finished.length,\n\t\t\t\t\tshown: running.length + shownFinished.length,\n\t\t\t\t\thidden,\n\t\t\t\t},\n\t\t\t};\n\t\t};\n\n\t\tpi.registerTool<typeof bgSchema, BgDetails>({\n\t\t\tname: \"bg\",\n\t\t\tlabel: \"bg\",\n\t\t\tdescription:\n\t\t\t\t\"Run and manage background bash tasks.\\n\\n\" +\n\t\t\t\t\"create: start a command in the background and return immediately with a task id and an \" +\n\t\t\t\t\"output file path. Only use this when you don't need the result immediately and are OK being \" +\n\t\t\t\t\"notified when the command completes later — a <background-task> notification with status, exit \" +\n\t\t\t\t\"code, and output tail arrives automatically when it ends. Do NOT append '&' to the command; bg \" +\n\t\t\t\t\"already runs it detached. An optional description labels the task in the UI; an optional timeout \" +\n\t\t\t\t\"in seconds kills the task on expiry.\\n\\n\" +\n\t\t\t\t\"read: bounded slice of a task's output (default: last 8KB); works while the task runs. The \" +\n\t\t\t\t\"output file is a plain file — the read tool also works on it for line-based paging.\\n\\n\" +\n\t\t\t\t\"wait: block until a task finishes (default 20s, max 60s) and return its status plus output \" +\n\t\t\t\t\"written since a given offset. Use when the next step depends on the result; on timeout the task \" +\n\t\t\t\t\"is still running and you may wait again. Never emulate waiting with sleep.\\n\\n\" +\n\t\t\t\t\"kill: stop a running task (whole process tree).\\n\\n\" +\n\t\t\t\t\"list: currently known tasks with status.\\n\\n\" +\n\t\t\t\t\"Task ids accept a unique prefix ('3f' for 'bg-3f').\",\n\t\t\tpromptSnippet: \"Manage background shell tasks (bg: create/read/wait/kill/list)\",\n\t\t\tpromptGuidelines: [\n\t\t\t\t\"Use bg (action create) for long-running commands (dev servers, watch builds, slow tests) instead of regular bash; results arrive as an automatic <background-task> notification, so continue independent work or end the turn.\",\n\t\t\t\t\"Never wait on background tasks with sleep loops or repeated reads; use bg action wait (bounded) when a step depends on a task's result, or rely on the completion notification.\",\n\t\t\t],\n\t\t\tparameters: bgSchema,\n\t\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx): Promise<AgentToolResult<BgDetails>> {\n\t\t\t\tvalidateAction(params);\n\t\t\t\tswitch (params.action) {\n\t\t\t\t\tcase \"create\":\n\t\t\t\t\t\treturn runCreate(params as BgCreateInput, ctx);\n\t\t\t\t\tcase \"read\":\n\t\t\t\t\t\treturn runRead(params as BgReadInput);\n\t\t\t\t\tcase \"wait\":\n\t\t\t\t\t\treturn runWait(params as BgWaitInput);\n\t\t\t\t\tcase \"kill\":\n\t\t\t\t\t\treturn runKill(params as BgKillInput);\n\t\t\t\t\tcase \"list\":\n\t\t\t\t\t\treturn runList();\n\t\t\t\t}\n\t\t\t},\n\t\t\trenderCall(args, theme, context) {\n\t\t\t\treturn renderBgCall(args, theme, context, waitLiveProbe);\n\t\t\t},\n\t\t\trenderResult(result, options, theme, context) {\n\t\t\t\treturn renderBgResult(result, options, theme, context);\n\t\t\t},\n\t\t});\n\n\t\tpi.registerMessageRenderer<BgNotificationDetails>(BG_NOTIFICATION_TYPE, renderBackgroundNotification);\n\n\t\tpi.registerCommand(\"bg\", {\n\t\t\tdescription: \"View and manage background tasks\",\n\t\t\thandler: async (_args, ctx: ExtensionCommandContext) => {\n\t\t\t\tconst active = registry;\n\t\t\t\tif (!active || active.counts().total === 0) {\n\t\t\t\t\tctx.ui.notify(\"No background tasks.\", \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (ctx.mode !== \"tui\") {\n\t\t\t\t\t// RPC/print: ctx.ui.custom is unavailable — show a bounded summary.\n\t\t\t\t\tconst lines = active\n\t\t\t\t\t\t.listTasks()\n\t\t\t\t\t\t.slice(0, 10)\n\t\t\t\t\t\t.map((task) => describeTaskLine(task, Date.now()));\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t`Background tasks:\\n${lines.join(\"\\n\")}\\nUse the bg tool (action kill) to stop a task.`,\n\t\t\t\t\t\t\"info\",\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait showBackgroundManager(ctx, active);\n\t\t\t},\n\t\t});\n\t};\n}\n\nasync function showBackgroundManager(ctx: ExtensionCommandContext, registry: BackgroundTaskRegistry): Promise<void> {\n\t// No overlay options: the component mounts inline in the editor slot, like /model.\n\tawait ctx.ui.custom(\n\t\t(tui, theme, keybindings, done) =>\n\t\t\tnew BackgroundTasksMenu({\n\t\t\t\ttui,\n\t\t\t\ttheme,\n\t\t\t\tkeybindings,\n\t\t\t\thost: {\n\t\t\t\t\tlistTasks: () => registry.listTasks(),\n\t\t\t\t\tkillTask: (id) => registry.killTask(id),\n\t\t\t\t\treadSlice: (filePath, options) => readOutputSlice(filePath, options),\n\t\t\t\t},\n\t\t\t\tonClose: () => done(undefined),\n\t\t\t}),\n\t);\n}\n\nexport default createBackgroundExtension();\n"]}
|
|
@@ -48,6 +48,10 @@ export declare class BackgroundTasksMenu implements Component, Focusable {
|
|
|
48
48
|
private tailOffsetLines;
|
|
49
49
|
private tailCache;
|
|
50
50
|
private killFeedback;
|
|
51
|
+
/** Task whose settle expires killFeedback; undefined = persists until the next key. */
|
|
52
|
+
private killFeedbackTaskId;
|
|
53
|
+
/** Last tick's render signature; unchanged means nothing visible moved. */
|
|
54
|
+
private lastSignature;
|
|
51
55
|
private pollTimer;
|
|
52
56
|
private readBusy;
|
|
53
57
|
private disposed;
|
|
@@ -60,7 +64,11 @@ export declare class BackgroundTasksMenu implements Component, Focusable {
|
|
|
60
64
|
handleInput(data: string): void;
|
|
61
65
|
private handleListInput;
|
|
62
66
|
private handleDetailInput;
|
|
67
|
+
/** Scroll the detail viewport by `lines` (positive = back through history). */
|
|
68
|
+
private scrollDetail;
|
|
63
69
|
render(width: number): string[];
|
|
70
|
+
/** Task rows the terminal can spare; short windows trade rows for the transcript. */
|
|
71
|
+
private listMaxVisible;
|
|
64
72
|
private renderList;
|
|
65
73
|
private renderTaskRow;
|
|
66
74
|
private countsLabel;
|
|
@@ -75,6 +83,12 @@ export declare class BackgroundTasksMenu implements Component, Focusable {
|
|
|
75
83
|
private maxTailOffset;
|
|
76
84
|
private killSelected;
|
|
77
85
|
private tick;
|
|
86
|
+
/** Drop "stopping" feedback once its task has settled. */
|
|
87
|
+
private expireKillFeedback;
|
|
88
|
+
/** Everything the rendered output depends on; equal signatures need no redraw. */
|
|
89
|
+
private renderSignature;
|
|
90
|
+
/** True when the detail viewport must re-read the output file this tick. */
|
|
91
|
+
private detailOutputChanged;
|
|
78
92
|
private refreshViewport;
|
|
79
93
|
}
|
|
80
94
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/extensions/background/manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAA2C,MAAM,wBAAwB,CAAC;AACjH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGpE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAEpE,OAAO,EAAE,KAAK,MAAM,EAAoC,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/extensions/background/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,9 @@ const POLL_INTERVAL_MS = 1000;
|
|
|
14
14
|
const VIEW_TAIL_BYTES = 128 * 1024;
|
|
15
15
|
const MAX_VIEW_LINES = 2000;
|
|
16
16
|
const LIST_MAX_VISIBLE = 10;
|
|
17
|
+
const LIST_MIN_VISIBLE = 3;
|
|
18
|
+
/** Rows outside the task list itself (borders, title, counter, footer, padding). */
|
|
19
|
+
const LIST_RESERVED_ROWS = 14;
|
|
17
20
|
/** Truncate to an exact visible width, padding short lines with spaces. */
|
|
18
21
|
function padLine(line, width) {
|
|
19
22
|
return truncateToWidth(line, width, "…", true);
|
|
@@ -25,6 +28,8 @@ export class BackgroundTasksMenu {
|
|
|
25
28
|
this.listScrollTop = 0;
|
|
26
29
|
this.follow = true;
|
|
27
30
|
this.tailOffsetLines = 0;
|
|
31
|
+
/** Last tick's render signature; unchanged means nothing visible moved. */
|
|
32
|
+
this.lastSignature = "";
|
|
28
33
|
this.readBusy = false;
|
|
29
34
|
this.disposed = false;
|
|
30
35
|
this._focused = false;
|
|
@@ -56,7 +61,11 @@ export class BackgroundTasksMenu {
|
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
63
|
handleInput(data) {
|
|
59
|
-
this.killFeedback
|
|
64
|
+
if (this.killFeedback !== undefined) {
|
|
65
|
+
this.killFeedback = undefined;
|
|
66
|
+
this.killFeedbackTaskId = undefined;
|
|
67
|
+
this.tui.requestRender();
|
|
68
|
+
}
|
|
60
69
|
if (this.keybindings.matches(data, "tui.select.cancel")) {
|
|
61
70
|
if (this.view === "detail") {
|
|
62
71
|
this.view = "list";
|
|
@@ -95,26 +104,42 @@ export class BackgroundTasksMenu {
|
|
|
95
104
|
}
|
|
96
105
|
handleDetailInput(data) {
|
|
97
106
|
if (this.keybindings.matches(data, "tui.select.pageUp")) {
|
|
107
|
+
this.scrollDetail(Math.max(1, this.detailBodyHeight()));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (this.keybindings.matches(data, "tui.select.pageDown")) {
|
|
111
|
+
if (!this.follow)
|
|
112
|
+
this.scrollDetail(-Math.max(1, this.detailBodyHeight()));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (this.keybindings.matches(data, "tui.select.up")) {
|
|
116
|
+
this.scrollDetail(1);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (this.keybindings.matches(data, "tui.select.down")) {
|
|
120
|
+
if (!this.follow)
|
|
121
|
+
this.scrollDetail(-1);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Scroll the detail viewport by `lines` (positive = back through history). */
|
|
125
|
+
scrollDetail(lines) {
|
|
126
|
+
if (lines > 0) {
|
|
98
127
|
const max = this.maxTailOffset();
|
|
99
128
|
if (max === 0)
|
|
100
129
|
return; // Nothing above the viewport to scroll back to.
|
|
101
|
-
const page = Math.max(1, this.detailBodyHeight());
|
|
102
130
|
this.follow = false;
|
|
103
|
-
this.tailOffsetLines = Math.min(max, this.tailOffsetLines +
|
|
104
|
-
this.tui.requestRender();
|
|
105
|
-
return;
|
|
131
|
+
this.tailOffsetLines = Math.min(max, this.tailOffsetLines + lines);
|
|
106
132
|
}
|
|
107
|
-
|
|
133
|
+
else {
|
|
108
134
|
if (this.follow)
|
|
109
135
|
return;
|
|
110
|
-
|
|
111
|
-
this.tailOffsetLines = Math.max(0, this.tailOffsetLines - page);
|
|
136
|
+
this.tailOffsetLines = Math.max(0, this.tailOffsetLines + lines);
|
|
112
137
|
if (this.tailOffsetLines === 0) {
|
|
113
138
|
this.follow = true;
|
|
114
139
|
void this.refreshViewport();
|
|
115
140
|
}
|
|
116
|
-
this.tui.requestRender();
|
|
117
141
|
}
|
|
142
|
+
this.tui.requestRender();
|
|
118
143
|
}
|
|
119
144
|
render(width) {
|
|
120
145
|
const body = this.view === "list" ? this.renderList(width) : this.renderDetail(width);
|
|
@@ -122,6 +147,10 @@ export class BackgroundTasksMenu {
|
|
|
122
147
|
return [border, ...body, padLine(this.footerLine(), width), border];
|
|
123
148
|
}
|
|
124
149
|
// ── list view ──────────────────────────────────────────────────────────
|
|
150
|
+
/** Task rows the terminal can spare; short windows trade rows for the transcript. */
|
|
151
|
+
listMaxVisible() {
|
|
152
|
+
return Math.min(LIST_MAX_VISIBLE, Math.max(LIST_MIN_VISIBLE, this.tui.terminal.rows - LIST_RESERVED_ROWS));
|
|
153
|
+
}
|
|
125
154
|
renderList(width) {
|
|
126
155
|
const lines = [];
|
|
127
156
|
const counts = this.countsLabel();
|
|
@@ -132,11 +161,20 @@ export class BackgroundTasksMenu {
|
|
|
132
161
|
return lines;
|
|
133
162
|
}
|
|
134
163
|
const selected = this.selectedTask();
|
|
135
|
-
const
|
|
164
|
+
const maxVisible = this.listMaxVisible();
|
|
165
|
+
const visible = this.tasks.slice(this.listScrollTop, this.listScrollTop + maxVisible);
|
|
166
|
+
let seenRunning = false;
|
|
136
167
|
for (const task of visible) {
|
|
168
|
+
// listTasks() orders running first, finished after: one separator at the boundary.
|
|
169
|
+
if (seenRunning && task.status !== "running") {
|
|
170
|
+
lines.push(padLine(this.theme.fg("muted", " ── finished ──"), width));
|
|
171
|
+
seenRunning = false;
|
|
172
|
+
}
|
|
173
|
+
if (task.status === "running")
|
|
174
|
+
seenRunning = true;
|
|
137
175
|
lines.push(this.renderTaskRow(task, task === selected, width));
|
|
138
176
|
}
|
|
139
|
-
if (this.tasks.length >
|
|
177
|
+
if (this.tasks.length > maxVisible) {
|
|
140
178
|
const index = this.tasks.findIndex((task) => task.id === this.selectedTaskId);
|
|
141
179
|
lines.push(padLine(this.theme.fg("muted", ` (${index + 1}/${this.tasks.length})`), width));
|
|
142
180
|
}
|
|
@@ -144,15 +182,17 @@ export class BackgroundTasksMenu {
|
|
|
144
182
|
}
|
|
145
183
|
renderTaskRow(task, isSelected, width) {
|
|
146
184
|
const duration = formatDuration((task.endedAt ?? Date.now()) - task.startedAt);
|
|
147
|
-
const
|
|
185
|
+
const label = task.description
|
|
186
|
+
? `${task.description} — ${firstCommandLine(task.command)}`
|
|
187
|
+
: firstCommandLine(task.command);
|
|
148
188
|
if (isSelected) {
|
|
149
189
|
// Pad to full width before styling so the selection background spans the row.
|
|
150
|
-
const plain = padLine(`→ ${statusGlyph(task.status)} ${task.id} ${duration} ${
|
|
190
|
+
const plain = padLine(`→ ${statusGlyph(task.status, task.stalled)} ${task.id} ${duration} ${label}`, width);
|
|
151
191
|
return this.theme.bg("selectedBg", this.theme.fg("text", plain));
|
|
152
192
|
}
|
|
153
|
-
const glyph = this.theme.fg(statusColor(task.status), statusGlyph(task.status));
|
|
193
|
+
const glyph = this.theme.fg(statusColor(task.status, task.stalled), statusGlyph(task.status, task.stalled));
|
|
154
194
|
const id = this.theme.fg("accent", task.id);
|
|
155
|
-
const rest = this.theme.fg("muted", `${duration} ${
|
|
195
|
+
const rest = this.theme.fg("muted", `${duration} ${label}`);
|
|
156
196
|
return padLine(` ${glyph} ${id} ${rest}`, width);
|
|
157
197
|
}
|
|
158
198
|
countsLabel() {
|
|
@@ -194,10 +234,12 @@ export class BackgroundTasksMenu {
|
|
|
194
234
|
return this.theme.fg("muted", "(no task selected)");
|
|
195
235
|
const duration = formatDuration((task.endedAt ?? Date.now()) - task.startedAt);
|
|
196
236
|
const exit = task.exitCode !== undefined && task.exitCode !== null ? ` exit ${task.exitCode}` : "";
|
|
197
|
-
const
|
|
237
|
+
const resumeLabel = keyLabel("tui.select.pageDown", { keybindings: this.keybindings });
|
|
238
|
+
const paused = this.follow ? "" : resumeLabel ? ` — paused (${resumeLabel} to follow)` : " — paused";
|
|
198
239
|
const fileName = task.outputPath.replace(/\\/g, "/").split("/").at(-1) ?? task.outputPath;
|
|
199
|
-
const glyph = this.theme.fg(statusColor(task.status), statusGlyph(task.status));
|
|
200
|
-
const
|
|
240
|
+
const glyph = this.theme.fg(statusColor(task.status, task.stalled), statusGlyph(task.status, task.stalled));
|
|
241
|
+
const statusLabel = task.stalled ? "running, waiting for input" : task.status;
|
|
242
|
+
const header = `${task.id} · ${statusLabel}${exit} · ${duration} · ${formatSize(task.outputBytes)} · ${fileName}${paused}`;
|
|
201
243
|
return `${glyph} ${this.theme.fg("muted", header)}`;
|
|
202
244
|
}
|
|
203
245
|
detailBodyHeight() {
|
|
@@ -217,7 +259,8 @@ export class BackgroundTasksMenu {
|
|
|
217
259
|
`${keyLabel("tui.select.cancel", opts)} close`,
|
|
218
260
|
]
|
|
219
261
|
: [
|
|
220
|
-
`${keyLabel("tui.select.
|
|
262
|
+
`${keyLabel("tui.select.up", opts)}/${keyLabel("tui.select.down", opts)} scroll`,
|
|
263
|
+
`${keyLabel("tui.select.pageUp", opts)}/${keyLabel("tui.select.pageDown", opts)} page`,
|
|
221
264
|
`${keyLabel("app.backgroundTasks.kill", opts)} kill`,
|
|
222
265
|
`${keyLabel("tui.select.cancel", opts)} back`,
|
|
223
266
|
];
|
|
@@ -237,8 +280,9 @@ export class BackgroundTasksMenu {
|
|
|
237
280
|
this.selectedTaskId = task.id;
|
|
238
281
|
if (next < this.listScrollTop)
|
|
239
282
|
this.listScrollTop = next;
|
|
240
|
-
if (next >= this.listScrollTop +
|
|
241
|
-
this.listScrollTop = next -
|
|
283
|
+
if (next >= this.listScrollTop + this.listMaxVisible()) {
|
|
284
|
+
this.listScrollTop = next - this.listMaxVisible() + 1;
|
|
285
|
+
}
|
|
242
286
|
this.resetFollow();
|
|
243
287
|
this.tui.requestRender();
|
|
244
288
|
}
|
|
@@ -266,7 +310,9 @@ export class BackgroundTasksMenu {
|
|
|
266
310
|
return;
|
|
267
311
|
}
|
|
268
312
|
this.host.killTask(task.id);
|
|
269
|
-
|
|
313
|
+
// Terminal state lands on the next poll; the feedback expires with it (tick).
|
|
314
|
+
this.killFeedback = `stopping ${task.id}…`;
|
|
315
|
+
this.killFeedbackTaskId = task.id;
|
|
270
316
|
this.tui.requestRender();
|
|
271
317
|
}
|
|
272
318
|
async tick() {
|
|
@@ -275,10 +321,60 @@ export class BackgroundTasksMenu {
|
|
|
275
321
|
this.tasks = this.host.listTasks();
|
|
276
322
|
if (!this.selectedTask() && this.tasks[0])
|
|
277
323
|
this.selectedTaskId = this.tasks[0].id;
|
|
278
|
-
|
|
324
|
+
this.expireKillFeedback();
|
|
325
|
+
if (this.renderSignature() === this.lastSignature)
|
|
326
|
+
return; // Nothing visible changed.
|
|
327
|
+
if (this.view === "detail" && this.follow && this.detailOutputChanged()) {
|
|
279
328
|
await this.refreshViewport();
|
|
329
|
+
}
|
|
330
|
+
this.lastSignature = this.renderSignature();
|
|
280
331
|
this.tui.requestRender();
|
|
281
332
|
}
|
|
333
|
+
/** Drop "stopping" feedback once its task has settled. */
|
|
334
|
+
expireKillFeedback() {
|
|
335
|
+
if (this.killFeedbackTaskId === undefined)
|
|
336
|
+
return;
|
|
337
|
+
const task = this.tasks.find((candidate) => candidate.id === this.killFeedbackTaskId);
|
|
338
|
+
if (!task || task.status !== "running") {
|
|
339
|
+
this.killFeedback = undefined;
|
|
340
|
+
this.killFeedbackTaskId = undefined;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/** Everything the rendered output depends on; equal signatures need no redraw. */
|
|
344
|
+
renderSignature() {
|
|
345
|
+
const parts = [
|
|
346
|
+
this.view,
|
|
347
|
+
this.selectedTaskId ?? "",
|
|
348
|
+
String(this.listScrollTop),
|
|
349
|
+
String(this.follow),
|
|
350
|
+
String(this.tailOffsetLines),
|
|
351
|
+
this.killFeedback ?? "",
|
|
352
|
+
this.tailCache
|
|
353
|
+
? `${this.tailCache.taskId}:${this.tailCache.lines.length}:${this.tailCache.totalBytes}:${this.tailCache.error ?? ""}:${String(this.tailCache.settledRead ?? false)}`
|
|
354
|
+
: "",
|
|
355
|
+
];
|
|
356
|
+
for (const task of this.tasks) {
|
|
357
|
+
const duration = formatDuration((task.endedAt ?? Date.now()) - task.startedAt);
|
|
358
|
+
parts.push(`${task.id}:${task.status}:${String(task.stalled)}:${task.outputBytes}:${task.exitCode ?? ""}:${duration}`);
|
|
359
|
+
}
|
|
360
|
+
return parts.join("|");
|
|
361
|
+
}
|
|
362
|
+
/** True when the detail viewport must re-read the output file this tick. */
|
|
363
|
+
detailOutputChanged() {
|
|
364
|
+
const task = this.selectedTask();
|
|
365
|
+
if (!task)
|
|
366
|
+
return false;
|
|
367
|
+
const cache = this.tailCache;
|
|
368
|
+
if (!cache || cache.taskId !== task.id)
|
|
369
|
+
return true;
|
|
370
|
+
if (cache.error !== undefined)
|
|
371
|
+
return true; // Keep retrying; failed reads are cheap.
|
|
372
|
+
if (task.status !== "running") {
|
|
373
|
+
// Terminal task: the file is final — read it once, then never again.
|
|
374
|
+
return cache.settledRead !== true;
|
|
375
|
+
}
|
|
376
|
+
return cache.totalBytes !== task.outputBytes;
|
|
377
|
+
}
|
|
282
378
|
async refreshViewport() {
|
|
283
379
|
if (this.readBusy)
|
|
284
380
|
return;
|
|
@@ -290,7 +386,12 @@ export class BackgroundTasksMenu {
|
|
|
290
386
|
const slice = await this.host.readSlice(task.outputPath, { mode: "tail", maxBytes: VIEW_TAIL_BYTES });
|
|
291
387
|
if (this.disposed || this.selectedTaskId !== task.id || !this.follow)
|
|
292
388
|
return;
|
|
293
|
-
this.tailCache = {
|
|
389
|
+
this.tailCache = {
|
|
390
|
+
taskId: task.id,
|
|
391
|
+
lines: toViewLines(slice.text),
|
|
392
|
+
totalBytes: slice.totalBytes,
|
|
393
|
+
settledRead: task.status !== "running",
|
|
394
|
+
};
|
|
294
395
|
}
|
|
295
396
|
catch (error) {
|
|
296
397
|
if (this.disposed || this.selectedTaskId !== task.id)
|