@agimon-ai/po-plan 0.0.0-alpha.32 → 0.0.0-alpha.34

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.
@@ -42,6 +42,7 @@ node_path = __toESM(node_path, 1);
42
42
  let _agimon_ai_po_core_piSettings = require("@agimon-ai/po-core/piSettings");
43
43
  let node_fs_promises = require("node:fs/promises");
44
44
  node_fs_promises = __toESM(node_fs_promises, 1);
45
+ let _agimon_ai_po_core_platform = require("@agimon-ai/po-core/platform");
45
46
  let _agimon_ai_po_core_voiceTools = require("@agimon-ai/po-core/voiceTools");
46
47
  let _agimon_ai_po_minor_mode = require("@agimon-ai/po-minor-mode");
47
48
  let _agimon_ai_po_config = require("@agimon-ai/po-config");
@@ -233,17 +234,55 @@ async function writeNewPlanFile(directory, filename, content) {
233
234
  async function readPlanText(planPath) {
234
235
  return await node_fs_promises.default.readFile(planPath, "utf8");
235
236
  }
236
- async function readPlanBytes(planPath) {
237
- return await node_fs_promises.default.readFile(planPath);
237
+ /** The extra byte detects growth without ever reading or allocating the whole file. */
238
+ async function readBounded(handle, maxBytes) {
239
+ const stats = await handle.stat();
240
+ if (!stats.isFile()) throw new Error("The plan is not a regular file.");
241
+ const buffer = Buffer.alloc(maxBytes + 1);
242
+ if (stats.size > maxBytes) return buffer;
243
+ let offset = 0;
244
+ while (offset < buffer.length) {
245
+ const { bytesRead } = await handle.read(buffer, offset, buffer.length - offset, offset);
246
+ if (bytesRead === 0) break;
247
+ offset += bytesRead;
248
+ }
249
+ return buffer.subarray(0, offset);
238
250
  }
239
- async function overwritePlanFile(planPath, content) {
240
- const stats = await node_fs_promises.default.lstat(planPath);
241
- if (!stats.isFile() || stats.nlink !== 1) return false;
242
- await node_fs_promises.default.writeFile(planPath, content, {
243
- encoding: "utf8",
244
- mode: 384
251
+ async function readPlanBytes(planPath, maxBytes) {
252
+ const handle = await (0, _agimon_ai_po_core_platform.openGuardedFile)(planPath);
253
+ try {
254
+ return await readBounded(handle, maxBytes);
255
+ } finally {
256
+ await handle.close();
257
+ }
258
+ }
259
+ /** Compare and write the same open inode. The queue protects cooperating API writers, not external processes. */
260
+ async function overwritePlanFile(planPath, content, expectedHash, maxBytes) {
261
+ const canonical = await node_fs_promises.default.realpath(planPath);
262
+ return await _agimon_ai_po_core_platform.fileMutationRunner.forKey(canonical)(async () => {
263
+ const handle = await (0, _agimon_ai_po_core_platform.openGuardedFile)(planPath, { write: true });
264
+ try {
265
+ if (await node_fs_promises.default.realpath(planPath) !== canonical) return void 0;
266
+ const raw = await readBounded(handle, maxBytes);
267
+ if (raw.length > maxBytes) return void 0;
268
+ const hash = (0, node_crypto.createHash)("sha256").update(raw.toString("utf8"), "utf8").digest("hex");
269
+ if (hash !== expectedHash) return {
270
+ written: false,
271
+ hash
272
+ };
273
+ const opened = await handle.stat();
274
+ const current = await node_fs_promises.default.lstat(planPath);
275
+ if (!opened.isFile() || opened.nlink !== 1 || !current.isFile() || current.nlink !== 1 || opened.dev !== current.dev || opened.ino !== current.ino || await node_fs_promises.default.realpath(planPath) !== canonical) return void 0;
276
+ await handle.writeFile(content, "utf8");
277
+ await handle.truncate(Buffer.byteLength(content, "utf8"));
278
+ return {
279
+ written: true,
280
+ hash: (0, node_crypto.createHash)("sha256").update(content, "utf8").digest("hex")
281
+ };
282
+ } finally {
283
+ await handle.close();
284
+ }
245
285
  });
246
- return true;
247
286
  }
248
287
  //#endregion
249
288
  //#region src/services/planApi/index.ts
@@ -277,7 +316,7 @@ function hashOf(content) {
277
316
  async function readPlan(planPath) {
278
317
  let raw;
279
318
  try {
280
- raw = await readPlanBytes(planPath);
319
+ raw = await readPlanBytes(planPath, MAX_PLAN_BYTES);
281
320
  } catch {
282
321
  return {
283
322
  content: "",
@@ -322,17 +361,21 @@ function createPlanApi(options = {}) {
322
361
  } catch {
323
362
  return context.json({ error: "The save body is not JSON." }, 400);
324
363
  }
325
- if (typeof request.content !== "string" || typeof request.expectedHash !== "string") return context.json({ error: "A save carries the content to write and the hash it was read at." }, 400);
364
+ if (typeof request !== "object" || request === null || Array.isArray(request) || !("content" in request) || typeof request.content !== "string" || !("expectedHash" in request) || typeof request.expectedHash !== "string") return context.json({ error: "A save carries the content to write and the hash it was read at." }, 400);
326
365
  const pointer = pointerFor();
327
366
  if (pointer === void 0) return context.json({ error: NO_PLAN }, 404);
328
- const current = await readPlan(pointer.path);
329
- if (current.unavailable) return context.json({ error: current.reason ?? NO_PLAN }, 409);
330
- if (current.hash !== request.expectedHash) return context.json({
331
- error: STALE_SAVE,
332
- hash: current.hash
333
- }, 409);
334
- if (!await overwritePlanFile(pointer.path, request.content)) return context.json({ error: NOT_A_FILE }, 409);
335
- return context.json({ hash: hashOf(request.content) });
367
+ if (Buffer.byteLength(request.content, "utf8") > 1048576) return context.json({ error: `The plan is larger than ${MAX_PLAN_BYTES} bytes.` }, 413);
368
+ try {
369
+ const saved = await overwritePlanFile(pointer.path, request.content, request.expectedHash, MAX_PLAN_BYTES);
370
+ if (saved === void 0) return context.json({ error: NOT_A_FILE }, 409);
371
+ if (!saved.written) return context.json({
372
+ error: STALE_SAVE,
373
+ hash: saved.hash
374
+ }, 409);
375
+ return context.json({ hash: saved.hash });
376
+ } catch {
377
+ return context.json({ error: NOT_A_FILE }, 409);
378
+ }
336
379
  });
337
380
  return app;
338
381
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.cjs","names":["Type","isRecord","os","path","piAgentDirectory","fs","createHash","fs","path","createHash","Hono","path","resolvePlanningPlansDirectory","defineMinorMode","serverMinorModes","PO_CONFIG_SERVICE","readPackageResource","PO_VOICE_AUTO_MODE_ID","buildPlanModeBasePrompt","buildFlavorPlanningPrompt","Buffer","defineRoot","defineRoute","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineToolRestriction","PO_VOICE_AUTO_MODE_ID","defineToolRestriction","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineServerPlugin","composeServerProviderOverrides","rootSession","composeRootInjects","composeRootHooks","apiRoute","hookBeforeAgentStart","hookContext","hookSessionStart","resourcePoUsePlan","toolRestrictionPlan","toolRestrictionPlanReadOnly","toolCompletePlan","toolRecordDebugEvidence","toolWritePlan"],"sources":["../../src/schemas/mcpTools.ts","../../src/services/mcpTools/index.ts","../../src/services/planPointer/index.ts","../../src/types/apiRoutes.ts","../../src/types/planApi.ts","../../src/services/planFiles/index.ts","../../src/services/planApi/index.ts","../../src/services/optionalTeamServices/index.ts","../../src/services/planServerSession/index.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/api/plans/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/beforeAgentStart.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/context.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poUsePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/plan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/planReadOnly.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/completePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/recordDebugEvidence.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/writePlan.server.ts","../../generated/server.ts"],"sourcesContent":["import { Type } from 'typebox';\n\nconst markdown = Type.String({ minLength: 1 });\n\nexport const remoteWritePlanParameters = Type.Object({ markdown }, { additionalProperties: false });\nexport const writePlanParameters = Type.Object({ markdown: Type.Optional(markdown) }, { additionalProperties: false });\n","import type { PoHeadlessTool } from '@agimon-ai/po-core/headless';\nimport type { PoMcpPluginContext } from '@agimon-ai/po-core/mcpFacet';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { remoteWritePlanParameters } from '../../schemas/mcpTools';\n\nexport const PLAN_MCP_TOOLS_SERVICE = 'po/plan-mcp-tools';\n\nconst MODE_ID = 'plan';\nconst MODE_LABEL = 'Plan';\n\nexport interface McpToolCatalog {\n get(name: string): PoHeadlessTool | undefined;\n names(): readonly string[];\n}\n\nexport function mountMcpTools(tools: readonly PoHeadlessTool[]) {\n return (context: Context): void => {\n context.plugin((providerContext) => {\n providerContext.provide(PLAN_MCP_TOOLS_SERVICE, {\n get: (name) => tools.find((tool) => tool.name === name),\n names: () => tools.map((tool) => tool.name),\n } satisfies McpToolCatalog);\n });\n };\n}\n\nexport function bindMcpTool(context: PoMcpPluginContext, name: string): PoHeadlessTool {\n const catalog = context.services.get<McpToolCatalog>(PLAN_MCP_TOOLS_SERVICE);\n const tool = catalog?.get(name);\n if (!tool || !catalog) throw new Error(`Plan tool is unavailable: ${name}`);\n const writesPlan = name === 'write_plan';\n return {\n ...tool,\n ...(writesPlan\n ? {\n description:\n 'Save the supplied Markdown plan in the bound session. Requires active Plan mode. Saving does not approve implementation.',\n parameters: remoteWritePlanParameters,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },\n }\n : {}),\n execute(toolCallId, parameters, signal, onUpdate) {\n const activeModes = context.selection.read().state?.['minor-mode'] ?? [];\n if (!activeModes.includes(MODE_ID)) {\n const inactiveTools = [...catalog.names()].sort().join(', ');\n throw new Error(`${MODE_LABEL} minor mode is inactive. Inactive ${MODE_LABEL} tools: ${inactiveTools}.`);\n }\n if (\n writesPlan &&\n (typeof parameters !== 'object' ||\n parameters === null ||\n !('markdown' in parameters) ||\n typeof parameters.markdown !== 'string' ||\n !parameters.markdown.trim())\n ) {\n throw new Error(\n 'Supply the complete visible plan in the markdown argument. Remote calls cannot read the ChatGPT transcript.',\n );\n }\n const executionSignal = AbortSignal.any([context.signal, signal ?? context.signal]);\n return tool.execute(toolCallId, parameters, executionSignal, onUpdate, context.execution);\n },\n };\n}\n","import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { piAgentDirectory } from '@agimon-ai/po-core/piSettings';\n\nimport type { PlanPointerRecord } from '../../types/planApi';\nimport type { PlanPointerPort } from '../../types/planPointer';\n\n/**\n * Record and read where write_plan left this session's plan file.\n *\n * Pi already gives every session an agent directory, so the records live under\n * it rather than in a second place a reader would have to know about. The\n * posture matches the plan file itself, 0700 on the directory and 0600 on the\n * record: a plan is a private working document, not something to leave\n * world-readable in a shared home.\n */\n\nconst POINTER_DIRECTORY = 'po-plan';\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst PRIVATE_FILE_MODE = 0o600;\n\nexport interface NodePlanPointerOptions {\n env?: NodeJS.ProcessEnv;\n homeDirectory?: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport class PlanPointerService implements PlanPointerPort {\n private readonly env: NodeJS.ProcessEnv;\n private readonly homeDirectory: string;\n\n constructor(options: NodePlanPointerOptions = {}) {\n this.env = options.env ?? {};\n this.homeDirectory = options.homeDirectory ?? os.homedir();\n }\n\n /** Where the records live; exposed so a test can look without guessing. */\n directory(): string {\n return path.join(piAgentDirectory(this.env, this.homeDirectory), POINTER_DIRECTORY);\n }\n\n /**\n * The record for one session. The id is hashed rather than used as written:\n * it reaches here from a host that may word it however it likes, and a\n * filename is not the place to find that out.\n */\n pathFor(sessionId: string): string {\n return path.join(this.directory(), `${this.hash(sessionId)}.json`);\n }\n\n read(sessionId: string): PlanPointerRecord | undefined {\n let raw: string;\n try {\n raw = fs.readFileSync(this.pathFor(sessionId), 'utf8');\n } catch {\n return undefined;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!isRecord(parsed)) return undefined;\n const { path: planPath, title, writtenAt, planId } = parsed;\n // A record half-written by an interrupted run reads as no plan at all,\n // which is a state the cockpit already handles.\n if (typeof planPath !== 'string' || !path.isAbsolute(planPath)) return undefined;\n if (typeof title !== 'string' || typeof writtenAt !== 'string') return undefined;\n return { path: planPath, title, writtenAt, ...(typeof planId === 'string' ? { planId } : {}) };\n }\n\n write(sessionId: string, record: PlanPointerRecord): void {\n fs.mkdirSync(this.directory(), { recursive: true, mode: PRIVATE_DIRECTORY_MODE });\n fs.writeFileSync(this.pathFor(sessionId), JSON.stringify(record), { mode: PRIVATE_FILE_MODE });\n }\n\n clear(sessionId: string): void {\n fs.rmSync(this.pathFor(sessionId), { force: true });\n }\n\n private hash(value: string): string {\n return createHash('sha256').update(value).digest('hex').slice(0, 16);\n }\n}\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { PlanDetailView, PlanSaveView } from './planApi';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/workspaces/sessions/(backend)/api/plans/`, so the mount is\n * stated once, by the folder that creates it. The paths used to be written\n * here as helpers, again in the contract, and again inside every URL the page\n * built, and the copies were free to disagree.\n *\n * This is the one file the routes, the Hono app and the browser all read, so a\n * path cannot move on one side alone.\n *\n * Neither route takes a query or a path parameter: a session has one current\n * plan, so `current` answers it and `save` takes the manual write back.\n */\nconst routes = {\n current: {\n method: 'GET',\n path: '/current',\n response: undefined as unknown as ApiResponseOf<PlanDetailView>,\n },\n save: {\n method: 'PUT',\n path: '/content',\n response: undefined as unknown as ApiResponseOf<PlanSaveView>,\n },\n} as const satisfies ApiRoutes;\n\nexport default routes;\n","/**\n * The wire vocabulary this package's API shares with whatever calls it.\n *\n * It lives under src/types because that is the one server root a browser\n * bundle may read: the routes answer with these shapes and the cockpit plugin\n * reads them, so neither half can drift from the other. The paths themselves\n * are not here; they are declared once in `./apiRoutes`, which the Hono app\n * and the generated client both read.\n *\n * Two routes, and neither takes a path. A session has one current plan, so\n * `current` answers it and `content` takes the manual save back; the file they\n * act on is the one write_plan recorded, never one the page named. That is\n * also why there is nothing to escape here: a reader cannot address a second\n * file through these URLs.\n */\n\n/** Where a host mounts this package's API; the segment after /api/plugins/. */\nexport const API_BASE_PATH = 'plans';\n\n/**\n * Footer status key the session publishes once a plan exists, which is what\n * makes the cockpit's activity group appear at all. It outlives plan mode: the\n * plan is most worth reading while the agent implements it.\n */\nexport const PLAN_STATUS_KEY = 'po-plan-document';\n\n/** The selector contract shared by complete_plan and its cockpit composer prompt. */\nexport const PLAN_REVIEW_TITLE = 'Plan complete. What would you like to do?';\nexport const EXIT_PLAN_MODE_CHOICE = 'Exit plan mode and start implementation';\nexport const CONTINUE_PLANNING_CHOICE = 'Continue planning';\nexport const EXIT_PLAN_DECISION = 'exit';\nexport const CONTINUE_PLAN_DECISION = 'continue';\n\n/**\n * The label the reader sees paired with the decision the tool acts on. A headless\n * client answers with `value`, so a server plugin never has to recognise the wording; Pi's\n * own `ui.select` carries labels only, so its half maps the label back itself.\n */\nexport const PLAN_REVIEW_CHOICES = [\n { label: EXIT_PLAN_MODE_CHOICE, value: EXIT_PLAN_DECISION },\n { label: CONTINUE_PLANNING_CHOICE, value: CONTINUE_PLAN_DECISION },\n] as const;\n\n/** The same options as bare labels, which is all Pi's select and the composer prompt need. */\nexport const PLAN_REVIEW_OPTIONS = PLAN_REVIEW_CHOICES.map((choice) => choice.label);\n\n/** Between the plan's title and the stamp that marks a rewrite. */\nconst STATUS_SEPARATOR = ' · ';\n\n/** Strips the colour a session may have themed a status with. */\nconst ANSI = /\u001b\\[[0-9;]*m/gu;\n\n/** The status line the session publishes; the stamp changes on every write. */\nexport function formatPlanStatus(title: string, stamp: string): string {\n return `${title}${STATUS_SEPARATOR}${stamp}`;\n}\n\n/** What a reader gets out of the status line. */\nexport interface PlanStatusView {\n title: string;\n /** When the plan was last written, as the session worded it; empty when it said nothing. */\n stamp: string;\n}\n\n/**\n * Reading the status line back. Statuses reach a plugin raw, so the colour a\n * session may have added comes off here. A title can itself contain the\n * separator, so the stamp is taken from the last one rather than the first.\n */\nexport function parsePlanStatus(raw: string | undefined): PlanStatusView | undefined {\n if (raw === undefined) return undefined;\n const text = raw.replace(ANSI, '').trim();\n if (text === '') return undefined;\n const cut = text.lastIndexOf(STATUS_SEPARATOR);\n if (cut === -1) return { title: text, stamp: '' };\n return { title: text.slice(0, cut).trim(), stamp: text.slice(cut + STATUS_SEPARATOR.length).trim() };\n}\n\n/**\n * What write_plan recorded about this session's plan.\n *\n * The absolute path is the point of it: the extension resolves the plans\n * directory against the harness root, which no other process knows, so it\n * writes down where the plan landed rather than leaving the API to derive a\n * location it would sometimes get wrong.\n */\nexport interface PlanPointerRecord {\n path: string;\n title: string;\n writtenAt: string;\n planId?: string;\n}\n\n/** The plan as it stands on disk right now, which is what the source view edits. */\nexport interface PlanDetailView {\n path: string;\n title: string;\n writtenAt: string;\n planId?: string;\n content: string;\n /** sha256 of the content; the token a save hands back to prove it is not stale. */\n hash: string;\n /** True when the plan is missing or past the size cap, so `content` is empty. */\n unavailable: boolean;\n reason?: string;\n}\n\n/** What the save route takes. */\nexport interface PlanSaveRequest {\n /** The hash the reader loaded; a mismatch means the plan moved underneath them. */\n expectedHash: string;\n content: string;\n}\n\n/** What the save route answers with. */\nexport interface PlanSaveView {\n hash: string;\n}\n\n/** What a route reports when it refuses; the page shows `error` verbatim. */\nexport interface PlanErrorView {\n error: string;\n /** On a stale save, the hash the plan actually has now. */\n hash?: string;\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport async function writeNewPlanFile(directory: string, filename: string, content: string): Promise<string> {\n await fs.mkdir(directory, { recursive: true, mode: 0o700 });\n const planPath = path.join(directory, filename);\n await fs.writeFile(planPath, content, { encoding: 'utf8', flag: 'wx', mode: 0o600 });\n return planPath;\n}\n\nexport async function readPlanText(planPath: string): Promise<string> {\n return await fs.readFile(planPath, 'utf8');\n}\n\nexport async function readPlanBytes(planPath: string): Promise<Buffer> {\n return await fs.readFile(planPath);\n}\n\nexport async function overwritePlanFile(planPath: string, content: string): Promise<boolean> {\n const stats = await fs.lstat(planPath);\n if (!stats.isFile() || stats.nlink !== 1) return false;\n await fs.writeFile(planPath, content, { encoding: 'utf8', mode: 0o600 });\n return true;\n}\n","import { createHash } from 'node:crypto';\n\nimport type { PoApi, PoApiContext, PoApiHandler } from '@agimon-ai/po-core/packageApi';\nimport { Hono } from 'hono';\n\nimport { PlanPointerService } from '../../services/planPointer';\nimport routes from '../../types/apiRoutes';\nimport { API_BASE_PATH, type PlanDetailView, type PlanSaveRequest, type PlanSaveView } from '../../types/planApi';\nimport type { PlanPointerPort } from '../../types/planPointer';\nimport { overwritePlanFile, readPlanBytes } from '../planFiles';\n\n/**\n * This package's HTTP surface: the session's current plan, and the manual save.\n *\n * Each path comes from the route table the browser reads, so a route the page\n * calls and the route this serves cannot be spelled apart. Both are relative\n * to the mount its host gives it, so nothing here repeats where it was mounted. The host is one session's own server, which is what\n * makes the session id available without the page supplying it.\n *\n * Neither route takes a path. A session has exactly one current plan, and the\n * file both routes act on is the one the pointer names, so a page can address\n * the plan and nothing else; there is no traversal question to answer because\n * there is no path to traverse.\n *\n * The save refuses unless the reader proves they were looking at the content\n * that is still on disk. The agent may rewrite the plan while a tab is open,\n * and silently discarding whichever side finished second is the one outcome\n * worth ruling out.\n */\n\n/** Past this, the plan is reported rather than carried. */\nexport const MAX_PLAN_BYTES = 1024 * 1024;\n\nconst NO_PLAN = 'This session has not written a plan yet.';\nconst STALE_SAVE = 'The plan changed since it was opened.';\nconst NOT_A_FILE = 'The plan file is no longer a regular file, so it was not written.';\n\nexport interface PlanApiOptions {\n /** The session these routes answer for; absent when the host is the hub. */\n sessionId?: string;\n pointers?: PlanPointerPort;\n}\n\nfunction hashOf(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/** Reads the plan as the source view will show it, or says why it cannot. */\nasync function readPlan(\n planPath: string,\n): Promise<Pick<PlanDetailView, 'content' | 'hash' | 'unavailable' | 'reason'>> {\n let raw: Buffer;\n try {\n raw = await readPlanBytes(planPath);\n } catch {\n return { content: '', hash: '', unavailable: true, reason: 'the plan file no longer exists' };\n }\n if (raw.byteLength > MAX_PLAN_BYTES) {\n return { content: '', hash: '', unavailable: true, reason: `the plan is larger than ${MAX_PLAN_BYTES} bytes` };\n }\n const content = raw.toString('utf8');\n return { content, hash: hashOf(content), unavailable: false };\n}\n\nexport function createPlanApi(options: PlanApiOptions = {}): Hono {\n const app = new Hono();\n const pointers = options.pointers ?? new PlanPointerService();\n const pointerFor = (): ReturnType<PlanPointerPort['read']> =>\n options.sessionId === undefined ? undefined : pointers.read(options.sessionId);\n\n app.get(routes.current.path, async (context) => {\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n const view: PlanDetailView = {\n path: pointer.path,\n title: pointer.title,\n writtenAt: pointer.writtenAt,\n ...(pointer.planId === undefined ? {} : { planId: pointer.planId }),\n ...(await readPlan(pointer.path)),\n };\n return context.json(view);\n });\n\n app.put(routes.save.path, async (context) => {\n let request: PlanSaveRequest;\n try {\n request = (await context.req.json()) as PlanSaveRequest;\n } catch {\n return context.json({ error: 'The save body is not JSON.' }, 400);\n }\n if (typeof request.content !== 'string' || typeof request.expectedHash !== 'string') {\n return context.json({ error: 'A save carries the content to write and the hash it was read at.' }, 400);\n }\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n\n const current = await readPlan(pointer.path);\n if (current.unavailable) return context.json({ error: current.reason ?? NO_PLAN }, 409);\n if (current.hash !== request.expectedHash) {\n return context.json({ error: STALE_SAVE, hash: current.hash }, 409);\n }\n // Refuse symlinks and multiply linked files, whatever the pointer still says.\n if (!(await overwritePlanFile(pointer.path, request.content))) return context.json({ error: NOT_A_FILE }, 409);\n return context.json({ hash: hashOf(request.content) } satisfies PlanSaveView);\n });\n\n return app;\n}\n\n/** The named export a host imports from this package's built entry. */\nexport const api: PoApi = {\n basePath: API_BASE_PATH,\n start(context: PoApiContext): PoApiHandler {\n const app = createPlanApi({\n ...(context.sessionId === undefined ? {} : { sessionId: context.sessionId }),\n pointers: new PlanPointerService({\n env: context.environment ?? {},\n homeDirectory: context.homeDirectory,\n }),\n });\n return {\n fetch: (request) => app.fetch(request),\n // Nothing outlives a request here; an API that starts a watch or a timer\n // tears it down in this callback.\n close: () => undefined,\n };\n },\n};\n","import type { Context } from '@deepseek-ai/cordis';\n\nimport { FABLE_PLAN_REQUESTER, type FablePlanRequest, type FablePlanResult } from '../fableFlow';\n\nexport const PO_FABLE_PLAN_SERVICE = 'po/fable-plan';\nexport const PO_SUBAGENT_POLICY_SERVICE = 'po/subagent-policy';\n\nexport interface PoFablePlanService {\n start(request: FablePlanRequest, signal: AbortSignal): Promise<FablePlanResult>;\n cancel(request: { requester: typeof FABLE_PLAN_REQUESTER; operationId: string; reason: string }): void;\n}\n\nexport interface SubagentPolicy {\n owner: string;\n allowedTools?: string[];\n requiredTools?: string[];\n allowMcpTools?: boolean;\n allowedExternalProfiles?: string[];\n denyExtensions?: boolean;\n}\n\nexport interface SubagentPolicyHandle {\n update(policy: SubagentPolicy): void;\n dispose(): void;\n}\n\nexport interface PoSubagentPolicyService {\n register(policy: SubagentPolicy): SubagentPolicyHandle;\n}\n\ntype StructuralServiceContext = {\n get(name: string): unknown;\n};\n\nexport function readPoFablePlanService(ctx: Context): PoFablePlanService | undefined {\n return (ctx as unknown as StructuralServiceContext).get(PO_FABLE_PLAN_SERVICE) as PoFablePlanService | undefined;\n}\n\nexport function readPoSubagentPolicyService(ctx: Context): PoSubagentPolicyService | undefined {\n return (ctx as unknown as StructuralServiceContext).get(PO_SUBAGENT_POLICY_SERVICE) as\n | PoSubagentPolicyService\n | undefined;\n}\n","import { Buffer } from 'node:buffer';\nimport path from 'node:path';\n\nimport type { IPoConfigService } from '@agimon-ai/po-config';\nimport { PO_CONFIG_SERVICE } from '@agimon-ai/po-core/config';\nimport { type PoHeadlessHostService, type PoHeadlessModelSettings } from '@agimon-ai/po-core/headless';\nimport { type PoHeadlessToolResult } from '@agimon-ai/po-core/headless';\nimport { readPackageResource, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\nimport { PO_VOICE_AUTO_MODE_ID } from '@agimon-ai/po-core/voiceTools';\nimport { serverMinorModes } from '@agimon-ai/po-minor-mode';\nimport { defineMinorMode, type MinorModeOwner, type MinorModeState } from '@agimon-ai/po-minor-mode';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { writePlanParameters } from '../../schemas/mcpTools';\nimport { resolvePlanningPlansDirectory } from '../../schemas/plan/config';\nimport {\n buildFlavorPlanningPrompt,\n buildPlanModeBasePrompt,\n type DebugEvidencePacket,\n type PlanHostCapabilities,\n type PlanningFlavor,\n} from '../../services/prompts';\nimport {\n CONTINUE_PLAN_DECISION,\n EXIT_PLAN_DECISION,\n PLAN_REVIEW_CHOICES,\n PLAN_REVIEW_TITLE,\n PLAN_STATUS_KEY,\n formatPlanStatus,\n} from '../../types/planApi';\nimport {\n PO_SUBAGENT_POLICY_SERVICE,\n readPoSubagentPolicyService,\n type SubagentPolicy,\n type SubagentPolicyHandle,\n} from '../optionalTeamServices';\nimport { readPlanText, writeNewPlanFile } from '../planFiles';\nimport { PlanPointerService } from '../planPointer';\n\nconst PLAN_ARTIFACT_SERVICE = 'po/artifacts';\ninterface PlanArtifactStorage {\n rootForSession(\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>>,\n ): Promise<string | undefined>;\n}\n\nconst RECORD_DEBUG_EVIDENCE_TOOL = 'record_debug_evidence';\nconst WRITE_PLAN_TOOL = 'write_plan';\nconst COMPLETE_PLAN_TOOL = 'complete_plan';\nconst PLAN_MODE_ID = 'plan';\nconst PLAN_MODEL_SNAPSHOT = 'plan-server-model-snapshot';\nconst PLAN_FLAVOR_SNAPSHOT = 'plan-server-flavor';\nconst PLAN_DEBUG_EVIDENCE = 'plan-debug-evidence';\nconst PLAN_DOCUMENT = 'plan-document';\n/** This host supports UI review without narrated decisions. */\nexport const PLAN_SERVER_CAPABILITIES: PlanHostCapabilities = {\n completePlanTakesDecision: false,\n narratesReview: false,\n fableAvailable: false,\n};\nconst PLAN_SUBAGENT_POLICY_OWNER = '@agimon-ai/po-plan';\n// Subagents keep every tool but `edit` and `write`, which the plan-mode restriction already withdraws from the\n// planner and, through it, from its subagents. An external runtime cannot be held to that, so none is allowed.\nconst PLAN_SUBAGENT_POLICY: SubagentPolicy = {\n owner: PLAN_SUBAGENT_POLICY_OWNER,\n allowMcpTools: true,\n allowedExternalProfiles: [],\n denyExtensions: false,\n};\n\nfunction serverPlanSubagentPolicy(host: PoHeadlessHostService): (context: Context) => void {\n return (context) => {\n context.inject([PO_SUBAGENT_POLICY_SERVICE], (child) => {\n const service = readPoSubagentPolicyService(child);\n if (!service) return undefined;\n let handle: SubagentPolicyHandle | undefined;\n const sync = (): void => {\n if (modeSelected(host)) {\n if (handle) handle.update(PLAN_SUBAGENT_POLICY);\n else handle = service.register(PLAN_SUBAGENT_POLICY);\n } else {\n handle?.dispose();\n handle = undefined;\n }\n };\n sync();\n child.effect(() => host.subscribeSelection(sync));\n return () => handle?.dispose();\n });\n };\n}\n\nfunction modeSelected(host: PoHeadlessHostService): boolean {\n return (host.context.selection.state?.['minor-mode'] ?? []).includes(PLAN_MODE_ID);\n}\n\nfunction output(value: unknown, isError = false): PoHeadlessToolResult {\n return {\n content: [{ type: 'text', text: typeof value === 'string' ? value : JSON.stringify(value, null, 2) }],\n details: value,\n ...(isError ? { isError: true } : {}),\n };\n}\n\nexport function createPlanServerSession(\n host: PoHeadlessHostService,\n options: { homeDirectory?: string },\n): Omit<PoServerSessionPlugin, 'tools'> & { tools: Parameters<PoHeadlessHostService['registerTool']>[0][] } {\n let flavor: PlanningFlavor = 'normal';\n let debugEvidence: DebugEvidencePacket | undefined;\n let modeOwner: MinorModeOwner | undefined;\n const selected = (): boolean => modeSelected(host);\n let configService: IPoConfigService | undefined;\n let artifactStorage: PlanArtifactStorage | undefined;\n const planningConfig = () => configService?.getSnapshot().settings.modes?.planning;\n // One resolution for both the prompt and write_plan.\n const plansDirectory = async (): Promise<string> => {\n const root = await artifactStorage?.rootForSession(host.context.sessionId, host.context.environment);\n if (root !== undefined) return path.join(root, 'plans');\n if (options.homeDirectory === undefined) throw new Error('Po needs a home directory to choose the plans folder.');\n return resolvePlanningPlansDirectory(\n planningConfig()?.plansDirectory,\n host.context.repoRoot,\n options.homeDirectory,\n );\n };\n const pointers = new PlanPointerService({\n env: host.context.environment,\n homeDirectory: options.homeDirectory,\n });\n /**\n * The activity group's line, and the pointer its panel reads.\n *\n * A cockpit drives this server plugin and never the Pi runtime, so both were written\n * only on the Pi side: the group never appeared, and when it did its panel\n * had no pointer to answer from.\n */\n const announcePlanDocument = (filePath: string, title: string, writtenAt: string): void => {\n try {\n pointers.write(host.context.sessionId, { path: filePath, title, writtenAt });\n } catch {\n // The plan is on disk either way. Losing the cockpit's view of it is not\n // a reason to fail the write that produced it.\n }\n host.context.client.setStatus(PLAN_STATUS_KEY, formatPlanStatus(title, planStampOf(writtenAt)));\n };\n const modeState = (): MinorModeState => {\n const active = selected();\n return {\n activation: active ? 'active' : 'inactive',\n condition: 'ready',\n ...(active ? { detail: `${flavor} - read only`, modelContextVariant: flavor } : {}),\n actions: [\n {\n id: 'activate',\n enabled: true,\n },\n {\n id: 'deactivate',\n enabled: active,\n ...(active ? {} : { disabledReason: 'Plan mode is inactive.' }),\n },\n ],\n };\n };\n const publishMode = (): void => modeOwner?.publish();\n const restoreModel = async (): Promise<void> => {\n const session = host.context.session;\n const entries = await session.entries({ type: 'custom', customType: PLAN_MODEL_SNAPSHOT, limit: 1 });\n const data = entries[0]?.data;\n if (data === undefined || data === null) return;\n if (\n typeof data !== 'object' ||\n !('thinkingLevel' in data) ||\n !['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'].includes(String(data.thinkingLevel))\n )\n throw new Error('The saved planning model settings are invalid.');\n if (!session.setModelSettings) throw new Error('This session cannot restore its model settings.');\n await session.setModelSettings(data as PoHeadlessModelSettings);\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, null);\n };\n const selectPlan = async (enabled: boolean, nextFlavor = flavor): Promise<void> => {\n const wasEnabled = selected();\n const session = host.context.session;\n if (enabled && !wasEnabled) {\n const config = planningConfig()?.main;\n if (config?.model || config?.thinking) {\n if (!session.readModelSettings || !session.setModelSettings)\n throw new Error('This session cannot apply planning model settings.');\n const previous = await session.readModelSettings();\n const settings: Partial<PoHeadlessModelSettings> = {};\n if (config.model) {\n const separator = config.model.indexOf('/');\n const provider = separator > 0 ? config.model.slice(0, separator) : previous.model?.provider;\n if (!provider) throw new Error('The planning model needs a provider.');\n settings.model = { provider, id: separator > 0 ? config.model.slice(separator + 1) : config.model };\n }\n if (config.thinking) settings.thinkingLevel = config.thinking;\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, previous);\n try {\n await session.setModelSettings(settings);\n } catch (error) {\n await session.setModelSettings(previous);\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, null);\n throw error;\n }\n }\n } else if (!enabled && wasEnabled) {\n await restoreModel();\n }\n const modes = (host.context.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== PLAN_MODE_ID);\n await host.changeSelection({\n axis: 'state',\n key: 'minor-mode',\n values: enabled ? [...modes, PLAN_MODE_ID] : modes,\n });\n flavor = nextFlavor;\n // Persisted because the minor mode survives a server restart while this local does not, and\n // the prompt is built from it. Without this a restored debug session silently plans as normal.\n await session.appendCustomEntry(PLAN_FLAVOR_SNAPSHOT, enabled ? { flavor } : null);\n publishMode();\n };\n\n /** Newest value for a custom entry type, or undefined when none was recorded. */\n const latestEntry = async (customType: string): Promise<unknown> => {\n const entries = await host.context.session.entries({ type: 'custom', customType, limit: 1 });\n return entries[0]?.data ?? undefined;\n };\n\n const restorePlanState = async (): Promise<void> => {\n const saved = await latestEntry(PLAN_FLAVOR_SNAPSHOT);\n if (saved !== undefined && saved !== null && typeof saved === 'object' && 'flavor' in saved) {\n const candidate = String((saved as { flavor: unknown }).flavor);\n if (candidate === 'fable') flavor = 'normal';\n else if (candidate === 'normal' || candidate === 'debug' || candidate === 'code-review') flavor = candidate;\n }\n const evidence = await latestEntry(PLAN_DEBUG_EVIDENCE);\n if (evidence === undefined || evidence === null) return;\n try {\n debugEvidence = parseDebugEvidencePacket(evidence);\n } catch {\n // A packet written by an older shape must not stop the session from planning.\n debugEvidence = undefined;\n }\n };\n modeOwner = defineMinorMode({\n descriptor: {\n source: '@agimon-ai/po-plan',\n id: PLAN_MODE_ID,\n label: 'Plan',\n description: 'Read-only planning with normal, debug, and code review flavors.',\n order: 40,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Activate plan mode or switch its planning flavor.',\n contexts: ['headless'],\n parameters: [\n {\n name: 'flavor',\n label: 'Flavor',\n kind: 'enum',\n required: true,\n choices: [\n { value: 'normal', label: 'Normal' },\n { value: 'debug', label: 'Debug' },\n { value: 'code-review', label: 'Code Review' },\n ],\n },\n ],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Exit plan mode and restore the previous agent configuration.',\n contexts: ['headless'],\n parameters: [],\n },\n ],\n },\n state: () => modeState(),\n async handleAction(_runtime, actionId, argumentsValue, { signal }) {\n signal.throwIfAborted();\n if (actionId === 'activate') {\n const nextFlavor = argumentsValue.flavor;\n if (nextFlavor !== 'normal' && nextFlavor !== 'debug' && nextFlavor !== 'code-review')\n throw new Error('A valid plan flavor is required.');\n await selectPlan(true, nextFlavor);\n return { message: `Plan mode is active with the ${nextFlavor} flavor.` };\n }\n if (actionId === 'deactivate') {\n await selectPlan(false);\n return { message: 'Plan mode deactivated.' };\n }\n throw new Error(`Unknown plan mode action: ${actionId}`);\n },\n }).createOwner(undefined);\n return {\n services: [\n serverMinorModes([modeOwner]),\n serverPlanSubagentPolicy(host),\n (context) => {\n context.inject([PO_CONFIG_SERVICE], (child) => {\n const service = child.get(PO_CONFIG_SERVICE) as IPoConfigService;\n configService = service;\n return () => {\n if (configService === service) configService = undefined;\n };\n });\n context.inject([PLAN_ARTIFACT_SERVICE], (child) => {\n const storage = child.get(PLAN_ARTIFACT_SERVICE) as PlanArtifactStorage;\n artifactStorage = storage;\n return () => {\n if (artifactStorage === storage) artifactStorage = undefined;\n };\n });\n },\n ],\n resources: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: 'po-use-plan',\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-plan/SKILL.md'),\n },\n ],\n tools: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: RECORD_DEBUG_EVIDENCE_TOOL,\n label: 'Record Debug Evidence',\n description: 'Record bounded debug evidence as optional planning context.',\n parameters: {\n type: 'object',\n properties: {\n issue: { type: 'string' },\n expectedBehavior: { type: 'string' },\n reproductionAttempt: { type: 'string' },\n actualBehavior: { type: 'string' },\n logs: { type: 'array', items: { type: 'string' } },\n correlatedTraceEvidence: { type: 'array', items: { type: 'string' } },\n processOutput: { type: 'array', items: { type: 'string' } },\n browserConsoleEvidence: { type: 'array', items: { type: 'string' } },\n correlationIds: { type: 'array', items: { type: 'string' } },\n timestamps: { type: 'array', items: { type: 'string' } },\n verifiedFacts: { type: 'array', items: { type: 'string' } },\n hypotheses: { type: 'array', items: { type: 'string' } },\n unavailableEvidence: { type: 'array', items: { type: 'string' } },\n },\n required: ['issue'],\n additionalProperties: false,\n },\n executionMode: 'serial',\n async execute(_toolCallId, parameters) {\n try {\n const parsedEvidence = parseDebugEvidencePacket(parameters);\n await host.context.session.appendCustomEntry(PLAN_DEBUG_EVIDENCE, parsedEvidence);\n // Held in memory too: the debug prompt is rebuilt every turn from this packet.\n debugEvidence = parsedEvidence;\n return output({ recorded: true });\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: WRITE_PLAN_TOOL,\n label: 'Write Plan',\n mainAgentOnly: true,\n description: 'Save the supplied Markdown plan, or the plan already presented in the local session.',\n parameters: writePlanParameters,\n executionMode: 'serial',\n async execute(toolCallId, parameters, signal) {\n try {\n signal?.throwIfAborted();\n // Remote callers supply their own visible Markdown. Only local calls may use the journal.\n let content =\n typeof parameters === 'object' && parameters !== null && 'markdown' in parameters\n ? parameters.markdown\n : undefined;\n if (content !== undefined && typeof content !== 'string')\n throw new Error('Plan Markdown must be a string.');\n if (content === undefined)\n content = visiblePlanForToolCall(await host.context.session.entries(), toolCallId);\n if (content === undefined) {\n if (host.context.selection.state?.['minor-mode']?.includes(PO_VOICE_AUTO_MODE_ID))\n throw new Error('Supply Markdown to write_plan during autonomous Voice; UI input is unavailable.');\n const requested = await host.context.client.request(\n {\n kind: 'input',\n title: 'Implementation plan',\n multiline: true,\n },\n signal,\n );\n content = typeof requested === 'string' ? requested : '';\n }\n if (typeof content !== 'string' || !content.trim())\n throw new Error('No implementation plan content was supplied.');\n const directory = await plansDirectory();\n const title = planTitleOf(content);\n const writtenAt = new Date().toISOString();\n const filename = `${planTitleSlug(content)}-${Date.now()}.md`;\n const filePath = await writeNewPlanFile(directory, filename, `${content.trim()}\\n`);\n await host.context.session.appendCustomEntry(PLAN_DOCUMENT, {\n path: filePath,\n content: content.trim(),\n title,\n writtenAt,\n });\n announcePlanDocument(filePath, title, writtenAt);\n await selectPlan(true);\n const saved = { path: filePath, written: true };\n return { ...output(saved), structuredContent: saved };\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: COMPLETE_PLAN_TOOL,\n label: 'Complete Plan',\n mainAgentOnly: true,\n description:\n 'Request exit-or-continue approval in the local Po UI. Requires the user to interact there; this is not a ChatGPT approval dialog.',\n // No decision parameter: this server plugin has no narrated review to answer, so a model-supplied\n // decision would be the agent approving its own plan instead of the reader approving it.\n parameters: { type: 'object', properties: {}, additionalProperties: false },\n executionMode: 'serial',\n async execute(_toolCallId, _parameters, signal) {\n try {\n if (host.context.selection.state?.['minor-mode']?.includes(PO_VOICE_AUTO_MODE_ID))\n throw new Error(\n 'UI plan review is unavailable during autonomous Voice. Wait for explicit user direction.',\n );\n // The client answers with the option's `value`, so the decision travels with the\n // question instead of the server plugin having to recognise the label it rendered.\n const decision = await host.context.client.request(\n {\n kind: 'select',\n title: PLAN_REVIEW_TITLE,\n options: PLAN_REVIEW_CHOICES.map((choice) => ({ ...choice })),\n },\n signal,\n );\n // A dismissed or aborted prompt answers with nothing, and that is not approval.\n const exited = decision === EXIT_PLAN_DECISION;\n await host.context.session.appendCustomEntry('plan-review', {\n decision: exited ? EXIT_PLAN_DECISION : CONTINUE_PLAN_DECISION,\n });\n await selectPlan(!exited);\n return {\n content: [{ type: 'text', text: exited ? PLAN_EXIT_APPROVED_TEXT : PLAN_CONTINUE_TEXT }],\n details: { exited },\n };\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n ],\n hooks: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n event: 'before_agent_start',\n async handle(event) {\n const prompt = typeof event.systemPrompt === 'string' ? event.systemPrompt : '';\n const directory = await plansDirectory();\n const sections = [\n buildPlanModeBasePrompt(directory, PLAN_SERVER_CAPABILITIES),\n buildFlavorPlanningPrompt(flavor, directory, debugEvidence),\n ];\n const saved = await latestEntry(PLAN_DOCUMENT);\n if (saved !== undefined && saved !== null && typeof saved === 'object' && 'path' in saved) {\n const document = saved as { path: string; content?: string };\n // Read from disk rather than from what write_plan remembered: the plan is editable in\n // the cockpit, and a reader who corrected it expects that correction implemented.\n let content = document.content ?? '';\n try {\n content = await readPlanText(document.path);\n } catch {\n content = document.content ?? '';\n }\n if (content.trim()) sections.push(`[CURRENT PLAN]\\nSource: ${document.path}\\n\\n${content}`);\n }\n return { systemPrompt: `${prompt}\\n\\n${sections.join('\\n\\n')}`.trim() };\n },\n },\n {\n event: 'session_start',\n async handle() {\n await restorePlanState();\n // A plan written in an earlier session is still the session's plan, so\n // the dock has to hear about it again on every restart.\n const pointer = pointers.read(host.context.sessionId);\n if (pointer)\n host.context.client.setStatus(\n PLAN_STATUS_KEY,\n formatPlanStatus(pointer.title, planStampOf(pointer.writtenAt)),\n );\n // Restore a saved model override if Plan was not restored with the session.\n if (!selected()) await restoreModel();\n },\n },\n {\n // Older harness sessions persisted plan-mode context messages; keep them out of the model context.\n event: 'context',\n async handle(event) {\n if (!Array.isArray(event.messages)) return;\n return {\n messages: event.messages.filter(\n (message) => (message as { customType?: string }).customType !== PLAN_MODE_CONTEXT,\n ),\n };\n },\n },\n ],\n };\n}\n\nconst DEFAULT_PLAN_TITLE = 'implementation-plan';\nconst PLAN_TITLE_MAX_LENGTH = 64;\nconst DEBUG_EVIDENCE_MAX_BYTES = 32 * 1024;\nconst DEBUG_EVIDENCE_MAX_TEXT_BYTES = 4 * 1024;\nconst DEBUG_EVIDENCE_MAX_ITEMS = 32;\nexport const PLAN_MODE_CONTEXT = 'agent-harness-plan-mode-context';\nexport const PLAN_EXIT_APPROVED_TEXT =\n 'The user approved exiting plan mode. Full tool access is restored. Begin implementing the approved plan.';\nexport const PLAN_CONTINUE_TEXT = 'The user chose to continue planning. Remain read-only and refine the plan.';\n/** The plan's own heading, as the status line and the pointer record word it. */\nexport function planTitleOf(markdown: string): string {\n return markdown.match(/^#\\s+(.+?)\\s*$/m)?.[1] ?? DEFAULT_PLAN_TITLE;\n}\n\nexport function planTitleSlug(markdown: string): string {\n const heading = planTitleOf(markdown);\n return (\n heading\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, PLAN_TITLE_MAX_LENGTH) || DEFAULT_PLAN_TITLE\n );\n}\n\n/**\n * How the status line words when a plan was written. A malformed timestamp is\n * shown as it came rather than as an invalid date: the stamp's other job is to\n * change on a rewrite, and it can still do that.\n */\nexport function planStampOf(writtenAt: string): string {\n const at = new Date(writtenAt);\n return Number.isNaN(at.getTime()) ? writtenAt : at.toLocaleTimeString();\n}\n\nexport function visiblePlanForToolCall(entries: readonly unknown[], toolCallId: string): string | undefined {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (!entry || typeof entry !== 'object') continue;\n const candidate = entry as {\n type?: string;\n message?: { role?: string; content?: unknown };\n };\n if (candidate.type !== 'message' || candidate.message?.role !== 'assistant') continue;\n if (!Array.isArray(candidate.message.content)) continue;\n\n const toolIndex = candidate.message.content.findIndex((block) => {\n if (!block || typeof block !== 'object') return false;\n const content = block as { type?: string; id?: string; name?: string };\n return content.type === 'toolCall' && content.id === toolCallId && content.name === WRITE_PLAN_TOOL;\n });\n if (toolIndex < 0) continue;\n\n const plan = candidate.message.content\n .slice(0, toolIndex)\n .flatMap((block) => {\n if (!block || typeof block !== 'object') return [];\n const content = block as { type?: string; text?: unknown };\n return content.type === 'text' && typeof content.text === 'string' ? [content.text] : [];\n })\n .join('\\n\\n')\n .trim();\n return plan || undefined;\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nfunction boundedDebugText(value: unknown, field: string, required: boolean): string {\n if (!isString(value)) throw new Error(`${field} must be a string.`);\n const text = value.trim();\n if (required && !text) throw new Error(`${field} must not be empty.`);\n if (Buffer.byteLength(text, 'utf8') > DEBUG_EVIDENCE_MAX_TEXT_BYTES) {\n throw new Error(`${field} exceeds the bounded debug evidence limit.`);\n }\n return text;\n}\n\nfunction boundedDebugList(value: unknown, field: string): string[] {\n if (!Array.isArray(value) || value.length > DEBUG_EVIDENCE_MAX_ITEMS) {\n throw new Error(`${field} must be a bounded string array.`);\n }\n return value.map((item, index) => boundedDebugText(item, `${field}[${index}]`, false));\n}\n\nfunction optionalDebugText(value: unknown, field: string): string {\n return value === undefined ? '' : boundedDebugText(value, field, false);\n}\n\nfunction optionalDebugList(value: unknown, field: string): string[] {\n return value === undefined ? [] : boundedDebugList(value, field);\n}\n\nfunction assertExactObjectKeys(value: Record<string, unknown>, keys: readonly string[], field: string): void {\n const allowed = new Set(keys);\n const unexpected = Object.keys(value).find((key) => !allowed.has(key));\n if (unexpected) throw new Error(`${field} contains unsupported field '${unexpected}'.`);\n}\n\nexport function parseDebugEvidencePacket(value: unknown): DebugEvidencePacket {\n if (!isRecord(value)) throw new Error('Debug evidence must be an object.');\n assertExactObjectKeys(\n value,\n [\n 'issue',\n 'expectedBehavior',\n 'reproductionAttempt',\n 'actualBehavior',\n 'logs',\n 'correlatedTraceEvidence',\n 'processOutput',\n 'browserConsoleEvidence',\n 'correlationIds',\n 'timestamps',\n 'verifiedFacts',\n 'hypotheses',\n 'unavailableEvidence',\n ],\n 'Debug evidence',\n );\n const packet: DebugEvidencePacket = {\n issue: boundedDebugText(value.issue, 'issue', true),\n expectedBehavior: optionalDebugText(value.expectedBehavior, 'expectedBehavior'),\n reproductionAttempt: optionalDebugText(value.reproductionAttempt, 'reproductionAttempt'),\n actualBehavior: optionalDebugText(value.actualBehavior, 'actualBehavior'),\n logs: optionalDebugList(value.logs, 'logs'),\n correlatedTraceEvidence: optionalDebugList(value.correlatedTraceEvidence, 'correlatedTraceEvidence'),\n processOutput: optionalDebugList(value.processOutput, 'processOutput'),\n browserConsoleEvidence: optionalDebugList(value.browserConsoleEvidence, 'browserConsoleEvidence'),\n correlationIds: optionalDebugList(value.correlationIds, 'correlationIds'),\n timestamps: optionalDebugList(value.timestamps, 'timestamps'),\n verifiedFacts: optionalDebugList(value.verifiedFacts, 'verifiedFacts'),\n hypotheses: optionalDebugList(value.hypotheses, 'hypotheses'),\n unavailableEvidence: optionalDebugList(value.unavailableEvidence, 'unavailableEvidence'),\n };\n if (Buffer.byteLength(JSON.stringify(packet), 'utf8') > DEBUG_EVIDENCE_MAX_BYTES) {\n throw new Error('Debug evidence exceeds the bounded packet size.');\n }\n return packet;\n}\n","import { defineRoot, type RootDeclaration } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext, PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\n\nimport { mountMcpTools } from '../../../../services/mcpTools';\nimport { api } from '../../../../services/planApi';\nimport { createPlanServerSession } from '../../../../services/planServerSession';\n\nexport default defineRoot(\n ({ agent, host }: PoServerPluginContext): RootDeclaration<PoServerSessionPlugin, PoServerPluginContext> => {\n const value = {\n api: [api],\n ...(agent\n ? createPlanServerSession(agent, {\n homeDirectory: host.context.homeDirectory ?? host.context.environment?.HOME,\n })\n : {}),\n };\n return {\n value,\n services: [...(value.services ?? []), ...(value.tools?.length ? [mountMcpTools(value.tools)] : [])],\n };\n },\n);\n","import { defineRoute, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../../root.server').default>>['value'];\n\nexport default defineRoute((context: WithRoot<unknown, Root>) => context.root.api![0]!);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[0], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[2], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[1], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.resources?.[0], {\n cardinality: 'optional',\n});\n","import { defineToolRestriction } from '@agimon-ai/po-core/extensionFile';\nimport type { PoHeadlessToolRestriction } from '@agimon-ai/po-core/headless';\nimport { PO_VOICE_AUTO_MODE_ID } from '@agimon-ai/po-core/voiceTools';\n\nexport default defineToolRestriction({\n when: { state: { 'minor-mode': PO_VOICE_AUTO_MODE_ID } },\n excludedTools: ['complete_plan'],\n} satisfies PoHeadlessToolRestriction);\n","import { defineToolRestriction } from '@agimon-ai/po-core/extensionFile';\nimport type { PoHeadlessToolRestriction } from '@agimon-ai/po-core/headless';\n\nexport default defineToolRestriction({\n when: { state: { 'minor-mode': 'plan' } },\n excludedTools: ['edit', 'write'],\n} satisfies PoHeadlessToolRestriction);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[2], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[0], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[1], {\n cardinality: 'optional',\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\nimport { composeServerProviderOverrides } from '@agimon-ai/po-core/serverPlugin';\nimport { composeRootHooks, composeRootInjects } from '@agimon-ai/po-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/plans/route.server';\nimport hookBeforeAgentStart from '../src/extensions/workspaces/sessions/(backend)/hook/beforeAgentStart.server';\nimport hookContext from '../src/extensions/workspaces/sessions/(backend)/hook/context.server';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server';\nimport resourcePoUsePlan from '../src/extensions/workspaces/sessions/(backend)/resource/poUsePlan.server';\nimport toolRestrictionPlan from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/plan.server';\nimport toolRestrictionPlanReadOnly from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/planReadOnly.server';\nimport toolCompletePlan from '../src/extensions/workspaces/sessions/(backend)/tool/completePlan.server';\nimport toolRecordDebugEvidence from '../src/extensions/workspaces/sessions/(backend)/tool/recordDebugEvidence.server';\nimport toolWritePlan from '../src/extensions/workspaces/sessions/(backend)/tool/writePlan.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const serverPlugin = defineServerPlugin({\n name: '@agimon-ai/po-plan',\n providerOverrides: composeServerProviderOverrides(rootSession),\n injects: composeRootInjects({ session: [rootSession] }),\n session: async (context) => {\n const scopeSession = await context.scopeRoot('session', rootSession, context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get api(): PoServerSessionPlugin['api'] { return [at(apiRoute, contextSession)]; },\n get hooks(): PoServerSessionPlugin['hooks'] { return defined([via({ event: 'before_agent_start' }, at(hookBeforeAgentStart, contextSession)), via({ event: 'context' }, at(hookContext, contextSession)), via({ event: 'session_start' }, at(hookSessionStart, contextSession))]); },\n get resources(): PoServerSessionPlugin['resources'] { return defined([at(resourcePoUsePlan, contextSession)]); },\n get toolRestrictions(): PoServerSessionPlugin['toolRestrictions'] { return [at(toolRestrictionPlan, contextSession), at(toolRestrictionPlanReadOnly, contextSession)]; },\n get tools(): PoServerSessionPlugin['tools'] { return defined([via({ name: 'complete_plan' }, at(toolCompletePlan, contextSession)), via({ name: 'record_debug_evidence' }, at(toolRecordDebugEvidence, contextSession)), via({ name: 'write_plan' }, at(toolWritePlan, contextSession))]); },\n services: [...(scopeSession.services ?? [])],\n get activities(): PoServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default serverPlugin;\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.cjs","names":["Type","isRecord","os","path","piAgentDirectory","fs","createHash","fs","path","openGuardedFile","fileMutationRunner","createHash","createHash","Hono","path","resolvePlanningPlansDirectory","defineMinorMode","serverMinorModes","PO_CONFIG_SERVICE","readPackageResource","PO_VOICE_AUTO_MODE_ID","buildPlanModeBasePrompt","buildFlavorPlanningPrompt","Buffer","defineRoot","defineRoute","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineToolRestriction","PO_VOICE_AUTO_MODE_ID","defineToolRestriction","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineServerPlugin","composeServerProviderOverrides","rootSession","composeRootInjects","composeRootHooks","apiRoute","hookBeforeAgentStart","hookContext","hookSessionStart","resourcePoUsePlan","toolRestrictionPlan","toolRestrictionPlanReadOnly","toolCompletePlan","toolRecordDebugEvidence","toolWritePlan"],"sources":["../../src/schemas/mcpTools.ts","../../src/services/mcpTools/index.ts","../../src/services/planPointer/index.ts","../../src/types/apiRoutes.ts","../../src/types/planApi.ts","../../src/services/planFiles/index.ts","../../src/services/planApi/index.ts","../../src/services/optionalTeamServices/index.ts","../../src/services/planServerSession/index.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/api/plans/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/beforeAgentStart.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/context.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poUsePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/plan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/planReadOnly.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/completePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/recordDebugEvidence.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/writePlan.server.ts","../../generated/server.ts"],"sourcesContent":["import { Type } from 'typebox';\n\nconst markdown = Type.String({ minLength: 1 });\n\nexport const remoteWritePlanParameters = Type.Object({ markdown }, { additionalProperties: false });\nexport const writePlanParameters = Type.Object({ markdown: Type.Optional(markdown) }, { additionalProperties: false });\n","import type { PoHeadlessTool } from '@agimon-ai/po-core/headless';\nimport type { PoMcpPluginContext } from '@agimon-ai/po-core/mcpFacet';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { remoteWritePlanParameters } from '../../schemas/mcpTools';\n\nexport const PLAN_MCP_TOOLS_SERVICE = 'po/plan-mcp-tools';\n\nconst MODE_ID = 'plan';\nconst MODE_LABEL = 'Plan';\n\nexport interface McpToolCatalog {\n get(name: string): PoHeadlessTool | undefined;\n names(): readonly string[];\n}\n\nexport function mountMcpTools(tools: readonly PoHeadlessTool[]) {\n return (context: Context): void => {\n context.plugin((providerContext) => {\n providerContext.provide(PLAN_MCP_TOOLS_SERVICE, {\n get: (name) => tools.find((tool) => tool.name === name),\n names: () => tools.map((tool) => tool.name),\n } satisfies McpToolCatalog);\n });\n };\n}\n\nexport function bindMcpTool(context: PoMcpPluginContext, name: string): PoHeadlessTool {\n const catalog = context.services.get<McpToolCatalog>(PLAN_MCP_TOOLS_SERVICE);\n const tool = catalog?.get(name);\n if (!tool || !catalog) throw new Error(`Plan tool is unavailable: ${name}`);\n const writesPlan = name === 'write_plan';\n return {\n ...tool,\n ...(writesPlan\n ? {\n description:\n 'Save the supplied Markdown plan in the bound session. Requires active Plan mode. Saving does not approve implementation.',\n parameters: remoteWritePlanParameters,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },\n }\n : {}),\n execute(toolCallId, parameters, signal, onUpdate) {\n const activeModes = context.selection.read().state?.['minor-mode'] ?? [];\n if (!activeModes.includes(MODE_ID)) {\n const inactiveTools = [...catalog.names()].sort().join(', ');\n throw new Error(`${MODE_LABEL} minor mode is inactive. Inactive ${MODE_LABEL} tools: ${inactiveTools}.`);\n }\n if (\n writesPlan &&\n (typeof parameters !== 'object' ||\n parameters === null ||\n !('markdown' in parameters) ||\n typeof parameters.markdown !== 'string' ||\n !parameters.markdown.trim())\n ) {\n throw new Error(\n 'Supply the complete visible plan in the markdown argument. Remote calls cannot read the ChatGPT transcript.',\n );\n }\n const executionSignal = AbortSignal.any([context.signal, signal ?? context.signal]);\n return tool.execute(toolCallId, parameters, executionSignal, onUpdate, context.execution);\n },\n };\n}\n","import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { piAgentDirectory } from '@agimon-ai/po-core/piSettings';\n\nimport type { PlanPointerRecord } from '../../types/planApi';\nimport type { PlanPointerPort } from '../../types/planPointer';\n\n/**\n * Record and read where write_plan left this session's plan file.\n *\n * Pi already gives every session an agent directory, so the records live under\n * it rather than in a second place a reader would have to know about. The\n * posture matches the plan file itself, 0700 on the directory and 0600 on the\n * record: a plan is a private working document, not something to leave\n * world-readable in a shared home.\n */\n\nconst POINTER_DIRECTORY = 'po-plan';\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst PRIVATE_FILE_MODE = 0o600;\n\nexport interface NodePlanPointerOptions {\n env?: NodeJS.ProcessEnv;\n homeDirectory?: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport class PlanPointerService implements PlanPointerPort {\n private readonly env: NodeJS.ProcessEnv;\n private readonly homeDirectory: string;\n\n constructor(options: NodePlanPointerOptions = {}) {\n this.env = options.env ?? {};\n this.homeDirectory = options.homeDirectory ?? os.homedir();\n }\n\n /** Where the records live; exposed so a test can look without guessing. */\n directory(): string {\n return path.join(piAgentDirectory(this.env, this.homeDirectory), POINTER_DIRECTORY);\n }\n\n /**\n * The record for one session. The id is hashed rather than used as written:\n * it reaches here from a host that may word it however it likes, and a\n * filename is not the place to find that out.\n */\n pathFor(sessionId: string): string {\n return path.join(this.directory(), `${this.hash(sessionId)}.json`);\n }\n\n read(sessionId: string): PlanPointerRecord | undefined {\n let raw: string;\n try {\n raw = fs.readFileSync(this.pathFor(sessionId), 'utf8');\n } catch {\n return undefined;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!isRecord(parsed)) return undefined;\n const { path: planPath, title, writtenAt, planId } = parsed;\n // A record half-written by an interrupted run reads as no plan at all,\n // which is a state the cockpit already handles.\n if (typeof planPath !== 'string' || !path.isAbsolute(planPath)) return undefined;\n if (typeof title !== 'string' || typeof writtenAt !== 'string') return undefined;\n return { path: planPath, title, writtenAt, ...(typeof planId === 'string' ? { planId } : {}) };\n }\n\n write(sessionId: string, record: PlanPointerRecord): void {\n fs.mkdirSync(this.directory(), { recursive: true, mode: PRIVATE_DIRECTORY_MODE });\n fs.writeFileSync(this.pathFor(sessionId), JSON.stringify(record), { mode: PRIVATE_FILE_MODE });\n }\n\n clear(sessionId: string): void {\n fs.rmSync(this.pathFor(sessionId), { force: true });\n }\n\n private hash(value: string): string {\n return createHash('sha256').update(value).digest('hex').slice(0, 16);\n }\n}\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { PlanDetailView, PlanSaveView } from './planApi';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/workspaces/sessions/(backend)/api/plans/`, so the mount is\n * stated once, by the folder that creates it. The paths used to be written\n * here as helpers, again in the contract, and again inside every URL the page\n * built, and the copies were free to disagree.\n *\n * This is the one file the routes, the Hono app and the browser all read, so a\n * path cannot move on one side alone.\n *\n * Neither route takes a query or a path parameter: a session has one current\n * plan, so `current` answers it and `save` takes the manual write back.\n */\nconst routes = {\n current: {\n method: 'GET',\n path: '/current',\n response: undefined as unknown as ApiResponseOf<PlanDetailView>,\n },\n save: {\n method: 'PUT',\n path: '/content',\n response: undefined as unknown as ApiResponseOf<PlanSaveView>,\n },\n} as const satisfies ApiRoutes;\n\nexport default routes;\n","/**\n * The wire vocabulary this package's API shares with whatever calls it.\n *\n * It lives under src/types because that is the one server root a browser\n * bundle may read: the routes answer with these shapes and the cockpit plugin\n * reads them, so neither half can drift from the other. The paths themselves\n * are not here; they are declared once in `./apiRoutes`, which the Hono app\n * and the generated client both read.\n *\n * Two routes, and neither takes a path. A session has one current plan, so\n * `current` answers it and `content` takes the manual save back; the file they\n * act on is the one write_plan recorded, never one the page named. That is\n * also why there is nothing to escape here: a reader cannot address a second\n * file through these URLs.\n */\n\n/** Where a host mounts this package's API; the segment after /api/plugins/. */\nexport const API_BASE_PATH = 'plans';\n\n/**\n * Footer status key the session publishes once a plan exists, which is what\n * makes the cockpit's activity group appear at all. It outlives plan mode: the\n * plan is most worth reading while the agent implements it.\n */\nexport const PLAN_STATUS_KEY = 'po-plan-document';\n\n/** The selector contract shared by complete_plan and its cockpit composer prompt. */\nexport const PLAN_REVIEW_TITLE = 'Plan complete. What would you like to do?';\nexport const EXIT_PLAN_MODE_CHOICE = 'Exit plan mode and start implementation';\nexport const CONTINUE_PLANNING_CHOICE = 'Continue planning';\nexport const EXIT_PLAN_DECISION = 'exit';\nexport const CONTINUE_PLAN_DECISION = 'continue';\n\n/**\n * The label the reader sees paired with the decision the tool acts on. A headless\n * client answers with `value`, so a server plugin never has to recognise the wording; Pi's\n * own `ui.select` carries labels only, so its half maps the label back itself.\n */\nexport const PLAN_REVIEW_CHOICES = [\n { label: EXIT_PLAN_MODE_CHOICE, value: EXIT_PLAN_DECISION },\n { label: CONTINUE_PLANNING_CHOICE, value: CONTINUE_PLAN_DECISION },\n] as const;\n\n/** The same options as bare labels, which is all Pi's select and the composer prompt need. */\nexport const PLAN_REVIEW_OPTIONS = PLAN_REVIEW_CHOICES.map((choice) => choice.label);\n\n/** Between the plan's title and the stamp that marks a rewrite. */\nconst STATUS_SEPARATOR = ' · ';\n\n/** Strips the colour a session may have themed a status with. */\nconst ANSI = /\u001b\\[[0-9;]*m/gu;\n\n/** The status line the session publishes; the stamp changes on every write. */\nexport function formatPlanStatus(title: string, stamp: string): string {\n return `${title}${STATUS_SEPARATOR}${stamp}`;\n}\n\n/** What a reader gets out of the status line. */\nexport interface PlanStatusView {\n title: string;\n /** When the plan was last written, as the session worded it; empty when it said nothing. */\n stamp: string;\n}\n\n/**\n * Reading the status line back. Statuses reach a plugin raw, so the colour a\n * session may have added comes off here. A title can itself contain the\n * separator, so the stamp is taken from the last one rather than the first.\n */\nexport function parsePlanStatus(raw: string | undefined): PlanStatusView | undefined {\n if (raw === undefined) return undefined;\n const text = raw.replace(ANSI, '').trim();\n if (text === '') return undefined;\n const cut = text.lastIndexOf(STATUS_SEPARATOR);\n if (cut === -1) return { title: text, stamp: '' };\n return { title: text.slice(0, cut).trim(), stamp: text.slice(cut + STATUS_SEPARATOR.length).trim() };\n}\n\n/**\n * What write_plan recorded about this session's plan.\n *\n * The absolute path is the point of it: the extension resolves the plans\n * directory against the harness root, which no other process knows, so it\n * writes down where the plan landed rather than leaving the API to derive a\n * location it would sometimes get wrong.\n */\nexport interface PlanPointerRecord {\n path: string;\n title: string;\n writtenAt: string;\n planId?: string;\n}\n\n/** The plan as it stands on disk right now, which is what the source view edits. */\nexport interface PlanDetailView {\n path: string;\n title: string;\n writtenAt: string;\n planId?: string;\n content: string;\n /** sha256 of the content; the token a save hands back to prove it is not stale. */\n hash: string;\n /** True when the plan is missing or past the size cap, so `content` is empty. */\n unavailable: boolean;\n reason?: string;\n}\n\n/** What the save route takes. */\nexport interface PlanSaveRequest {\n /** The hash the reader loaded; a mismatch means the plan moved underneath them. */\n expectedHash: string;\n content: string;\n}\n\n/** What the save route answers with. */\nexport interface PlanSaveView {\n hash: string;\n}\n\n/** What a route reports when it refuses; the page shows `error` verbatim. */\nexport interface PlanErrorView {\n error: string;\n /** On a stale save, the hash the plan actually has now. */\n hash?: string;\n}\n","import { createHash } from 'node:crypto';\nimport fs, { type FileHandle } from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { fileMutationRunner, openGuardedFile } from '@agimon-ai/po-core/platform';\n\nexport async function writeNewPlanFile(directory: string, filename: string, content: string): Promise<string> {\n await fs.mkdir(directory, { recursive: true, mode: 0o700 });\n const planPath = path.join(directory, filename);\n await fs.writeFile(planPath, content, { encoding: 'utf8', flag: 'wx', mode: 0o600 });\n return planPath;\n}\n\nexport async function readPlanText(planPath: string): Promise<string> {\n return await fs.readFile(planPath, 'utf8');\n}\n\n/** The extra byte detects growth without ever reading or allocating the whole file. */\nasync function readBounded(handle: FileHandle, maxBytes: number): Promise<Buffer> {\n const stats = await handle.stat();\n if (!stats.isFile()) throw new Error('The plan is not a regular file.');\n const buffer = Buffer.alloc(maxBytes + 1);\n if (stats.size > maxBytes) return buffer;\n let offset = 0;\n while (offset < buffer.length) {\n const { bytesRead } = await handle.read(buffer, offset, buffer.length - offset, offset);\n if (bytesRead === 0) break;\n offset += bytesRead;\n }\n return buffer.subarray(0, offset);\n}\n\nexport async function readPlanBytes(planPath: string, maxBytes: number): Promise<Buffer> {\n const handle = await openGuardedFile(planPath);\n try {\n return await readBounded(handle, maxBytes);\n } finally {\n await handle.close();\n }\n}\n\n/** Compare and write the same open inode. The queue protects cooperating API writers, not external processes. */\nexport async function overwritePlanFile(\n planPath: string,\n content: string,\n expectedHash: string,\n maxBytes: number,\n): Promise<{ written: boolean; hash: string } | undefined> {\n const canonical = await fs.realpath(planPath);\n return await fileMutationRunner.forKey(canonical)(async () => {\n const handle = await openGuardedFile(planPath, { write: true });\n try {\n if ((await fs.realpath(planPath)) !== canonical) return undefined;\n const raw = await readBounded(handle, maxBytes);\n if (raw.length > maxBytes) return undefined;\n const hash = createHash('sha256').update(raw.toString('utf8'), 'utf8').digest('hex');\n if (hash !== expectedHash) return { written: false, hash };\n const opened = await handle.stat();\n const current = await fs.lstat(planPath);\n if (\n !opened.isFile() ||\n opened.nlink !== 1 ||\n !current.isFile() ||\n current.nlink !== 1 ||\n opened.dev !== current.dev ||\n opened.ino !== current.ino ||\n (await fs.realpath(planPath)) !== canonical\n )\n return undefined;\n await handle.writeFile(content, 'utf8');\n await handle.truncate(Buffer.byteLength(content, 'utf8'));\n return { written: true, hash: createHash('sha256').update(content, 'utf8').digest('hex') };\n } finally {\n await handle.close();\n }\n });\n}\n","import { createHash } from 'node:crypto';\n\nimport type { PoApi, PoApiContext, PoApiHandler } from '@agimon-ai/po-core/packageApi';\nimport { Hono } from 'hono';\n\nimport { PlanPointerService } from '../../services/planPointer';\nimport routes from '../../types/apiRoutes';\nimport { API_BASE_PATH, type PlanDetailView, type PlanSaveView } from '../../types/planApi';\nimport type { PlanPointerPort } from '../../types/planPointer';\nimport { overwritePlanFile, readPlanBytes } from '../planFiles';\n\n/**\n * This package's HTTP surface: the session's current plan, and the manual save.\n *\n * Each path comes from the route table the browser reads, so a route the page\n * calls and the route this serves cannot be spelled apart. Both are relative\n * to the mount its host gives it, so nothing here repeats where it was mounted. The host is one session's own server, which is what\n * makes the session id available without the page supplying it.\n *\n * Neither route takes a path. A session has exactly one current plan, and the\n * file both routes act on is the one the pointer names, so a page can address\n * the plan and nothing else; there is no traversal question to answer because\n * there is no path to traverse.\n *\n * The save refuses unless the reader proves they were looking at the content\n * that is still on disk. The agent may rewrite the plan while a tab is open,\n * and silently discarding whichever side finished second is the one outcome\n * worth ruling out.\n */\n\n/** Past this, the plan is reported rather than carried. */\nexport const MAX_PLAN_BYTES = 1024 * 1024;\n\nconst NO_PLAN = 'This session has not written a plan yet.';\nconst STALE_SAVE = 'The plan changed since it was opened.';\nconst NOT_A_FILE = 'The plan file is no longer a regular file, so it was not written.';\n\nexport interface PlanApiOptions {\n /** The session these routes answer for; absent when the host is the hub. */\n sessionId?: string;\n pointers?: PlanPointerPort;\n}\n\nfunction hashOf(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/** Reads the plan as the source view will show it, or says why it cannot. */\nasync function readPlan(\n planPath: string,\n): Promise<Pick<PlanDetailView, 'content' | 'hash' | 'unavailable' | 'reason'>> {\n let raw: Buffer;\n try {\n raw = await readPlanBytes(planPath, MAX_PLAN_BYTES);\n } catch {\n return { content: '', hash: '', unavailable: true, reason: 'the plan file no longer exists' };\n }\n if (raw.byteLength > MAX_PLAN_BYTES) {\n return { content: '', hash: '', unavailable: true, reason: `the plan is larger than ${MAX_PLAN_BYTES} bytes` };\n }\n const content = raw.toString('utf8');\n return { content, hash: hashOf(content), unavailable: false };\n}\n\nexport function createPlanApi(options: PlanApiOptions = {}): Hono {\n const app = new Hono();\n const pointers = options.pointers ?? new PlanPointerService();\n const pointerFor = (): ReturnType<PlanPointerPort['read']> =>\n options.sessionId === undefined ? undefined : pointers.read(options.sessionId);\n\n app.get(routes.current.path, async (context) => {\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n const view: PlanDetailView = {\n path: pointer.path,\n title: pointer.title,\n writtenAt: pointer.writtenAt,\n ...(pointer.planId === undefined ? {} : { planId: pointer.planId }),\n ...(await readPlan(pointer.path)),\n };\n return context.json(view);\n });\n\n app.put(routes.save.path, async (context) => {\n let request: unknown;\n try {\n request = await context.req.json();\n } catch {\n return context.json({ error: 'The save body is not JSON.' }, 400);\n }\n if (\n typeof request !== 'object' ||\n request === null ||\n Array.isArray(request) ||\n !('content' in request) ||\n typeof request.content !== 'string' ||\n !('expectedHash' in request) ||\n typeof request.expectedHash !== 'string'\n ) {\n return context.json({ error: 'A save carries the content to write and the hash it was read at.' }, 400);\n }\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n\n if (Buffer.byteLength(request.content, 'utf8') > MAX_PLAN_BYTES) {\n return context.json({ error: `The plan is larger than ${MAX_PLAN_BYTES} bytes.` }, 413);\n }\n try {\n const saved = await overwritePlanFile(pointer.path, request.content, request.expectedHash, MAX_PLAN_BYTES);\n if (saved === undefined) return context.json({ error: NOT_A_FILE }, 409);\n if (!saved.written) return context.json({ error: STALE_SAVE, hash: saved.hash }, 409);\n return context.json({ hash: saved.hash } satisfies PlanSaveView);\n } catch {\n return context.json({ error: NOT_A_FILE }, 409);\n }\n });\n\n return app;\n}\n\n/** The named export a host imports from this package's built entry. */\nexport const api: PoApi = {\n basePath: API_BASE_PATH,\n start(context: PoApiContext): PoApiHandler {\n const app = createPlanApi({\n ...(context.sessionId === undefined ? {} : { sessionId: context.sessionId }),\n pointers: new PlanPointerService({\n env: context.environment ?? {},\n homeDirectory: context.homeDirectory,\n }),\n });\n return {\n fetch: (request) => app.fetch(request),\n // Nothing outlives a request here; an API that starts a watch or a timer\n // tears it down in this callback.\n close: () => undefined,\n };\n },\n};\n","import type { Context } from '@deepseek-ai/cordis';\n\nimport { FABLE_PLAN_REQUESTER, type FablePlanRequest, type FablePlanResult } from '../fableFlow';\n\nexport const PO_FABLE_PLAN_SERVICE = 'po/fable-plan';\nexport const PO_SUBAGENT_POLICY_SERVICE = 'po/subagent-policy';\n\nexport interface PoFablePlanService {\n start(request: FablePlanRequest, signal: AbortSignal): Promise<FablePlanResult>;\n cancel(request: { requester: typeof FABLE_PLAN_REQUESTER; operationId: string; reason: string }): void;\n}\n\nexport interface SubagentPolicy {\n owner: string;\n allowedTools?: string[];\n requiredTools?: string[];\n allowMcpTools?: boolean;\n allowedExternalProfiles?: string[];\n denyExtensions?: boolean;\n}\n\nexport interface SubagentPolicyHandle {\n update(policy: SubagentPolicy): void;\n dispose(): void;\n}\n\nexport interface PoSubagentPolicyService {\n register(policy: SubagentPolicy): SubagentPolicyHandle;\n}\n\ntype StructuralServiceContext = {\n get(name: string): unknown;\n};\n\nexport function readPoFablePlanService(ctx: Context): PoFablePlanService | undefined {\n return (ctx as unknown as StructuralServiceContext).get(PO_FABLE_PLAN_SERVICE) as PoFablePlanService | undefined;\n}\n\nexport function readPoSubagentPolicyService(ctx: Context): PoSubagentPolicyService | undefined {\n return (ctx as unknown as StructuralServiceContext).get(PO_SUBAGENT_POLICY_SERVICE) as\n | PoSubagentPolicyService\n | undefined;\n}\n","import { Buffer } from 'node:buffer';\nimport path from 'node:path';\n\nimport type { IPoConfigService } from '@agimon-ai/po-config';\nimport { PO_CONFIG_SERVICE } from '@agimon-ai/po-core/config';\nimport { type PoHeadlessHostService, type PoHeadlessModelSettings } from '@agimon-ai/po-core/headless';\nimport { type PoHeadlessToolResult } from '@agimon-ai/po-core/headless';\nimport { readPackageResource, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\nimport { PO_VOICE_AUTO_MODE_ID } from '@agimon-ai/po-core/voiceTools';\nimport { serverMinorModes } from '@agimon-ai/po-minor-mode';\nimport { defineMinorMode, type MinorModeOwner, type MinorModeState } from '@agimon-ai/po-minor-mode';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { writePlanParameters } from '../../schemas/mcpTools';\nimport { resolvePlanningPlansDirectory } from '../../schemas/plan/config';\nimport {\n buildFlavorPlanningPrompt,\n buildPlanModeBasePrompt,\n type DebugEvidencePacket,\n type PlanHostCapabilities,\n type PlanningFlavor,\n} from '../../services/prompts';\nimport {\n CONTINUE_PLAN_DECISION,\n EXIT_PLAN_DECISION,\n PLAN_REVIEW_CHOICES,\n PLAN_REVIEW_TITLE,\n PLAN_STATUS_KEY,\n formatPlanStatus,\n} from '../../types/planApi';\nimport {\n PO_SUBAGENT_POLICY_SERVICE,\n readPoSubagentPolicyService,\n type SubagentPolicy,\n type SubagentPolicyHandle,\n} from '../optionalTeamServices';\nimport { readPlanText, writeNewPlanFile } from '../planFiles';\nimport { PlanPointerService } from '../planPointer';\n\nconst PLAN_ARTIFACT_SERVICE = 'po/artifacts';\ninterface PlanArtifactStorage {\n rootForSession(\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>>,\n ): Promise<string | undefined>;\n}\n\nconst RECORD_DEBUG_EVIDENCE_TOOL = 'record_debug_evidence';\nconst WRITE_PLAN_TOOL = 'write_plan';\nconst COMPLETE_PLAN_TOOL = 'complete_plan';\nconst PLAN_MODE_ID = 'plan';\nconst PLAN_MODEL_SNAPSHOT = 'plan-server-model-snapshot';\nconst PLAN_FLAVOR_SNAPSHOT = 'plan-server-flavor';\nconst PLAN_DEBUG_EVIDENCE = 'plan-debug-evidence';\nconst PLAN_DOCUMENT = 'plan-document';\n/** This host supports UI review without narrated decisions. */\nexport const PLAN_SERVER_CAPABILITIES: PlanHostCapabilities = {\n completePlanTakesDecision: false,\n narratesReview: false,\n fableAvailable: false,\n};\nconst PLAN_SUBAGENT_POLICY_OWNER = '@agimon-ai/po-plan';\n// Subagents keep every tool but `edit` and `write`, which the plan-mode restriction already withdraws from the\n// planner and, through it, from its subagents. An external runtime cannot be held to that, so none is allowed.\nconst PLAN_SUBAGENT_POLICY: SubagentPolicy = {\n owner: PLAN_SUBAGENT_POLICY_OWNER,\n allowMcpTools: true,\n allowedExternalProfiles: [],\n denyExtensions: false,\n};\n\nfunction serverPlanSubagentPolicy(host: PoHeadlessHostService): (context: Context) => void {\n return (context) => {\n context.inject([PO_SUBAGENT_POLICY_SERVICE], (child) => {\n const service = readPoSubagentPolicyService(child);\n if (!service) return undefined;\n let handle: SubagentPolicyHandle | undefined;\n const sync = (): void => {\n if (modeSelected(host)) {\n if (handle) handle.update(PLAN_SUBAGENT_POLICY);\n else handle = service.register(PLAN_SUBAGENT_POLICY);\n } else {\n handle?.dispose();\n handle = undefined;\n }\n };\n sync();\n child.effect(() => host.subscribeSelection(sync));\n return () => handle?.dispose();\n });\n };\n}\n\nfunction modeSelected(host: PoHeadlessHostService): boolean {\n return (host.context.selection.state?.['minor-mode'] ?? []).includes(PLAN_MODE_ID);\n}\n\nfunction output(value: unknown, isError = false): PoHeadlessToolResult {\n return {\n content: [{ type: 'text', text: typeof value === 'string' ? value : JSON.stringify(value, null, 2) }],\n details: value,\n ...(isError ? { isError: true } : {}),\n };\n}\n\nexport function createPlanServerSession(\n host: PoHeadlessHostService,\n options: { homeDirectory?: string },\n): Omit<PoServerSessionPlugin, 'tools'> & { tools: Parameters<PoHeadlessHostService['registerTool']>[0][] } {\n let flavor: PlanningFlavor = 'normal';\n let debugEvidence: DebugEvidencePacket | undefined;\n let modeOwner: MinorModeOwner | undefined;\n const selected = (): boolean => modeSelected(host);\n let configService: IPoConfigService | undefined;\n let artifactStorage: PlanArtifactStorage | undefined;\n const planningConfig = () => configService?.getSnapshot().settings.modes?.planning;\n // One resolution for both the prompt and write_plan.\n const plansDirectory = async (): Promise<string> => {\n const root = await artifactStorage?.rootForSession(host.context.sessionId, host.context.environment);\n if (root !== undefined) return path.join(root, 'plans');\n if (options.homeDirectory === undefined) throw new Error('Po needs a home directory to choose the plans folder.');\n return resolvePlanningPlansDirectory(\n planningConfig()?.plansDirectory,\n host.context.repoRoot,\n options.homeDirectory,\n );\n };\n const pointers = new PlanPointerService({\n env: host.context.environment,\n homeDirectory: options.homeDirectory,\n });\n /**\n * The activity group's line, and the pointer its panel reads.\n *\n * A cockpit drives this server plugin and never the Pi runtime, so both were written\n * only on the Pi side: the group never appeared, and when it did its panel\n * had no pointer to answer from.\n */\n const announcePlanDocument = (filePath: string, title: string, writtenAt: string): void => {\n try {\n pointers.write(host.context.sessionId, { path: filePath, title, writtenAt });\n } catch {\n // The plan is on disk either way. Losing the cockpit's view of it is not\n // a reason to fail the write that produced it.\n }\n host.context.client.setStatus(PLAN_STATUS_KEY, formatPlanStatus(title, planStampOf(writtenAt)));\n };\n const modeState = (): MinorModeState => {\n const active = selected();\n return {\n activation: active ? 'active' : 'inactive',\n condition: 'ready',\n ...(active ? { detail: `${flavor} - read only`, modelContextVariant: flavor } : {}),\n actions: [\n {\n id: 'activate',\n enabled: true,\n },\n {\n id: 'deactivate',\n enabled: active,\n ...(active ? {} : { disabledReason: 'Plan mode is inactive.' }),\n },\n ],\n };\n };\n const publishMode = (): void => modeOwner?.publish();\n const restoreModel = async (): Promise<void> => {\n const session = host.context.session;\n const entries = await session.entries({ type: 'custom', customType: PLAN_MODEL_SNAPSHOT, limit: 1 });\n const data = entries[0]?.data;\n if (data === undefined || data === null) return;\n if (\n typeof data !== 'object' ||\n !('thinkingLevel' in data) ||\n !['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'].includes(String(data.thinkingLevel))\n )\n throw new Error('The saved planning model settings are invalid.');\n if (!session.setModelSettings) throw new Error('This session cannot restore its model settings.');\n await session.setModelSettings(data as PoHeadlessModelSettings);\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, null);\n };\n const selectPlan = async (enabled: boolean, nextFlavor = flavor): Promise<void> => {\n const wasEnabled = selected();\n const session = host.context.session;\n if (enabled && !wasEnabled) {\n const config = planningConfig()?.main;\n if (config?.model || config?.thinking) {\n if (!session.readModelSettings || !session.setModelSettings)\n throw new Error('This session cannot apply planning model settings.');\n const previous = await session.readModelSettings();\n const settings: Partial<PoHeadlessModelSettings> = {};\n if (config.model) {\n const separator = config.model.indexOf('/');\n const provider = separator > 0 ? config.model.slice(0, separator) : previous.model?.provider;\n if (!provider) throw new Error('The planning model needs a provider.');\n settings.model = { provider, id: separator > 0 ? config.model.slice(separator + 1) : config.model };\n }\n if (config.thinking) settings.thinkingLevel = config.thinking;\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, previous);\n try {\n await session.setModelSettings(settings);\n } catch (error) {\n await session.setModelSettings(previous);\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, null);\n throw error;\n }\n }\n } else if (!enabled && wasEnabled) {\n await restoreModel();\n }\n const modes = (host.context.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== PLAN_MODE_ID);\n await host.changeSelection({\n axis: 'state',\n key: 'minor-mode',\n values: enabled ? [...modes, PLAN_MODE_ID] : modes,\n });\n flavor = nextFlavor;\n // Persisted because the minor mode survives a server restart while this local does not, and\n // the prompt is built from it. Without this a restored debug session silently plans as normal.\n await session.appendCustomEntry(PLAN_FLAVOR_SNAPSHOT, enabled ? { flavor } : null);\n publishMode();\n };\n\n /** Newest value for a custom entry type, or undefined when none was recorded. */\n const latestEntry = async (customType: string): Promise<unknown> => {\n const entries = await host.context.session.entries({ type: 'custom', customType, limit: 1 });\n return entries[0]?.data ?? undefined;\n };\n\n const restorePlanState = async (): Promise<void> => {\n const saved = await latestEntry(PLAN_FLAVOR_SNAPSHOT);\n if (saved !== undefined && saved !== null && typeof saved === 'object' && 'flavor' in saved) {\n const candidate = String((saved as { flavor: unknown }).flavor);\n if (candidate === 'fable') flavor = 'normal';\n else if (candidate === 'normal' || candidate === 'debug' || candidate === 'code-review') flavor = candidate;\n }\n const evidence = await latestEntry(PLAN_DEBUG_EVIDENCE);\n if (evidence === undefined || evidence === null) return;\n try {\n debugEvidence = parseDebugEvidencePacket(evidence);\n } catch {\n // A packet written by an older shape must not stop the session from planning.\n debugEvidence = undefined;\n }\n };\n modeOwner = defineMinorMode({\n descriptor: {\n source: '@agimon-ai/po-plan',\n id: PLAN_MODE_ID,\n label: 'Plan',\n description: 'Read-only planning with normal, debug, and code review flavors.',\n order: 40,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Activate plan mode or switch its planning flavor.',\n contexts: ['headless'],\n parameters: [\n {\n name: 'flavor',\n label: 'Flavor',\n kind: 'enum',\n required: true,\n choices: [\n { value: 'normal', label: 'Normal' },\n { value: 'debug', label: 'Debug' },\n { value: 'code-review', label: 'Code Review' },\n ],\n },\n ],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Exit plan mode and restore the previous agent configuration.',\n contexts: ['headless'],\n parameters: [],\n },\n ],\n },\n state: () => modeState(),\n async handleAction(_runtime, actionId, argumentsValue, { signal }) {\n signal.throwIfAborted();\n if (actionId === 'activate') {\n const nextFlavor = argumentsValue.flavor;\n if (nextFlavor !== 'normal' && nextFlavor !== 'debug' && nextFlavor !== 'code-review')\n throw new Error('A valid plan flavor is required.');\n await selectPlan(true, nextFlavor);\n return { message: `Plan mode is active with the ${nextFlavor} flavor.` };\n }\n if (actionId === 'deactivate') {\n await selectPlan(false);\n return { message: 'Plan mode deactivated.' };\n }\n throw new Error(`Unknown plan mode action: ${actionId}`);\n },\n }).createOwner(undefined);\n return {\n services: [\n serverMinorModes([modeOwner]),\n serverPlanSubagentPolicy(host),\n (context) => {\n context.inject([PO_CONFIG_SERVICE], (child) => {\n const service = child.get(PO_CONFIG_SERVICE) as IPoConfigService;\n configService = service;\n return () => {\n if (configService === service) configService = undefined;\n };\n });\n context.inject([PLAN_ARTIFACT_SERVICE], (child) => {\n const storage = child.get(PLAN_ARTIFACT_SERVICE) as PlanArtifactStorage;\n artifactStorage = storage;\n return () => {\n if (artifactStorage === storage) artifactStorage = undefined;\n };\n });\n },\n ],\n resources: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: 'po-use-plan',\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-plan/SKILL.md'),\n },\n ],\n tools: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: RECORD_DEBUG_EVIDENCE_TOOL,\n label: 'Record Debug Evidence',\n description: 'Record bounded debug evidence as optional planning context.',\n parameters: {\n type: 'object',\n properties: {\n issue: { type: 'string' },\n expectedBehavior: { type: 'string' },\n reproductionAttempt: { type: 'string' },\n actualBehavior: { type: 'string' },\n logs: { type: 'array', items: { type: 'string' } },\n correlatedTraceEvidence: { type: 'array', items: { type: 'string' } },\n processOutput: { type: 'array', items: { type: 'string' } },\n browserConsoleEvidence: { type: 'array', items: { type: 'string' } },\n correlationIds: { type: 'array', items: { type: 'string' } },\n timestamps: { type: 'array', items: { type: 'string' } },\n verifiedFacts: { type: 'array', items: { type: 'string' } },\n hypotheses: { type: 'array', items: { type: 'string' } },\n unavailableEvidence: { type: 'array', items: { type: 'string' } },\n },\n required: ['issue'],\n additionalProperties: false,\n },\n executionMode: 'serial',\n async execute(_toolCallId, parameters) {\n try {\n const parsedEvidence = parseDebugEvidencePacket(parameters);\n await host.context.session.appendCustomEntry(PLAN_DEBUG_EVIDENCE, parsedEvidence);\n // Held in memory too: the debug prompt is rebuilt every turn from this packet.\n debugEvidence = parsedEvidence;\n return output({ recorded: true });\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: WRITE_PLAN_TOOL,\n label: 'Write Plan',\n mainAgentOnly: true,\n description: 'Save the supplied Markdown plan, or the plan already presented in the local session.',\n parameters: writePlanParameters,\n executionMode: 'serial',\n async execute(toolCallId, parameters, signal) {\n try {\n signal?.throwIfAborted();\n // Remote callers supply their own visible Markdown. Only local calls may use the journal.\n let content =\n typeof parameters === 'object' && parameters !== null && 'markdown' in parameters\n ? parameters.markdown\n : undefined;\n if (content !== undefined && typeof content !== 'string')\n throw new Error('Plan Markdown must be a string.');\n if (content === undefined)\n content = visiblePlanForToolCall(await host.context.session.entries(), toolCallId);\n if (content === undefined) {\n if (host.context.selection.state?.['minor-mode']?.includes(PO_VOICE_AUTO_MODE_ID))\n throw new Error('Supply Markdown to write_plan during autonomous Voice; UI input is unavailable.');\n const requested = await host.context.client.request(\n {\n kind: 'input',\n title: 'Implementation plan',\n multiline: true,\n },\n signal,\n );\n content = typeof requested === 'string' ? requested : '';\n }\n if (typeof content !== 'string' || !content.trim())\n throw new Error('No implementation plan content was supplied.');\n const directory = await plansDirectory();\n const title = planTitleOf(content);\n const writtenAt = new Date().toISOString();\n const filename = `${planTitleSlug(content)}-${Date.now()}.md`;\n const filePath = await writeNewPlanFile(directory, filename, `${content.trim()}\\n`);\n await host.context.session.appendCustomEntry(PLAN_DOCUMENT, {\n path: filePath,\n content: content.trim(),\n title,\n writtenAt,\n });\n announcePlanDocument(filePath, title, writtenAt);\n await selectPlan(true);\n const saved = { path: filePath, written: true };\n return { ...output(saved), structuredContent: saved };\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: COMPLETE_PLAN_TOOL,\n label: 'Complete Plan',\n mainAgentOnly: true,\n description:\n 'Request exit-or-continue approval in the local Po UI. Requires the user to interact there; this is not a ChatGPT approval dialog.',\n // No decision parameter: this server plugin has no narrated review to answer, so a model-supplied\n // decision would be the agent approving its own plan instead of the reader approving it.\n parameters: { type: 'object', properties: {}, additionalProperties: false },\n executionMode: 'serial',\n async execute(_toolCallId, _parameters, signal) {\n try {\n if (host.context.selection.state?.['minor-mode']?.includes(PO_VOICE_AUTO_MODE_ID))\n throw new Error(\n 'UI plan review is unavailable during autonomous Voice. Wait for explicit user direction.',\n );\n // The client answers with the option's `value`, so the decision travels with the\n // question instead of the server plugin having to recognise the label it rendered.\n const decision = await host.context.client.request(\n {\n kind: 'select',\n title: PLAN_REVIEW_TITLE,\n options: PLAN_REVIEW_CHOICES.map((choice) => ({ ...choice })),\n },\n signal,\n );\n // A dismissed or aborted prompt answers with nothing, and that is not approval.\n const exited = decision === EXIT_PLAN_DECISION;\n await host.context.session.appendCustomEntry('plan-review', {\n decision: exited ? EXIT_PLAN_DECISION : CONTINUE_PLAN_DECISION,\n });\n await selectPlan(!exited);\n return {\n content: [{ type: 'text', text: exited ? PLAN_EXIT_APPROVED_TEXT : PLAN_CONTINUE_TEXT }],\n details: { exited },\n };\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n ],\n hooks: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n event: 'before_agent_start',\n async handle(event) {\n const prompt = typeof event.systemPrompt === 'string' ? event.systemPrompt : '';\n const directory = await plansDirectory();\n const sections = [\n buildPlanModeBasePrompt(directory, PLAN_SERVER_CAPABILITIES),\n buildFlavorPlanningPrompt(flavor, directory, debugEvidence),\n ];\n const saved = await latestEntry(PLAN_DOCUMENT);\n if (saved !== undefined && saved !== null && typeof saved === 'object' && 'path' in saved) {\n const document = saved as { path: string; content?: string };\n // Read from disk rather than from what write_plan remembered: the plan is editable in\n // the cockpit, and a reader who corrected it expects that correction implemented.\n let content = document.content ?? '';\n try {\n content = await readPlanText(document.path);\n } catch {\n content = document.content ?? '';\n }\n if (content.trim()) sections.push(`[CURRENT PLAN]\\nSource: ${document.path}\\n\\n${content}`);\n }\n return { systemPrompt: `${prompt}\\n\\n${sections.join('\\n\\n')}`.trim() };\n },\n },\n {\n event: 'session_start',\n async handle() {\n await restorePlanState();\n // A plan written in an earlier session is still the session's plan, so\n // the dock has to hear about it again on every restart.\n const pointer = pointers.read(host.context.sessionId);\n if (pointer)\n host.context.client.setStatus(\n PLAN_STATUS_KEY,\n formatPlanStatus(pointer.title, planStampOf(pointer.writtenAt)),\n );\n // Restore a saved model override if Plan was not restored with the session.\n if (!selected()) await restoreModel();\n },\n },\n {\n // Older harness sessions persisted plan-mode context messages; keep them out of the model context.\n event: 'context',\n async handle(event) {\n if (!Array.isArray(event.messages)) return;\n return {\n messages: event.messages.filter(\n (message) => (message as { customType?: string }).customType !== PLAN_MODE_CONTEXT,\n ),\n };\n },\n },\n ],\n };\n}\n\nconst DEFAULT_PLAN_TITLE = 'implementation-plan';\nconst PLAN_TITLE_MAX_LENGTH = 64;\nconst DEBUG_EVIDENCE_MAX_BYTES = 32 * 1024;\nconst DEBUG_EVIDENCE_MAX_TEXT_BYTES = 4 * 1024;\nconst DEBUG_EVIDENCE_MAX_ITEMS = 32;\nexport const PLAN_MODE_CONTEXT = 'agent-harness-plan-mode-context';\nexport const PLAN_EXIT_APPROVED_TEXT =\n 'The user approved exiting plan mode. Full tool access is restored. Begin implementing the approved plan.';\nexport const PLAN_CONTINUE_TEXT = 'The user chose to continue planning. Remain read-only and refine the plan.';\n/** The plan's own heading, as the status line and the pointer record word it. */\nexport function planTitleOf(markdown: string): string {\n return markdown.match(/^#\\s+(.+?)\\s*$/m)?.[1] ?? DEFAULT_PLAN_TITLE;\n}\n\nexport function planTitleSlug(markdown: string): string {\n const heading = planTitleOf(markdown);\n return (\n heading\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, PLAN_TITLE_MAX_LENGTH) || DEFAULT_PLAN_TITLE\n );\n}\n\n/**\n * How the status line words when a plan was written. A malformed timestamp is\n * shown as it came rather than as an invalid date: the stamp's other job is to\n * change on a rewrite, and it can still do that.\n */\nexport function planStampOf(writtenAt: string): string {\n const at = new Date(writtenAt);\n return Number.isNaN(at.getTime()) ? writtenAt : at.toLocaleTimeString();\n}\n\nexport function visiblePlanForToolCall(entries: readonly unknown[], toolCallId: string): string | undefined {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (!entry || typeof entry !== 'object') continue;\n const candidate = entry as {\n type?: string;\n message?: { role?: string; content?: unknown };\n };\n if (candidate.type !== 'message' || candidate.message?.role !== 'assistant') continue;\n if (!Array.isArray(candidate.message.content)) continue;\n\n const toolIndex = candidate.message.content.findIndex((block) => {\n if (!block || typeof block !== 'object') return false;\n const content = block as { type?: string; id?: string; name?: string };\n return content.type === 'toolCall' && content.id === toolCallId && content.name === WRITE_PLAN_TOOL;\n });\n if (toolIndex < 0) continue;\n\n const plan = candidate.message.content\n .slice(0, toolIndex)\n .flatMap((block) => {\n if (!block || typeof block !== 'object') return [];\n const content = block as { type?: string; text?: unknown };\n return content.type === 'text' && typeof content.text === 'string' ? [content.text] : [];\n })\n .join('\\n\\n')\n .trim();\n return plan || undefined;\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nfunction boundedDebugText(value: unknown, field: string, required: boolean): string {\n if (!isString(value)) throw new Error(`${field} must be a string.`);\n const text = value.trim();\n if (required && !text) throw new Error(`${field} must not be empty.`);\n if (Buffer.byteLength(text, 'utf8') > DEBUG_EVIDENCE_MAX_TEXT_BYTES) {\n throw new Error(`${field} exceeds the bounded debug evidence limit.`);\n }\n return text;\n}\n\nfunction boundedDebugList(value: unknown, field: string): string[] {\n if (!Array.isArray(value) || value.length > DEBUG_EVIDENCE_MAX_ITEMS) {\n throw new Error(`${field} must be a bounded string array.`);\n }\n return value.map((item, index) => boundedDebugText(item, `${field}[${index}]`, false));\n}\n\nfunction optionalDebugText(value: unknown, field: string): string {\n return value === undefined ? '' : boundedDebugText(value, field, false);\n}\n\nfunction optionalDebugList(value: unknown, field: string): string[] {\n return value === undefined ? [] : boundedDebugList(value, field);\n}\n\nfunction assertExactObjectKeys(value: Record<string, unknown>, keys: readonly string[], field: string): void {\n const allowed = new Set(keys);\n const unexpected = Object.keys(value).find((key) => !allowed.has(key));\n if (unexpected) throw new Error(`${field} contains unsupported field '${unexpected}'.`);\n}\n\nexport function parseDebugEvidencePacket(value: unknown): DebugEvidencePacket {\n if (!isRecord(value)) throw new Error('Debug evidence must be an object.');\n assertExactObjectKeys(\n value,\n [\n 'issue',\n 'expectedBehavior',\n 'reproductionAttempt',\n 'actualBehavior',\n 'logs',\n 'correlatedTraceEvidence',\n 'processOutput',\n 'browserConsoleEvidence',\n 'correlationIds',\n 'timestamps',\n 'verifiedFacts',\n 'hypotheses',\n 'unavailableEvidence',\n ],\n 'Debug evidence',\n );\n const packet: DebugEvidencePacket = {\n issue: boundedDebugText(value.issue, 'issue', true),\n expectedBehavior: optionalDebugText(value.expectedBehavior, 'expectedBehavior'),\n reproductionAttempt: optionalDebugText(value.reproductionAttempt, 'reproductionAttempt'),\n actualBehavior: optionalDebugText(value.actualBehavior, 'actualBehavior'),\n logs: optionalDebugList(value.logs, 'logs'),\n correlatedTraceEvidence: optionalDebugList(value.correlatedTraceEvidence, 'correlatedTraceEvidence'),\n processOutput: optionalDebugList(value.processOutput, 'processOutput'),\n browserConsoleEvidence: optionalDebugList(value.browserConsoleEvidence, 'browserConsoleEvidence'),\n correlationIds: optionalDebugList(value.correlationIds, 'correlationIds'),\n timestamps: optionalDebugList(value.timestamps, 'timestamps'),\n verifiedFacts: optionalDebugList(value.verifiedFacts, 'verifiedFacts'),\n hypotheses: optionalDebugList(value.hypotheses, 'hypotheses'),\n unavailableEvidence: optionalDebugList(value.unavailableEvidence, 'unavailableEvidence'),\n };\n if (Buffer.byteLength(JSON.stringify(packet), 'utf8') > DEBUG_EVIDENCE_MAX_BYTES) {\n throw new Error('Debug evidence exceeds the bounded packet size.');\n }\n return packet;\n}\n","import { defineRoot, type RootDeclaration } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext, PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\n\nimport { mountMcpTools } from '../../../../services/mcpTools';\nimport { api } from '../../../../services/planApi';\nimport { createPlanServerSession } from '../../../../services/planServerSession';\n\nexport default defineRoot(\n ({ agent, host }: PoServerPluginContext): RootDeclaration<PoServerSessionPlugin, PoServerPluginContext> => {\n const value = {\n api: [api],\n ...(agent\n ? createPlanServerSession(agent, {\n homeDirectory: host.context.homeDirectory ?? host.context.environment?.HOME,\n })\n : {}),\n };\n return {\n value,\n services: [...(value.services ?? []), ...(value.tools?.length ? [mountMcpTools(value.tools)] : [])],\n };\n },\n);\n","import { defineRoute, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../../root.server').default>>['value'];\n\nexport default defineRoute((context: WithRoot<unknown, Root>) => context.root.api![0]!);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[0], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[2], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[1], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.resources?.[0], {\n cardinality: 'optional',\n});\n","import { defineToolRestriction } from '@agimon-ai/po-core/extensionFile';\nimport type { PoHeadlessToolRestriction } from '@agimon-ai/po-core/headless';\nimport { PO_VOICE_AUTO_MODE_ID } from '@agimon-ai/po-core/voiceTools';\n\nexport default defineToolRestriction({\n when: { state: { 'minor-mode': PO_VOICE_AUTO_MODE_ID } },\n excludedTools: ['complete_plan'],\n} satisfies PoHeadlessToolRestriction);\n","import { defineToolRestriction } from '@agimon-ai/po-core/extensionFile';\nimport type { PoHeadlessToolRestriction } from '@agimon-ai/po-core/headless';\n\nexport default defineToolRestriction({\n when: { state: { 'minor-mode': 'plan' } },\n excludedTools: ['edit', 'write'],\n} satisfies PoHeadlessToolRestriction);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[2], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[0], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[1], {\n cardinality: 'optional',\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\nimport { composeServerProviderOverrides } from '@agimon-ai/po-core/serverPlugin';\nimport { composeRootHooks, composeRootInjects } from '@agimon-ai/po-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/plans/route.server';\nimport hookBeforeAgentStart from '../src/extensions/workspaces/sessions/(backend)/hook/beforeAgentStart.server';\nimport hookContext from '../src/extensions/workspaces/sessions/(backend)/hook/context.server';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server';\nimport resourcePoUsePlan from '../src/extensions/workspaces/sessions/(backend)/resource/poUsePlan.server';\nimport toolRestrictionPlan from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/plan.server';\nimport toolRestrictionPlanReadOnly from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/planReadOnly.server';\nimport toolCompletePlan from '../src/extensions/workspaces/sessions/(backend)/tool/completePlan.server';\nimport toolRecordDebugEvidence from '../src/extensions/workspaces/sessions/(backend)/tool/recordDebugEvidence.server';\nimport toolWritePlan from '../src/extensions/workspaces/sessions/(backend)/tool/writePlan.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const serverPlugin = defineServerPlugin({\n name: '@agimon-ai/po-plan',\n providerOverrides: composeServerProviderOverrides(rootSession),\n injects: composeRootInjects({ session: [rootSession] }),\n session: async (context) => {\n const scopeSession = await context.scopeRoot('session', rootSession, context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get api(): PoServerSessionPlugin['api'] { return [at(apiRoute, contextSession)]; },\n get hooks(): PoServerSessionPlugin['hooks'] { return defined([via({ event: 'before_agent_start' }, at(hookBeforeAgentStart, contextSession)), via({ event: 'context' }, at(hookContext, contextSession)), via({ event: 'session_start' }, at(hookSessionStart, contextSession))]); },\n get resources(): PoServerSessionPlugin['resources'] { return defined([at(resourcePoUsePlan, contextSession)]); },\n get toolRestrictions(): PoServerSessionPlugin['toolRestrictions'] { return [at(toolRestrictionPlan, contextSession), at(toolRestrictionPlanReadOnly, contextSession)]; },\n get tools(): PoServerSessionPlugin['tools'] { return defined([via({ name: 'complete_plan' }, at(toolCompletePlan, contextSession)), via({ name: 'record_debug_evidence' }, at(toolRecordDebugEvidence, contextSession)), via({ name: 'write_plan' }, at(toolWritePlan, contextSession))]); },\n services: [...(scopeSession.services ?? [])],\n get activities(): PoServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default serverPlugin;\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { l as resolvePlanningPlansDirectory } from "../config-1hJV8Z69.mjs";
2
2
  import { i as buildFlavorPlanningPrompt, o as buildPlanModeBasePrompt } from "../prompts-C32Hrpem.mjs";
3
- import { Buffer } from "node:buffer";
3
+ import { Buffer as Buffer$1 } from "node:buffer";
4
4
  import { PO_CONFIG_SERVICE } from "@agimon-ai/po-core/config";
5
5
  import { composeServerProviderOverrides, defineServerPlugin, readPackageResource } from "@agimon-ai/po-core/serverPlugin";
6
6
  import { composeRootHooks, composeRootInjects, defineRoot, defineRoute, defineRoutedContribution, defineToolRestriction } from "@agimon-ai/po-core/extensionFile";
@@ -12,6 +12,7 @@ import os from "node:os";
12
12
  import path from "node:path";
13
13
  import { piAgentDirectory } from "@agimon-ai/po-core/piSettings";
14
14
  import fs$1 from "node:fs/promises";
15
+ import { fileMutationRunner, openGuardedFile } from "@agimon-ai/po-core/platform";
15
16
  import { PO_VOICE_AUTO_MODE_ID } from "@agimon-ai/po-core/voiceTools";
16
17
  import { defineMinorMode, serverMinorModes } from "@agimon-ai/po-minor-mode";
17
18
  //#region src/schemas/mcpTools.ts
@@ -202,17 +203,55 @@ async function writeNewPlanFile(directory, filename, content) {
202
203
  async function readPlanText(planPath) {
203
204
  return await fs$1.readFile(planPath, "utf8");
204
205
  }
205
- async function readPlanBytes(planPath) {
206
- return await fs$1.readFile(planPath);
206
+ /** The extra byte detects growth without ever reading or allocating the whole file. */
207
+ async function readBounded(handle, maxBytes) {
208
+ const stats = await handle.stat();
209
+ if (!stats.isFile()) throw new Error("The plan is not a regular file.");
210
+ const buffer = Buffer.alloc(maxBytes + 1);
211
+ if (stats.size > maxBytes) return buffer;
212
+ let offset = 0;
213
+ while (offset < buffer.length) {
214
+ const { bytesRead } = await handle.read(buffer, offset, buffer.length - offset, offset);
215
+ if (bytesRead === 0) break;
216
+ offset += bytesRead;
217
+ }
218
+ return buffer.subarray(0, offset);
207
219
  }
208
- async function overwritePlanFile(planPath, content) {
209
- const stats = await fs$1.lstat(planPath);
210
- if (!stats.isFile() || stats.nlink !== 1) return false;
211
- await fs$1.writeFile(planPath, content, {
212
- encoding: "utf8",
213
- mode: 384
220
+ async function readPlanBytes(planPath, maxBytes) {
221
+ const handle = await openGuardedFile(planPath);
222
+ try {
223
+ return await readBounded(handle, maxBytes);
224
+ } finally {
225
+ await handle.close();
226
+ }
227
+ }
228
+ /** Compare and write the same open inode. The queue protects cooperating API writers, not external processes. */
229
+ async function overwritePlanFile(planPath, content, expectedHash, maxBytes) {
230
+ const canonical = await fs$1.realpath(planPath);
231
+ return await fileMutationRunner.forKey(canonical)(async () => {
232
+ const handle = await openGuardedFile(planPath, { write: true });
233
+ try {
234
+ if (await fs$1.realpath(planPath) !== canonical) return void 0;
235
+ const raw = await readBounded(handle, maxBytes);
236
+ if (raw.length > maxBytes) return void 0;
237
+ const hash = createHash("sha256").update(raw.toString("utf8"), "utf8").digest("hex");
238
+ if (hash !== expectedHash) return {
239
+ written: false,
240
+ hash
241
+ };
242
+ const opened = await handle.stat();
243
+ const current = await fs$1.lstat(planPath);
244
+ if (!opened.isFile() || opened.nlink !== 1 || !current.isFile() || current.nlink !== 1 || opened.dev !== current.dev || opened.ino !== current.ino || await fs$1.realpath(planPath) !== canonical) return void 0;
245
+ await handle.writeFile(content, "utf8");
246
+ await handle.truncate(Buffer.byteLength(content, "utf8"));
247
+ return {
248
+ written: true,
249
+ hash: createHash("sha256").update(content, "utf8").digest("hex")
250
+ };
251
+ } finally {
252
+ await handle.close();
253
+ }
214
254
  });
215
- return true;
216
255
  }
217
256
  //#endregion
218
257
  //#region src/services/planApi/index.ts
@@ -246,7 +285,7 @@ function hashOf(content) {
246
285
  async function readPlan(planPath) {
247
286
  let raw;
248
287
  try {
249
- raw = await readPlanBytes(planPath);
288
+ raw = await readPlanBytes(planPath, MAX_PLAN_BYTES);
250
289
  } catch {
251
290
  return {
252
291
  content: "",
@@ -291,17 +330,21 @@ function createPlanApi(options = {}) {
291
330
  } catch {
292
331
  return context.json({ error: "The save body is not JSON." }, 400);
293
332
  }
294
- if (typeof request.content !== "string" || typeof request.expectedHash !== "string") return context.json({ error: "A save carries the content to write and the hash it was read at." }, 400);
333
+ if (typeof request !== "object" || request === null || Array.isArray(request) || !("content" in request) || typeof request.content !== "string" || !("expectedHash" in request) || typeof request.expectedHash !== "string") return context.json({ error: "A save carries the content to write and the hash it was read at." }, 400);
295
334
  const pointer = pointerFor();
296
335
  if (pointer === void 0) return context.json({ error: NO_PLAN }, 404);
297
- const current = await readPlan(pointer.path);
298
- if (current.unavailable) return context.json({ error: current.reason ?? NO_PLAN }, 409);
299
- if (current.hash !== request.expectedHash) return context.json({
300
- error: STALE_SAVE,
301
- hash: current.hash
302
- }, 409);
303
- if (!await overwritePlanFile(pointer.path, request.content)) return context.json({ error: NOT_A_FILE }, 409);
304
- return context.json({ hash: hashOf(request.content) });
336
+ if (Buffer.byteLength(request.content, "utf8") > 1048576) return context.json({ error: `The plan is larger than ${MAX_PLAN_BYTES} bytes.` }, 413);
337
+ try {
338
+ const saved = await overwritePlanFile(pointer.path, request.content, request.expectedHash, MAX_PLAN_BYTES);
339
+ if (saved === void 0) return context.json({ error: NOT_A_FILE }, 409);
340
+ if (!saved.written) return context.json({
341
+ error: STALE_SAVE,
342
+ hash: saved.hash
343
+ }, 409);
344
+ return context.json({ hash: saved.hash });
345
+ } catch {
346
+ return context.json({ error: NOT_A_FILE }, 409);
347
+ }
305
348
  });
306
349
  return app;
307
350
  }
@@ -880,7 +923,7 @@ function boundedDebugText(value, field, required) {
880
923
  if (!isString(value)) throw new Error(`${field} must be a string.`);
881
924
  const text = value.trim();
882
925
  if (required && !text) throw new Error(`${field} must not be empty.`);
883
- if (Buffer.byteLength(text, "utf8") > DEBUG_EVIDENCE_MAX_TEXT_BYTES) throw new Error(`${field} exceeds the bounded debug evidence limit.`);
926
+ if (Buffer$1.byteLength(text, "utf8") > DEBUG_EVIDENCE_MAX_TEXT_BYTES) throw new Error(`${field} exceeds the bounded debug evidence limit.`);
884
927
  return text;
885
928
  }
886
929
  function boundedDebugList(value, field) {
@@ -930,7 +973,7 @@ function parseDebugEvidencePacket(value) {
930
973
  hypotheses: optionalDebugList(value.hypotheses, "hypotheses"),
931
974
  unavailableEvidence: optionalDebugList(value.unavailableEvidence, "unavailableEvidence")
932
975
  };
933
- if (Buffer.byteLength(JSON.stringify(packet), "utf8") > DEBUG_EVIDENCE_MAX_BYTES) throw new Error("Debug evidence exceeds the bounded packet size.");
976
+ if (Buffer$1.byteLength(JSON.stringify(packet), "utf8") > DEBUG_EVIDENCE_MAX_BYTES) throw new Error("Debug evidence exceeds the bounded packet size.");
934
977
  return packet;
935
978
  }
936
979
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","names":["isRecord","fs","rootSession","apiRoute","hookBeforeAgentStart","hookContext","hookSessionStart","resourcePoUsePlan","toolRestrictionPlan","toolRestrictionPlanReadOnly","toolCompletePlan","toolRecordDebugEvidence","toolWritePlan"],"sources":["../../src/schemas/mcpTools.ts","../../src/services/mcpTools/index.ts","../../src/services/planPointer/index.ts","../../src/types/apiRoutes.ts","../../src/types/planApi.ts","../../src/services/planFiles/index.ts","../../src/services/planApi/index.ts","../../src/services/optionalTeamServices/index.ts","../../src/services/planServerSession/index.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/api/plans/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/beforeAgentStart.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/context.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poUsePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/plan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/planReadOnly.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/completePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/recordDebugEvidence.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/writePlan.server.ts","../../generated/server.ts"],"sourcesContent":["import { Type } from 'typebox';\n\nconst markdown = Type.String({ minLength: 1 });\n\nexport const remoteWritePlanParameters = Type.Object({ markdown }, { additionalProperties: false });\nexport const writePlanParameters = Type.Object({ markdown: Type.Optional(markdown) }, { additionalProperties: false });\n","import type { PoHeadlessTool } from '@agimon-ai/po-core/headless';\nimport type { PoMcpPluginContext } from '@agimon-ai/po-core/mcpFacet';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { remoteWritePlanParameters } from '../../schemas/mcpTools';\n\nexport const PLAN_MCP_TOOLS_SERVICE = 'po/plan-mcp-tools';\n\nconst MODE_ID = 'plan';\nconst MODE_LABEL = 'Plan';\n\nexport interface McpToolCatalog {\n get(name: string): PoHeadlessTool | undefined;\n names(): readonly string[];\n}\n\nexport function mountMcpTools(tools: readonly PoHeadlessTool[]) {\n return (context: Context): void => {\n context.plugin((providerContext) => {\n providerContext.provide(PLAN_MCP_TOOLS_SERVICE, {\n get: (name) => tools.find((tool) => tool.name === name),\n names: () => tools.map((tool) => tool.name),\n } satisfies McpToolCatalog);\n });\n };\n}\n\nexport function bindMcpTool(context: PoMcpPluginContext, name: string): PoHeadlessTool {\n const catalog = context.services.get<McpToolCatalog>(PLAN_MCP_TOOLS_SERVICE);\n const tool = catalog?.get(name);\n if (!tool || !catalog) throw new Error(`Plan tool is unavailable: ${name}`);\n const writesPlan = name === 'write_plan';\n return {\n ...tool,\n ...(writesPlan\n ? {\n description:\n 'Save the supplied Markdown plan in the bound session. Requires active Plan mode. Saving does not approve implementation.',\n parameters: remoteWritePlanParameters,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },\n }\n : {}),\n execute(toolCallId, parameters, signal, onUpdate) {\n const activeModes = context.selection.read().state?.['minor-mode'] ?? [];\n if (!activeModes.includes(MODE_ID)) {\n const inactiveTools = [...catalog.names()].sort().join(', ');\n throw new Error(`${MODE_LABEL} minor mode is inactive. Inactive ${MODE_LABEL} tools: ${inactiveTools}.`);\n }\n if (\n writesPlan &&\n (typeof parameters !== 'object' ||\n parameters === null ||\n !('markdown' in parameters) ||\n typeof parameters.markdown !== 'string' ||\n !parameters.markdown.trim())\n ) {\n throw new Error(\n 'Supply the complete visible plan in the markdown argument. Remote calls cannot read the ChatGPT transcript.',\n );\n }\n const executionSignal = AbortSignal.any([context.signal, signal ?? context.signal]);\n return tool.execute(toolCallId, parameters, executionSignal, onUpdate, context.execution);\n },\n };\n}\n","import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { piAgentDirectory } from '@agimon-ai/po-core/piSettings';\n\nimport type { PlanPointerRecord } from '../../types/planApi';\nimport type { PlanPointerPort } from '../../types/planPointer';\n\n/**\n * Record and read where write_plan left this session's plan file.\n *\n * Pi already gives every session an agent directory, so the records live under\n * it rather than in a second place a reader would have to know about. The\n * posture matches the plan file itself, 0700 on the directory and 0600 on the\n * record: a plan is a private working document, not something to leave\n * world-readable in a shared home.\n */\n\nconst POINTER_DIRECTORY = 'po-plan';\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst PRIVATE_FILE_MODE = 0o600;\n\nexport interface NodePlanPointerOptions {\n env?: NodeJS.ProcessEnv;\n homeDirectory?: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport class PlanPointerService implements PlanPointerPort {\n private readonly env: NodeJS.ProcessEnv;\n private readonly homeDirectory: string;\n\n constructor(options: NodePlanPointerOptions = {}) {\n this.env = options.env ?? {};\n this.homeDirectory = options.homeDirectory ?? os.homedir();\n }\n\n /** Where the records live; exposed so a test can look without guessing. */\n directory(): string {\n return path.join(piAgentDirectory(this.env, this.homeDirectory), POINTER_DIRECTORY);\n }\n\n /**\n * The record for one session. The id is hashed rather than used as written:\n * it reaches here from a host that may word it however it likes, and a\n * filename is not the place to find that out.\n */\n pathFor(sessionId: string): string {\n return path.join(this.directory(), `${this.hash(sessionId)}.json`);\n }\n\n read(sessionId: string): PlanPointerRecord | undefined {\n let raw: string;\n try {\n raw = fs.readFileSync(this.pathFor(sessionId), 'utf8');\n } catch {\n return undefined;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!isRecord(parsed)) return undefined;\n const { path: planPath, title, writtenAt, planId } = parsed;\n // A record half-written by an interrupted run reads as no plan at all,\n // which is a state the cockpit already handles.\n if (typeof planPath !== 'string' || !path.isAbsolute(planPath)) return undefined;\n if (typeof title !== 'string' || typeof writtenAt !== 'string') return undefined;\n return { path: planPath, title, writtenAt, ...(typeof planId === 'string' ? { planId } : {}) };\n }\n\n write(sessionId: string, record: PlanPointerRecord): void {\n fs.mkdirSync(this.directory(), { recursive: true, mode: PRIVATE_DIRECTORY_MODE });\n fs.writeFileSync(this.pathFor(sessionId), JSON.stringify(record), { mode: PRIVATE_FILE_MODE });\n }\n\n clear(sessionId: string): void {\n fs.rmSync(this.pathFor(sessionId), { force: true });\n }\n\n private hash(value: string): string {\n return createHash('sha256').update(value).digest('hex').slice(0, 16);\n }\n}\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { PlanDetailView, PlanSaveView } from './planApi';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/workspaces/sessions/(backend)/api/plans/`, so the mount is\n * stated once, by the folder that creates it. The paths used to be written\n * here as helpers, again in the contract, and again inside every URL the page\n * built, and the copies were free to disagree.\n *\n * This is the one file the routes, the Hono app and the browser all read, so a\n * path cannot move on one side alone.\n *\n * Neither route takes a query or a path parameter: a session has one current\n * plan, so `current` answers it and `save` takes the manual write back.\n */\nconst routes = {\n current: {\n method: 'GET',\n path: '/current',\n response: undefined as unknown as ApiResponseOf<PlanDetailView>,\n },\n save: {\n method: 'PUT',\n path: '/content',\n response: undefined as unknown as ApiResponseOf<PlanSaveView>,\n },\n} as const satisfies ApiRoutes;\n\nexport default routes;\n","/**\n * The wire vocabulary this package's API shares with whatever calls it.\n *\n * It lives under src/types because that is the one server root a browser\n * bundle may read: the routes answer with these shapes and the cockpit plugin\n * reads them, so neither half can drift from the other. The paths themselves\n * are not here; they are declared once in `./apiRoutes`, which the Hono app\n * and the generated client both read.\n *\n * Two routes, and neither takes a path. A session has one current plan, so\n * `current` answers it and `content` takes the manual save back; the file they\n * act on is the one write_plan recorded, never one the page named. That is\n * also why there is nothing to escape here: a reader cannot address a second\n * file through these URLs.\n */\n\n/** Where a host mounts this package's API; the segment after /api/plugins/. */\nexport const API_BASE_PATH = 'plans';\n\n/**\n * Footer status key the session publishes once a plan exists, which is what\n * makes the cockpit's activity group appear at all. It outlives plan mode: the\n * plan is most worth reading while the agent implements it.\n */\nexport const PLAN_STATUS_KEY = 'po-plan-document';\n\n/** The selector contract shared by complete_plan and its cockpit composer prompt. */\nexport const PLAN_REVIEW_TITLE = 'Plan complete. What would you like to do?';\nexport const EXIT_PLAN_MODE_CHOICE = 'Exit plan mode and start implementation';\nexport const CONTINUE_PLANNING_CHOICE = 'Continue planning';\nexport const EXIT_PLAN_DECISION = 'exit';\nexport const CONTINUE_PLAN_DECISION = 'continue';\n\n/**\n * The label the reader sees paired with the decision the tool acts on. A headless\n * client answers with `value`, so a server plugin never has to recognise the wording; Pi's\n * own `ui.select` carries labels only, so its half maps the label back itself.\n */\nexport const PLAN_REVIEW_CHOICES = [\n { label: EXIT_PLAN_MODE_CHOICE, value: EXIT_PLAN_DECISION },\n { label: CONTINUE_PLANNING_CHOICE, value: CONTINUE_PLAN_DECISION },\n] as const;\n\n/** The same options as bare labels, which is all Pi's select and the composer prompt need. */\nexport const PLAN_REVIEW_OPTIONS = PLAN_REVIEW_CHOICES.map((choice) => choice.label);\n\n/** Between the plan's title and the stamp that marks a rewrite. */\nconst STATUS_SEPARATOR = ' · ';\n\n/** Strips the colour a session may have themed a status with. */\nconst ANSI = /\u001b\\[[0-9;]*m/gu;\n\n/** The status line the session publishes; the stamp changes on every write. */\nexport function formatPlanStatus(title: string, stamp: string): string {\n return `${title}${STATUS_SEPARATOR}${stamp}`;\n}\n\n/** What a reader gets out of the status line. */\nexport interface PlanStatusView {\n title: string;\n /** When the plan was last written, as the session worded it; empty when it said nothing. */\n stamp: string;\n}\n\n/**\n * Reading the status line back. Statuses reach a plugin raw, so the colour a\n * session may have added comes off here. A title can itself contain the\n * separator, so the stamp is taken from the last one rather than the first.\n */\nexport function parsePlanStatus(raw: string | undefined): PlanStatusView | undefined {\n if (raw === undefined) return undefined;\n const text = raw.replace(ANSI, '').trim();\n if (text === '') return undefined;\n const cut = text.lastIndexOf(STATUS_SEPARATOR);\n if (cut === -1) return { title: text, stamp: '' };\n return { title: text.slice(0, cut).trim(), stamp: text.slice(cut + STATUS_SEPARATOR.length).trim() };\n}\n\n/**\n * What write_plan recorded about this session's plan.\n *\n * The absolute path is the point of it: the extension resolves the plans\n * directory against the harness root, which no other process knows, so it\n * writes down where the plan landed rather than leaving the API to derive a\n * location it would sometimes get wrong.\n */\nexport interface PlanPointerRecord {\n path: string;\n title: string;\n writtenAt: string;\n planId?: string;\n}\n\n/** The plan as it stands on disk right now, which is what the source view edits. */\nexport interface PlanDetailView {\n path: string;\n title: string;\n writtenAt: string;\n planId?: string;\n content: string;\n /** sha256 of the content; the token a save hands back to prove it is not stale. */\n hash: string;\n /** True when the plan is missing or past the size cap, so `content` is empty. */\n unavailable: boolean;\n reason?: string;\n}\n\n/** What the save route takes. */\nexport interface PlanSaveRequest {\n /** The hash the reader loaded; a mismatch means the plan moved underneath them. */\n expectedHash: string;\n content: string;\n}\n\n/** What the save route answers with. */\nexport interface PlanSaveView {\n hash: string;\n}\n\n/** What a route reports when it refuses; the page shows `error` verbatim. */\nexport interface PlanErrorView {\n error: string;\n /** On a stale save, the hash the plan actually has now. */\n hash?: string;\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport async function writeNewPlanFile(directory: string, filename: string, content: string): Promise<string> {\n await fs.mkdir(directory, { recursive: true, mode: 0o700 });\n const planPath = path.join(directory, filename);\n await fs.writeFile(planPath, content, { encoding: 'utf8', flag: 'wx', mode: 0o600 });\n return planPath;\n}\n\nexport async function readPlanText(planPath: string): Promise<string> {\n return await fs.readFile(planPath, 'utf8');\n}\n\nexport async function readPlanBytes(planPath: string): Promise<Buffer> {\n return await fs.readFile(planPath);\n}\n\nexport async function overwritePlanFile(planPath: string, content: string): Promise<boolean> {\n const stats = await fs.lstat(planPath);\n if (!stats.isFile() || stats.nlink !== 1) return false;\n await fs.writeFile(planPath, content, { encoding: 'utf8', mode: 0o600 });\n return true;\n}\n","import { createHash } from 'node:crypto';\n\nimport type { PoApi, PoApiContext, PoApiHandler } from '@agimon-ai/po-core/packageApi';\nimport { Hono } from 'hono';\n\nimport { PlanPointerService } from '../../services/planPointer';\nimport routes from '../../types/apiRoutes';\nimport { API_BASE_PATH, type PlanDetailView, type PlanSaveRequest, type PlanSaveView } from '../../types/planApi';\nimport type { PlanPointerPort } from '../../types/planPointer';\nimport { overwritePlanFile, readPlanBytes } from '../planFiles';\n\n/**\n * This package's HTTP surface: the session's current plan, and the manual save.\n *\n * Each path comes from the route table the browser reads, so a route the page\n * calls and the route this serves cannot be spelled apart. Both are relative\n * to the mount its host gives it, so nothing here repeats where it was mounted. The host is one session's own server, which is what\n * makes the session id available without the page supplying it.\n *\n * Neither route takes a path. A session has exactly one current plan, and the\n * file both routes act on is the one the pointer names, so a page can address\n * the plan and nothing else; there is no traversal question to answer because\n * there is no path to traverse.\n *\n * The save refuses unless the reader proves they were looking at the content\n * that is still on disk. The agent may rewrite the plan while a tab is open,\n * and silently discarding whichever side finished second is the one outcome\n * worth ruling out.\n */\n\n/** Past this, the plan is reported rather than carried. */\nexport const MAX_PLAN_BYTES = 1024 * 1024;\n\nconst NO_PLAN = 'This session has not written a plan yet.';\nconst STALE_SAVE = 'The plan changed since it was opened.';\nconst NOT_A_FILE = 'The plan file is no longer a regular file, so it was not written.';\n\nexport interface PlanApiOptions {\n /** The session these routes answer for; absent when the host is the hub. */\n sessionId?: string;\n pointers?: PlanPointerPort;\n}\n\nfunction hashOf(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/** Reads the plan as the source view will show it, or says why it cannot. */\nasync function readPlan(\n planPath: string,\n): Promise<Pick<PlanDetailView, 'content' | 'hash' | 'unavailable' | 'reason'>> {\n let raw: Buffer;\n try {\n raw = await readPlanBytes(planPath);\n } catch {\n return { content: '', hash: '', unavailable: true, reason: 'the plan file no longer exists' };\n }\n if (raw.byteLength > MAX_PLAN_BYTES) {\n return { content: '', hash: '', unavailable: true, reason: `the plan is larger than ${MAX_PLAN_BYTES} bytes` };\n }\n const content = raw.toString('utf8');\n return { content, hash: hashOf(content), unavailable: false };\n}\n\nexport function createPlanApi(options: PlanApiOptions = {}): Hono {\n const app = new Hono();\n const pointers = options.pointers ?? new PlanPointerService();\n const pointerFor = (): ReturnType<PlanPointerPort['read']> =>\n options.sessionId === undefined ? undefined : pointers.read(options.sessionId);\n\n app.get(routes.current.path, async (context) => {\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n const view: PlanDetailView = {\n path: pointer.path,\n title: pointer.title,\n writtenAt: pointer.writtenAt,\n ...(pointer.planId === undefined ? {} : { planId: pointer.planId }),\n ...(await readPlan(pointer.path)),\n };\n return context.json(view);\n });\n\n app.put(routes.save.path, async (context) => {\n let request: PlanSaveRequest;\n try {\n request = (await context.req.json()) as PlanSaveRequest;\n } catch {\n return context.json({ error: 'The save body is not JSON.' }, 400);\n }\n if (typeof request.content !== 'string' || typeof request.expectedHash !== 'string') {\n return context.json({ error: 'A save carries the content to write and the hash it was read at.' }, 400);\n }\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n\n const current = await readPlan(pointer.path);\n if (current.unavailable) return context.json({ error: current.reason ?? NO_PLAN }, 409);\n if (current.hash !== request.expectedHash) {\n return context.json({ error: STALE_SAVE, hash: current.hash }, 409);\n }\n // Refuse symlinks and multiply linked files, whatever the pointer still says.\n if (!(await overwritePlanFile(pointer.path, request.content))) return context.json({ error: NOT_A_FILE }, 409);\n return context.json({ hash: hashOf(request.content) } satisfies PlanSaveView);\n });\n\n return app;\n}\n\n/** The named export a host imports from this package's built entry. */\nexport const api: PoApi = {\n basePath: API_BASE_PATH,\n start(context: PoApiContext): PoApiHandler {\n const app = createPlanApi({\n ...(context.sessionId === undefined ? {} : { sessionId: context.sessionId }),\n pointers: new PlanPointerService({\n env: context.environment ?? {},\n homeDirectory: context.homeDirectory,\n }),\n });\n return {\n fetch: (request) => app.fetch(request),\n // Nothing outlives a request here; an API that starts a watch or a timer\n // tears it down in this callback.\n close: () => undefined,\n };\n },\n};\n","import type { Context } from '@deepseek-ai/cordis';\n\nimport { FABLE_PLAN_REQUESTER, type FablePlanRequest, type FablePlanResult } from '../fableFlow';\n\nexport const PO_FABLE_PLAN_SERVICE = 'po/fable-plan';\nexport const PO_SUBAGENT_POLICY_SERVICE = 'po/subagent-policy';\n\nexport interface PoFablePlanService {\n start(request: FablePlanRequest, signal: AbortSignal): Promise<FablePlanResult>;\n cancel(request: { requester: typeof FABLE_PLAN_REQUESTER; operationId: string; reason: string }): void;\n}\n\nexport interface SubagentPolicy {\n owner: string;\n allowedTools?: string[];\n requiredTools?: string[];\n allowMcpTools?: boolean;\n allowedExternalProfiles?: string[];\n denyExtensions?: boolean;\n}\n\nexport interface SubagentPolicyHandle {\n update(policy: SubagentPolicy): void;\n dispose(): void;\n}\n\nexport interface PoSubagentPolicyService {\n register(policy: SubagentPolicy): SubagentPolicyHandle;\n}\n\ntype StructuralServiceContext = {\n get(name: string): unknown;\n};\n\nexport function readPoFablePlanService(ctx: Context): PoFablePlanService | undefined {\n return (ctx as unknown as StructuralServiceContext).get(PO_FABLE_PLAN_SERVICE) as PoFablePlanService | undefined;\n}\n\nexport function readPoSubagentPolicyService(ctx: Context): PoSubagentPolicyService | undefined {\n return (ctx as unknown as StructuralServiceContext).get(PO_SUBAGENT_POLICY_SERVICE) as\n | PoSubagentPolicyService\n | undefined;\n}\n","import { Buffer } from 'node:buffer';\nimport path from 'node:path';\n\nimport type { IPoConfigService } from '@agimon-ai/po-config';\nimport { PO_CONFIG_SERVICE } from '@agimon-ai/po-core/config';\nimport { type PoHeadlessHostService, type PoHeadlessModelSettings } from '@agimon-ai/po-core/headless';\nimport { type PoHeadlessToolResult } from '@agimon-ai/po-core/headless';\nimport { readPackageResource, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\nimport { PO_VOICE_AUTO_MODE_ID } from '@agimon-ai/po-core/voiceTools';\nimport { serverMinorModes } from '@agimon-ai/po-minor-mode';\nimport { defineMinorMode, type MinorModeOwner, type MinorModeState } from '@agimon-ai/po-minor-mode';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { writePlanParameters } from '../../schemas/mcpTools';\nimport { resolvePlanningPlansDirectory } from '../../schemas/plan/config';\nimport {\n buildFlavorPlanningPrompt,\n buildPlanModeBasePrompt,\n type DebugEvidencePacket,\n type PlanHostCapabilities,\n type PlanningFlavor,\n} from '../../services/prompts';\nimport {\n CONTINUE_PLAN_DECISION,\n EXIT_PLAN_DECISION,\n PLAN_REVIEW_CHOICES,\n PLAN_REVIEW_TITLE,\n PLAN_STATUS_KEY,\n formatPlanStatus,\n} from '../../types/planApi';\nimport {\n PO_SUBAGENT_POLICY_SERVICE,\n readPoSubagentPolicyService,\n type SubagentPolicy,\n type SubagentPolicyHandle,\n} from '../optionalTeamServices';\nimport { readPlanText, writeNewPlanFile } from '../planFiles';\nimport { PlanPointerService } from '../planPointer';\n\nconst PLAN_ARTIFACT_SERVICE = 'po/artifacts';\ninterface PlanArtifactStorage {\n rootForSession(\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>>,\n ): Promise<string | undefined>;\n}\n\nconst RECORD_DEBUG_EVIDENCE_TOOL = 'record_debug_evidence';\nconst WRITE_PLAN_TOOL = 'write_plan';\nconst COMPLETE_PLAN_TOOL = 'complete_plan';\nconst PLAN_MODE_ID = 'plan';\nconst PLAN_MODEL_SNAPSHOT = 'plan-server-model-snapshot';\nconst PLAN_FLAVOR_SNAPSHOT = 'plan-server-flavor';\nconst PLAN_DEBUG_EVIDENCE = 'plan-debug-evidence';\nconst PLAN_DOCUMENT = 'plan-document';\n/** This host supports UI review without narrated decisions. */\nexport const PLAN_SERVER_CAPABILITIES: PlanHostCapabilities = {\n completePlanTakesDecision: false,\n narratesReview: false,\n fableAvailable: false,\n};\nconst PLAN_SUBAGENT_POLICY_OWNER = '@agimon-ai/po-plan';\n// Subagents keep every tool but `edit` and `write`, which the plan-mode restriction already withdraws from the\n// planner and, through it, from its subagents. An external runtime cannot be held to that, so none is allowed.\nconst PLAN_SUBAGENT_POLICY: SubagentPolicy = {\n owner: PLAN_SUBAGENT_POLICY_OWNER,\n allowMcpTools: true,\n allowedExternalProfiles: [],\n denyExtensions: false,\n};\n\nfunction serverPlanSubagentPolicy(host: PoHeadlessHostService): (context: Context) => void {\n return (context) => {\n context.inject([PO_SUBAGENT_POLICY_SERVICE], (child) => {\n const service = readPoSubagentPolicyService(child);\n if (!service) return undefined;\n let handle: SubagentPolicyHandle | undefined;\n const sync = (): void => {\n if (modeSelected(host)) {\n if (handle) handle.update(PLAN_SUBAGENT_POLICY);\n else handle = service.register(PLAN_SUBAGENT_POLICY);\n } else {\n handle?.dispose();\n handle = undefined;\n }\n };\n sync();\n child.effect(() => host.subscribeSelection(sync));\n return () => handle?.dispose();\n });\n };\n}\n\nfunction modeSelected(host: PoHeadlessHostService): boolean {\n return (host.context.selection.state?.['minor-mode'] ?? []).includes(PLAN_MODE_ID);\n}\n\nfunction output(value: unknown, isError = false): PoHeadlessToolResult {\n return {\n content: [{ type: 'text', text: typeof value === 'string' ? value : JSON.stringify(value, null, 2) }],\n details: value,\n ...(isError ? { isError: true } : {}),\n };\n}\n\nexport function createPlanServerSession(\n host: PoHeadlessHostService,\n options: { homeDirectory?: string },\n): Omit<PoServerSessionPlugin, 'tools'> & { tools: Parameters<PoHeadlessHostService['registerTool']>[0][] } {\n let flavor: PlanningFlavor = 'normal';\n let debugEvidence: DebugEvidencePacket | undefined;\n let modeOwner: MinorModeOwner | undefined;\n const selected = (): boolean => modeSelected(host);\n let configService: IPoConfigService | undefined;\n let artifactStorage: PlanArtifactStorage | undefined;\n const planningConfig = () => configService?.getSnapshot().settings.modes?.planning;\n // One resolution for both the prompt and write_plan.\n const plansDirectory = async (): Promise<string> => {\n const root = await artifactStorage?.rootForSession(host.context.sessionId, host.context.environment);\n if (root !== undefined) return path.join(root, 'plans');\n if (options.homeDirectory === undefined) throw new Error('Po needs a home directory to choose the plans folder.');\n return resolvePlanningPlansDirectory(\n planningConfig()?.plansDirectory,\n host.context.repoRoot,\n options.homeDirectory,\n );\n };\n const pointers = new PlanPointerService({\n env: host.context.environment,\n homeDirectory: options.homeDirectory,\n });\n /**\n * The activity group's line, and the pointer its panel reads.\n *\n * A cockpit drives this server plugin and never the Pi runtime, so both were written\n * only on the Pi side: the group never appeared, and when it did its panel\n * had no pointer to answer from.\n */\n const announcePlanDocument = (filePath: string, title: string, writtenAt: string): void => {\n try {\n pointers.write(host.context.sessionId, { path: filePath, title, writtenAt });\n } catch {\n // The plan is on disk either way. Losing the cockpit's view of it is not\n // a reason to fail the write that produced it.\n }\n host.context.client.setStatus(PLAN_STATUS_KEY, formatPlanStatus(title, planStampOf(writtenAt)));\n };\n const modeState = (): MinorModeState => {\n const active = selected();\n return {\n activation: active ? 'active' : 'inactive',\n condition: 'ready',\n ...(active ? { detail: `${flavor} - read only`, modelContextVariant: flavor } : {}),\n actions: [\n {\n id: 'activate',\n enabled: true,\n },\n {\n id: 'deactivate',\n enabled: active,\n ...(active ? {} : { disabledReason: 'Plan mode is inactive.' }),\n },\n ],\n };\n };\n const publishMode = (): void => modeOwner?.publish();\n const restoreModel = async (): Promise<void> => {\n const session = host.context.session;\n const entries = await session.entries({ type: 'custom', customType: PLAN_MODEL_SNAPSHOT, limit: 1 });\n const data = entries[0]?.data;\n if (data === undefined || data === null) return;\n if (\n typeof data !== 'object' ||\n !('thinkingLevel' in data) ||\n !['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'].includes(String(data.thinkingLevel))\n )\n throw new Error('The saved planning model settings are invalid.');\n if (!session.setModelSettings) throw new Error('This session cannot restore its model settings.');\n await session.setModelSettings(data as PoHeadlessModelSettings);\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, null);\n };\n const selectPlan = async (enabled: boolean, nextFlavor = flavor): Promise<void> => {\n const wasEnabled = selected();\n const session = host.context.session;\n if (enabled && !wasEnabled) {\n const config = planningConfig()?.main;\n if (config?.model || config?.thinking) {\n if (!session.readModelSettings || !session.setModelSettings)\n throw new Error('This session cannot apply planning model settings.');\n const previous = await session.readModelSettings();\n const settings: Partial<PoHeadlessModelSettings> = {};\n if (config.model) {\n const separator = config.model.indexOf('/');\n const provider = separator > 0 ? config.model.slice(0, separator) : previous.model?.provider;\n if (!provider) throw new Error('The planning model needs a provider.');\n settings.model = { provider, id: separator > 0 ? config.model.slice(separator + 1) : config.model };\n }\n if (config.thinking) settings.thinkingLevel = config.thinking;\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, previous);\n try {\n await session.setModelSettings(settings);\n } catch (error) {\n await session.setModelSettings(previous);\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, null);\n throw error;\n }\n }\n } else if (!enabled && wasEnabled) {\n await restoreModel();\n }\n const modes = (host.context.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== PLAN_MODE_ID);\n await host.changeSelection({\n axis: 'state',\n key: 'minor-mode',\n values: enabled ? [...modes, PLAN_MODE_ID] : modes,\n });\n flavor = nextFlavor;\n // Persisted because the minor mode survives a server restart while this local does not, and\n // the prompt is built from it. Without this a restored debug session silently plans as normal.\n await session.appendCustomEntry(PLAN_FLAVOR_SNAPSHOT, enabled ? { flavor } : null);\n publishMode();\n };\n\n /** Newest value for a custom entry type, or undefined when none was recorded. */\n const latestEntry = async (customType: string): Promise<unknown> => {\n const entries = await host.context.session.entries({ type: 'custom', customType, limit: 1 });\n return entries[0]?.data ?? undefined;\n };\n\n const restorePlanState = async (): Promise<void> => {\n const saved = await latestEntry(PLAN_FLAVOR_SNAPSHOT);\n if (saved !== undefined && saved !== null && typeof saved === 'object' && 'flavor' in saved) {\n const candidate = String((saved as { flavor: unknown }).flavor);\n if (candidate === 'fable') flavor = 'normal';\n else if (candidate === 'normal' || candidate === 'debug' || candidate === 'code-review') flavor = candidate;\n }\n const evidence = await latestEntry(PLAN_DEBUG_EVIDENCE);\n if (evidence === undefined || evidence === null) return;\n try {\n debugEvidence = parseDebugEvidencePacket(evidence);\n } catch {\n // A packet written by an older shape must not stop the session from planning.\n debugEvidence = undefined;\n }\n };\n modeOwner = defineMinorMode({\n descriptor: {\n source: '@agimon-ai/po-plan',\n id: PLAN_MODE_ID,\n label: 'Plan',\n description: 'Read-only planning with normal, debug, and code review flavors.',\n order: 40,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Activate plan mode or switch its planning flavor.',\n contexts: ['headless'],\n parameters: [\n {\n name: 'flavor',\n label: 'Flavor',\n kind: 'enum',\n required: true,\n choices: [\n { value: 'normal', label: 'Normal' },\n { value: 'debug', label: 'Debug' },\n { value: 'code-review', label: 'Code Review' },\n ],\n },\n ],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Exit plan mode and restore the previous agent configuration.',\n contexts: ['headless'],\n parameters: [],\n },\n ],\n },\n state: () => modeState(),\n async handleAction(_runtime, actionId, argumentsValue, { signal }) {\n signal.throwIfAborted();\n if (actionId === 'activate') {\n const nextFlavor = argumentsValue.flavor;\n if (nextFlavor !== 'normal' && nextFlavor !== 'debug' && nextFlavor !== 'code-review')\n throw new Error('A valid plan flavor is required.');\n await selectPlan(true, nextFlavor);\n return { message: `Plan mode is active with the ${nextFlavor} flavor.` };\n }\n if (actionId === 'deactivate') {\n await selectPlan(false);\n return { message: 'Plan mode deactivated.' };\n }\n throw new Error(`Unknown plan mode action: ${actionId}`);\n },\n }).createOwner(undefined);\n return {\n services: [\n serverMinorModes([modeOwner]),\n serverPlanSubagentPolicy(host),\n (context) => {\n context.inject([PO_CONFIG_SERVICE], (child) => {\n const service = child.get(PO_CONFIG_SERVICE) as IPoConfigService;\n configService = service;\n return () => {\n if (configService === service) configService = undefined;\n };\n });\n context.inject([PLAN_ARTIFACT_SERVICE], (child) => {\n const storage = child.get(PLAN_ARTIFACT_SERVICE) as PlanArtifactStorage;\n artifactStorage = storage;\n return () => {\n if (artifactStorage === storage) artifactStorage = undefined;\n };\n });\n },\n ],\n resources: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: 'po-use-plan',\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-plan/SKILL.md'),\n },\n ],\n tools: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: RECORD_DEBUG_EVIDENCE_TOOL,\n label: 'Record Debug Evidence',\n description: 'Record bounded debug evidence as optional planning context.',\n parameters: {\n type: 'object',\n properties: {\n issue: { type: 'string' },\n expectedBehavior: { type: 'string' },\n reproductionAttempt: { type: 'string' },\n actualBehavior: { type: 'string' },\n logs: { type: 'array', items: { type: 'string' } },\n correlatedTraceEvidence: { type: 'array', items: { type: 'string' } },\n processOutput: { type: 'array', items: { type: 'string' } },\n browserConsoleEvidence: { type: 'array', items: { type: 'string' } },\n correlationIds: { type: 'array', items: { type: 'string' } },\n timestamps: { type: 'array', items: { type: 'string' } },\n verifiedFacts: { type: 'array', items: { type: 'string' } },\n hypotheses: { type: 'array', items: { type: 'string' } },\n unavailableEvidence: { type: 'array', items: { type: 'string' } },\n },\n required: ['issue'],\n additionalProperties: false,\n },\n executionMode: 'serial',\n async execute(_toolCallId, parameters) {\n try {\n const parsedEvidence = parseDebugEvidencePacket(parameters);\n await host.context.session.appendCustomEntry(PLAN_DEBUG_EVIDENCE, parsedEvidence);\n // Held in memory too: the debug prompt is rebuilt every turn from this packet.\n debugEvidence = parsedEvidence;\n return output({ recorded: true });\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: WRITE_PLAN_TOOL,\n label: 'Write Plan',\n mainAgentOnly: true,\n description: 'Save the supplied Markdown plan, or the plan already presented in the local session.',\n parameters: writePlanParameters,\n executionMode: 'serial',\n async execute(toolCallId, parameters, signal) {\n try {\n signal?.throwIfAborted();\n // Remote callers supply their own visible Markdown. Only local calls may use the journal.\n let content =\n typeof parameters === 'object' && parameters !== null && 'markdown' in parameters\n ? parameters.markdown\n : undefined;\n if (content !== undefined && typeof content !== 'string')\n throw new Error('Plan Markdown must be a string.');\n if (content === undefined)\n content = visiblePlanForToolCall(await host.context.session.entries(), toolCallId);\n if (content === undefined) {\n if (host.context.selection.state?.['minor-mode']?.includes(PO_VOICE_AUTO_MODE_ID))\n throw new Error('Supply Markdown to write_plan during autonomous Voice; UI input is unavailable.');\n const requested = await host.context.client.request(\n {\n kind: 'input',\n title: 'Implementation plan',\n multiline: true,\n },\n signal,\n );\n content = typeof requested === 'string' ? requested : '';\n }\n if (typeof content !== 'string' || !content.trim())\n throw new Error('No implementation plan content was supplied.');\n const directory = await plansDirectory();\n const title = planTitleOf(content);\n const writtenAt = new Date().toISOString();\n const filename = `${planTitleSlug(content)}-${Date.now()}.md`;\n const filePath = await writeNewPlanFile(directory, filename, `${content.trim()}\\n`);\n await host.context.session.appendCustomEntry(PLAN_DOCUMENT, {\n path: filePath,\n content: content.trim(),\n title,\n writtenAt,\n });\n announcePlanDocument(filePath, title, writtenAt);\n await selectPlan(true);\n const saved = { path: filePath, written: true };\n return { ...output(saved), structuredContent: saved };\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: COMPLETE_PLAN_TOOL,\n label: 'Complete Plan',\n mainAgentOnly: true,\n description:\n 'Request exit-or-continue approval in the local Po UI. Requires the user to interact there; this is not a ChatGPT approval dialog.',\n // No decision parameter: this server plugin has no narrated review to answer, so a model-supplied\n // decision would be the agent approving its own plan instead of the reader approving it.\n parameters: { type: 'object', properties: {}, additionalProperties: false },\n executionMode: 'serial',\n async execute(_toolCallId, _parameters, signal) {\n try {\n if (host.context.selection.state?.['minor-mode']?.includes(PO_VOICE_AUTO_MODE_ID))\n throw new Error(\n 'UI plan review is unavailable during autonomous Voice. Wait for explicit user direction.',\n );\n // The client answers with the option's `value`, so the decision travels with the\n // question instead of the server plugin having to recognise the label it rendered.\n const decision = await host.context.client.request(\n {\n kind: 'select',\n title: PLAN_REVIEW_TITLE,\n options: PLAN_REVIEW_CHOICES.map((choice) => ({ ...choice })),\n },\n signal,\n );\n // A dismissed or aborted prompt answers with nothing, and that is not approval.\n const exited = decision === EXIT_PLAN_DECISION;\n await host.context.session.appendCustomEntry('plan-review', {\n decision: exited ? EXIT_PLAN_DECISION : CONTINUE_PLAN_DECISION,\n });\n await selectPlan(!exited);\n return {\n content: [{ type: 'text', text: exited ? PLAN_EXIT_APPROVED_TEXT : PLAN_CONTINUE_TEXT }],\n details: { exited },\n };\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n ],\n hooks: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n event: 'before_agent_start',\n async handle(event) {\n const prompt = typeof event.systemPrompt === 'string' ? event.systemPrompt : '';\n const directory = await plansDirectory();\n const sections = [\n buildPlanModeBasePrompt(directory, PLAN_SERVER_CAPABILITIES),\n buildFlavorPlanningPrompt(flavor, directory, debugEvidence),\n ];\n const saved = await latestEntry(PLAN_DOCUMENT);\n if (saved !== undefined && saved !== null && typeof saved === 'object' && 'path' in saved) {\n const document = saved as { path: string; content?: string };\n // Read from disk rather than from what write_plan remembered: the plan is editable in\n // the cockpit, and a reader who corrected it expects that correction implemented.\n let content = document.content ?? '';\n try {\n content = await readPlanText(document.path);\n } catch {\n content = document.content ?? '';\n }\n if (content.trim()) sections.push(`[CURRENT PLAN]\\nSource: ${document.path}\\n\\n${content}`);\n }\n return { systemPrompt: `${prompt}\\n\\n${sections.join('\\n\\n')}`.trim() };\n },\n },\n {\n event: 'session_start',\n async handle() {\n await restorePlanState();\n // A plan written in an earlier session is still the session's plan, so\n // the dock has to hear about it again on every restart.\n const pointer = pointers.read(host.context.sessionId);\n if (pointer)\n host.context.client.setStatus(\n PLAN_STATUS_KEY,\n formatPlanStatus(pointer.title, planStampOf(pointer.writtenAt)),\n );\n // Restore a saved model override if Plan was not restored with the session.\n if (!selected()) await restoreModel();\n },\n },\n {\n // Older harness sessions persisted plan-mode context messages; keep them out of the model context.\n event: 'context',\n async handle(event) {\n if (!Array.isArray(event.messages)) return;\n return {\n messages: event.messages.filter(\n (message) => (message as { customType?: string }).customType !== PLAN_MODE_CONTEXT,\n ),\n };\n },\n },\n ],\n };\n}\n\nconst DEFAULT_PLAN_TITLE = 'implementation-plan';\nconst PLAN_TITLE_MAX_LENGTH = 64;\nconst DEBUG_EVIDENCE_MAX_BYTES = 32 * 1024;\nconst DEBUG_EVIDENCE_MAX_TEXT_BYTES = 4 * 1024;\nconst DEBUG_EVIDENCE_MAX_ITEMS = 32;\nexport const PLAN_MODE_CONTEXT = 'agent-harness-plan-mode-context';\nexport const PLAN_EXIT_APPROVED_TEXT =\n 'The user approved exiting plan mode. Full tool access is restored. Begin implementing the approved plan.';\nexport const PLAN_CONTINUE_TEXT = 'The user chose to continue planning. Remain read-only and refine the plan.';\n/** The plan's own heading, as the status line and the pointer record word it. */\nexport function planTitleOf(markdown: string): string {\n return markdown.match(/^#\\s+(.+?)\\s*$/m)?.[1] ?? DEFAULT_PLAN_TITLE;\n}\n\nexport function planTitleSlug(markdown: string): string {\n const heading = planTitleOf(markdown);\n return (\n heading\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, PLAN_TITLE_MAX_LENGTH) || DEFAULT_PLAN_TITLE\n );\n}\n\n/**\n * How the status line words when a plan was written. A malformed timestamp is\n * shown as it came rather than as an invalid date: the stamp's other job is to\n * change on a rewrite, and it can still do that.\n */\nexport function planStampOf(writtenAt: string): string {\n const at = new Date(writtenAt);\n return Number.isNaN(at.getTime()) ? writtenAt : at.toLocaleTimeString();\n}\n\nexport function visiblePlanForToolCall(entries: readonly unknown[], toolCallId: string): string | undefined {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (!entry || typeof entry !== 'object') continue;\n const candidate = entry as {\n type?: string;\n message?: { role?: string; content?: unknown };\n };\n if (candidate.type !== 'message' || candidate.message?.role !== 'assistant') continue;\n if (!Array.isArray(candidate.message.content)) continue;\n\n const toolIndex = candidate.message.content.findIndex((block) => {\n if (!block || typeof block !== 'object') return false;\n const content = block as { type?: string; id?: string; name?: string };\n return content.type === 'toolCall' && content.id === toolCallId && content.name === WRITE_PLAN_TOOL;\n });\n if (toolIndex < 0) continue;\n\n const plan = candidate.message.content\n .slice(0, toolIndex)\n .flatMap((block) => {\n if (!block || typeof block !== 'object') return [];\n const content = block as { type?: string; text?: unknown };\n return content.type === 'text' && typeof content.text === 'string' ? [content.text] : [];\n })\n .join('\\n\\n')\n .trim();\n return plan || undefined;\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nfunction boundedDebugText(value: unknown, field: string, required: boolean): string {\n if (!isString(value)) throw new Error(`${field} must be a string.`);\n const text = value.trim();\n if (required && !text) throw new Error(`${field} must not be empty.`);\n if (Buffer.byteLength(text, 'utf8') > DEBUG_EVIDENCE_MAX_TEXT_BYTES) {\n throw new Error(`${field} exceeds the bounded debug evidence limit.`);\n }\n return text;\n}\n\nfunction boundedDebugList(value: unknown, field: string): string[] {\n if (!Array.isArray(value) || value.length > DEBUG_EVIDENCE_MAX_ITEMS) {\n throw new Error(`${field} must be a bounded string array.`);\n }\n return value.map((item, index) => boundedDebugText(item, `${field}[${index}]`, false));\n}\n\nfunction optionalDebugText(value: unknown, field: string): string {\n return value === undefined ? '' : boundedDebugText(value, field, false);\n}\n\nfunction optionalDebugList(value: unknown, field: string): string[] {\n return value === undefined ? [] : boundedDebugList(value, field);\n}\n\nfunction assertExactObjectKeys(value: Record<string, unknown>, keys: readonly string[], field: string): void {\n const allowed = new Set(keys);\n const unexpected = Object.keys(value).find((key) => !allowed.has(key));\n if (unexpected) throw new Error(`${field} contains unsupported field '${unexpected}'.`);\n}\n\nexport function parseDebugEvidencePacket(value: unknown): DebugEvidencePacket {\n if (!isRecord(value)) throw new Error('Debug evidence must be an object.');\n assertExactObjectKeys(\n value,\n [\n 'issue',\n 'expectedBehavior',\n 'reproductionAttempt',\n 'actualBehavior',\n 'logs',\n 'correlatedTraceEvidence',\n 'processOutput',\n 'browserConsoleEvidence',\n 'correlationIds',\n 'timestamps',\n 'verifiedFacts',\n 'hypotheses',\n 'unavailableEvidence',\n ],\n 'Debug evidence',\n );\n const packet: DebugEvidencePacket = {\n issue: boundedDebugText(value.issue, 'issue', true),\n expectedBehavior: optionalDebugText(value.expectedBehavior, 'expectedBehavior'),\n reproductionAttempt: optionalDebugText(value.reproductionAttempt, 'reproductionAttempt'),\n actualBehavior: optionalDebugText(value.actualBehavior, 'actualBehavior'),\n logs: optionalDebugList(value.logs, 'logs'),\n correlatedTraceEvidence: optionalDebugList(value.correlatedTraceEvidence, 'correlatedTraceEvidence'),\n processOutput: optionalDebugList(value.processOutput, 'processOutput'),\n browserConsoleEvidence: optionalDebugList(value.browserConsoleEvidence, 'browserConsoleEvidence'),\n correlationIds: optionalDebugList(value.correlationIds, 'correlationIds'),\n timestamps: optionalDebugList(value.timestamps, 'timestamps'),\n verifiedFacts: optionalDebugList(value.verifiedFacts, 'verifiedFacts'),\n hypotheses: optionalDebugList(value.hypotheses, 'hypotheses'),\n unavailableEvidence: optionalDebugList(value.unavailableEvidence, 'unavailableEvidence'),\n };\n if (Buffer.byteLength(JSON.stringify(packet), 'utf8') > DEBUG_EVIDENCE_MAX_BYTES) {\n throw new Error('Debug evidence exceeds the bounded packet size.');\n }\n return packet;\n}\n","import { defineRoot, type RootDeclaration } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext, PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\n\nimport { mountMcpTools } from '../../../../services/mcpTools';\nimport { api } from '../../../../services/planApi';\nimport { createPlanServerSession } from '../../../../services/planServerSession';\n\nexport default defineRoot(\n ({ agent, host }: PoServerPluginContext): RootDeclaration<PoServerSessionPlugin, PoServerPluginContext> => {\n const value = {\n api: [api],\n ...(agent\n ? createPlanServerSession(agent, {\n homeDirectory: host.context.homeDirectory ?? host.context.environment?.HOME,\n })\n : {}),\n };\n return {\n value,\n services: [...(value.services ?? []), ...(value.tools?.length ? [mountMcpTools(value.tools)] : [])],\n };\n },\n);\n","import { defineRoute, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../../root.server').default>>['value'];\n\nexport default defineRoute((context: WithRoot<unknown, Root>) => context.root.api![0]!);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[0], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[2], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[1], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.resources?.[0], {\n cardinality: 'optional',\n});\n","import { defineToolRestriction } from '@agimon-ai/po-core/extensionFile';\nimport type { PoHeadlessToolRestriction } from '@agimon-ai/po-core/headless';\nimport { PO_VOICE_AUTO_MODE_ID } from '@agimon-ai/po-core/voiceTools';\n\nexport default defineToolRestriction({\n when: { state: { 'minor-mode': PO_VOICE_AUTO_MODE_ID } },\n excludedTools: ['complete_plan'],\n} satisfies PoHeadlessToolRestriction);\n","import { defineToolRestriction } from '@agimon-ai/po-core/extensionFile';\nimport type { PoHeadlessToolRestriction } from '@agimon-ai/po-core/headless';\n\nexport default defineToolRestriction({\n when: { state: { 'minor-mode': 'plan' } },\n excludedTools: ['edit', 'write'],\n} satisfies PoHeadlessToolRestriction);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[2], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[0], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[1], {\n cardinality: 'optional',\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\nimport { composeServerProviderOverrides } from '@agimon-ai/po-core/serverPlugin';\nimport { composeRootHooks, composeRootInjects } from '@agimon-ai/po-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/plans/route.server';\nimport hookBeforeAgentStart from '../src/extensions/workspaces/sessions/(backend)/hook/beforeAgentStart.server';\nimport hookContext from '../src/extensions/workspaces/sessions/(backend)/hook/context.server';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server';\nimport resourcePoUsePlan from '../src/extensions/workspaces/sessions/(backend)/resource/poUsePlan.server';\nimport toolRestrictionPlan from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/plan.server';\nimport toolRestrictionPlanReadOnly from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/planReadOnly.server';\nimport toolCompletePlan from '../src/extensions/workspaces/sessions/(backend)/tool/completePlan.server';\nimport toolRecordDebugEvidence from '../src/extensions/workspaces/sessions/(backend)/tool/recordDebugEvidence.server';\nimport toolWritePlan from '../src/extensions/workspaces/sessions/(backend)/tool/writePlan.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const serverPlugin = defineServerPlugin({\n name: '@agimon-ai/po-plan',\n providerOverrides: composeServerProviderOverrides(rootSession),\n injects: composeRootInjects({ session: [rootSession] }),\n session: async (context) => {\n const scopeSession = await context.scopeRoot('session', rootSession, context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get api(): PoServerSessionPlugin['api'] { return [at(apiRoute, contextSession)]; },\n get hooks(): PoServerSessionPlugin['hooks'] { return defined([via({ event: 'before_agent_start' }, at(hookBeforeAgentStart, contextSession)), via({ event: 'context' }, at(hookContext, contextSession)), via({ event: 'session_start' }, at(hookSessionStart, contextSession))]); },\n get resources(): PoServerSessionPlugin['resources'] { return defined([at(resourcePoUsePlan, contextSession)]); },\n get toolRestrictions(): PoServerSessionPlugin['toolRestrictions'] { return [at(toolRestrictionPlan, contextSession), at(toolRestrictionPlanReadOnly, contextSession)]; },\n get tools(): PoServerSessionPlugin['tools'] { return defined([via({ name: 'complete_plan' }, at(toolCompletePlan, contextSession)), via({ name: 'record_debug_evidence' }, at(toolRecordDebugEvidence, contextSession)), via({ name: 'write_plan' }, at(toolWritePlan, contextSession))]); },\n services: [...(scopeSession.services ?? [])],\n get activities(): PoServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default serverPlugin;\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.mjs","names":["isRecord","fs","Buffer","rootSession","apiRoute","hookBeforeAgentStart","hookContext","hookSessionStart","resourcePoUsePlan","toolRestrictionPlan","toolRestrictionPlanReadOnly","toolCompletePlan","toolRecordDebugEvidence","toolWritePlan"],"sources":["../../src/schemas/mcpTools.ts","../../src/services/mcpTools/index.ts","../../src/services/planPointer/index.ts","../../src/types/apiRoutes.ts","../../src/types/planApi.ts","../../src/services/planFiles/index.ts","../../src/services/planApi/index.ts","../../src/services/optionalTeamServices/index.ts","../../src/services/planServerSession/index.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/api/plans/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/beforeAgentStart.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/context.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poUsePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/plan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/planReadOnly.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/completePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/recordDebugEvidence.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/writePlan.server.ts","../../generated/server.ts"],"sourcesContent":["import { Type } from 'typebox';\n\nconst markdown = Type.String({ minLength: 1 });\n\nexport const remoteWritePlanParameters = Type.Object({ markdown }, { additionalProperties: false });\nexport const writePlanParameters = Type.Object({ markdown: Type.Optional(markdown) }, { additionalProperties: false });\n","import type { PoHeadlessTool } from '@agimon-ai/po-core/headless';\nimport type { PoMcpPluginContext } from '@agimon-ai/po-core/mcpFacet';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { remoteWritePlanParameters } from '../../schemas/mcpTools';\n\nexport const PLAN_MCP_TOOLS_SERVICE = 'po/plan-mcp-tools';\n\nconst MODE_ID = 'plan';\nconst MODE_LABEL = 'Plan';\n\nexport interface McpToolCatalog {\n get(name: string): PoHeadlessTool | undefined;\n names(): readonly string[];\n}\n\nexport function mountMcpTools(tools: readonly PoHeadlessTool[]) {\n return (context: Context): void => {\n context.plugin((providerContext) => {\n providerContext.provide(PLAN_MCP_TOOLS_SERVICE, {\n get: (name) => tools.find((tool) => tool.name === name),\n names: () => tools.map((tool) => tool.name),\n } satisfies McpToolCatalog);\n });\n };\n}\n\nexport function bindMcpTool(context: PoMcpPluginContext, name: string): PoHeadlessTool {\n const catalog = context.services.get<McpToolCatalog>(PLAN_MCP_TOOLS_SERVICE);\n const tool = catalog?.get(name);\n if (!tool || !catalog) throw new Error(`Plan tool is unavailable: ${name}`);\n const writesPlan = name === 'write_plan';\n return {\n ...tool,\n ...(writesPlan\n ? {\n description:\n 'Save the supplied Markdown plan in the bound session. Requires active Plan mode. Saving does not approve implementation.',\n parameters: remoteWritePlanParameters,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },\n }\n : {}),\n execute(toolCallId, parameters, signal, onUpdate) {\n const activeModes = context.selection.read().state?.['minor-mode'] ?? [];\n if (!activeModes.includes(MODE_ID)) {\n const inactiveTools = [...catalog.names()].sort().join(', ');\n throw new Error(`${MODE_LABEL} minor mode is inactive. Inactive ${MODE_LABEL} tools: ${inactiveTools}.`);\n }\n if (\n writesPlan &&\n (typeof parameters !== 'object' ||\n parameters === null ||\n !('markdown' in parameters) ||\n typeof parameters.markdown !== 'string' ||\n !parameters.markdown.trim())\n ) {\n throw new Error(\n 'Supply the complete visible plan in the markdown argument. Remote calls cannot read the ChatGPT transcript.',\n );\n }\n const executionSignal = AbortSignal.any([context.signal, signal ?? context.signal]);\n return tool.execute(toolCallId, parameters, executionSignal, onUpdate, context.execution);\n },\n };\n}\n","import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { piAgentDirectory } from '@agimon-ai/po-core/piSettings';\n\nimport type { PlanPointerRecord } from '../../types/planApi';\nimport type { PlanPointerPort } from '../../types/planPointer';\n\n/**\n * Record and read where write_plan left this session's plan file.\n *\n * Pi already gives every session an agent directory, so the records live under\n * it rather than in a second place a reader would have to know about. The\n * posture matches the plan file itself, 0700 on the directory and 0600 on the\n * record: a plan is a private working document, not something to leave\n * world-readable in a shared home.\n */\n\nconst POINTER_DIRECTORY = 'po-plan';\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst PRIVATE_FILE_MODE = 0o600;\n\nexport interface NodePlanPointerOptions {\n env?: NodeJS.ProcessEnv;\n homeDirectory?: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport class PlanPointerService implements PlanPointerPort {\n private readonly env: NodeJS.ProcessEnv;\n private readonly homeDirectory: string;\n\n constructor(options: NodePlanPointerOptions = {}) {\n this.env = options.env ?? {};\n this.homeDirectory = options.homeDirectory ?? os.homedir();\n }\n\n /** Where the records live; exposed so a test can look without guessing. */\n directory(): string {\n return path.join(piAgentDirectory(this.env, this.homeDirectory), POINTER_DIRECTORY);\n }\n\n /**\n * The record for one session. The id is hashed rather than used as written:\n * it reaches here from a host that may word it however it likes, and a\n * filename is not the place to find that out.\n */\n pathFor(sessionId: string): string {\n return path.join(this.directory(), `${this.hash(sessionId)}.json`);\n }\n\n read(sessionId: string): PlanPointerRecord | undefined {\n let raw: string;\n try {\n raw = fs.readFileSync(this.pathFor(sessionId), 'utf8');\n } catch {\n return undefined;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!isRecord(parsed)) return undefined;\n const { path: planPath, title, writtenAt, planId } = parsed;\n // A record half-written by an interrupted run reads as no plan at all,\n // which is a state the cockpit already handles.\n if (typeof planPath !== 'string' || !path.isAbsolute(planPath)) return undefined;\n if (typeof title !== 'string' || typeof writtenAt !== 'string') return undefined;\n return { path: planPath, title, writtenAt, ...(typeof planId === 'string' ? { planId } : {}) };\n }\n\n write(sessionId: string, record: PlanPointerRecord): void {\n fs.mkdirSync(this.directory(), { recursive: true, mode: PRIVATE_DIRECTORY_MODE });\n fs.writeFileSync(this.pathFor(sessionId), JSON.stringify(record), { mode: PRIVATE_FILE_MODE });\n }\n\n clear(sessionId: string): void {\n fs.rmSync(this.pathFor(sessionId), { force: true });\n }\n\n private hash(value: string): string {\n return createHash('sha256').update(value).digest('hex').slice(0, 16);\n }\n}\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { PlanDetailView, PlanSaveView } from './planApi';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/workspaces/sessions/(backend)/api/plans/`, so the mount is\n * stated once, by the folder that creates it. The paths used to be written\n * here as helpers, again in the contract, and again inside every URL the page\n * built, and the copies were free to disagree.\n *\n * This is the one file the routes, the Hono app and the browser all read, so a\n * path cannot move on one side alone.\n *\n * Neither route takes a query or a path parameter: a session has one current\n * plan, so `current` answers it and `save` takes the manual write back.\n */\nconst routes = {\n current: {\n method: 'GET',\n path: '/current',\n response: undefined as unknown as ApiResponseOf<PlanDetailView>,\n },\n save: {\n method: 'PUT',\n path: '/content',\n response: undefined as unknown as ApiResponseOf<PlanSaveView>,\n },\n} as const satisfies ApiRoutes;\n\nexport default routes;\n","/**\n * The wire vocabulary this package's API shares with whatever calls it.\n *\n * It lives under src/types because that is the one server root a browser\n * bundle may read: the routes answer with these shapes and the cockpit plugin\n * reads them, so neither half can drift from the other. The paths themselves\n * are not here; they are declared once in `./apiRoutes`, which the Hono app\n * and the generated client both read.\n *\n * Two routes, and neither takes a path. A session has one current plan, so\n * `current` answers it and `content` takes the manual save back; the file they\n * act on is the one write_plan recorded, never one the page named. That is\n * also why there is nothing to escape here: a reader cannot address a second\n * file through these URLs.\n */\n\n/** Where a host mounts this package's API; the segment after /api/plugins/. */\nexport const API_BASE_PATH = 'plans';\n\n/**\n * Footer status key the session publishes once a plan exists, which is what\n * makes the cockpit's activity group appear at all. It outlives plan mode: the\n * plan is most worth reading while the agent implements it.\n */\nexport const PLAN_STATUS_KEY = 'po-plan-document';\n\n/** The selector contract shared by complete_plan and its cockpit composer prompt. */\nexport const PLAN_REVIEW_TITLE = 'Plan complete. What would you like to do?';\nexport const EXIT_PLAN_MODE_CHOICE = 'Exit plan mode and start implementation';\nexport const CONTINUE_PLANNING_CHOICE = 'Continue planning';\nexport const EXIT_PLAN_DECISION = 'exit';\nexport const CONTINUE_PLAN_DECISION = 'continue';\n\n/**\n * The label the reader sees paired with the decision the tool acts on. A headless\n * client answers with `value`, so a server plugin never has to recognise the wording; Pi's\n * own `ui.select` carries labels only, so its half maps the label back itself.\n */\nexport const PLAN_REVIEW_CHOICES = [\n { label: EXIT_PLAN_MODE_CHOICE, value: EXIT_PLAN_DECISION },\n { label: CONTINUE_PLANNING_CHOICE, value: CONTINUE_PLAN_DECISION },\n] as const;\n\n/** The same options as bare labels, which is all Pi's select and the composer prompt need. */\nexport const PLAN_REVIEW_OPTIONS = PLAN_REVIEW_CHOICES.map((choice) => choice.label);\n\n/** Between the plan's title and the stamp that marks a rewrite. */\nconst STATUS_SEPARATOR = ' · ';\n\n/** Strips the colour a session may have themed a status with. */\nconst ANSI = /\u001b\\[[0-9;]*m/gu;\n\n/** The status line the session publishes; the stamp changes on every write. */\nexport function formatPlanStatus(title: string, stamp: string): string {\n return `${title}${STATUS_SEPARATOR}${stamp}`;\n}\n\n/** What a reader gets out of the status line. */\nexport interface PlanStatusView {\n title: string;\n /** When the plan was last written, as the session worded it; empty when it said nothing. */\n stamp: string;\n}\n\n/**\n * Reading the status line back. Statuses reach a plugin raw, so the colour a\n * session may have added comes off here. A title can itself contain the\n * separator, so the stamp is taken from the last one rather than the first.\n */\nexport function parsePlanStatus(raw: string | undefined): PlanStatusView | undefined {\n if (raw === undefined) return undefined;\n const text = raw.replace(ANSI, '').trim();\n if (text === '') return undefined;\n const cut = text.lastIndexOf(STATUS_SEPARATOR);\n if (cut === -1) return { title: text, stamp: '' };\n return { title: text.slice(0, cut).trim(), stamp: text.slice(cut + STATUS_SEPARATOR.length).trim() };\n}\n\n/**\n * What write_plan recorded about this session's plan.\n *\n * The absolute path is the point of it: the extension resolves the plans\n * directory against the harness root, which no other process knows, so it\n * writes down where the plan landed rather than leaving the API to derive a\n * location it would sometimes get wrong.\n */\nexport interface PlanPointerRecord {\n path: string;\n title: string;\n writtenAt: string;\n planId?: string;\n}\n\n/** The plan as it stands on disk right now, which is what the source view edits. */\nexport interface PlanDetailView {\n path: string;\n title: string;\n writtenAt: string;\n planId?: string;\n content: string;\n /** sha256 of the content; the token a save hands back to prove it is not stale. */\n hash: string;\n /** True when the plan is missing or past the size cap, so `content` is empty. */\n unavailable: boolean;\n reason?: string;\n}\n\n/** What the save route takes. */\nexport interface PlanSaveRequest {\n /** The hash the reader loaded; a mismatch means the plan moved underneath them. */\n expectedHash: string;\n content: string;\n}\n\n/** What the save route answers with. */\nexport interface PlanSaveView {\n hash: string;\n}\n\n/** What a route reports when it refuses; the page shows `error` verbatim. */\nexport interface PlanErrorView {\n error: string;\n /** On a stale save, the hash the plan actually has now. */\n hash?: string;\n}\n","import { createHash } from 'node:crypto';\nimport fs, { type FileHandle } from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { fileMutationRunner, openGuardedFile } from '@agimon-ai/po-core/platform';\n\nexport async function writeNewPlanFile(directory: string, filename: string, content: string): Promise<string> {\n await fs.mkdir(directory, { recursive: true, mode: 0o700 });\n const planPath = path.join(directory, filename);\n await fs.writeFile(planPath, content, { encoding: 'utf8', flag: 'wx', mode: 0o600 });\n return planPath;\n}\n\nexport async function readPlanText(planPath: string): Promise<string> {\n return await fs.readFile(planPath, 'utf8');\n}\n\n/** The extra byte detects growth without ever reading or allocating the whole file. */\nasync function readBounded(handle: FileHandle, maxBytes: number): Promise<Buffer> {\n const stats = await handle.stat();\n if (!stats.isFile()) throw new Error('The plan is not a regular file.');\n const buffer = Buffer.alloc(maxBytes + 1);\n if (stats.size > maxBytes) return buffer;\n let offset = 0;\n while (offset < buffer.length) {\n const { bytesRead } = await handle.read(buffer, offset, buffer.length - offset, offset);\n if (bytesRead === 0) break;\n offset += bytesRead;\n }\n return buffer.subarray(0, offset);\n}\n\nexport async function readPlanBytes(planPath: string, maxBytes: number): Promise<Buffer> {\n const handle = await openGuardedFile(planPath);\n try {\n return await readBounded(handle, maxBytes);\n } finally {\n await handle.close();\n }\n}\n\n/** Compare and write the same open inode. The queue protects cooperating API writers, not external processes. */\nexport async function overwritePlanFile(\n planPath: string,\n content: string,\n expectedHash: string,\n maxBytes: number,\n): Promise<{ written: boolean; hash: string } | undefined> {\n const canonical = await fs.realpath(planPath);\n return await fileMutationRunner.forKey(canonical)(async () => {\n const handle = await openGuardedFile(planPath, { write: true });\n try {\n if ((await fs.realpath(planPath)) !== canonical) return undefined;\n const raw = await readBounded(handle, maxBytes);\n if (raw.length > maxBytes) return undefined;\n const hash = createHash('sha256').update(raw.toString('utf8'), 'utf8').digest('hex');\n if (hash !== expectedHash) return { written: false, hash };\n const opened = await handle.stat();\n const current = await fs.lstat(planPath);\n if (\n !opened.isFile() ||\n opened.nlink !== 1 ||\n !current.isFile() ||\n current.nlink !== 1 ||\n opened.dev !== current.dev ||\n opened.ino !== current.ino ||\n (await fs.realpath(planPath)) !== canonical\n )\n return undefined;\n await handle.writeFile(content, 'utf8');\n await handle.truncate(Buffer.byteLength(content, 'utf8'));\n return { written: true, hash: createHash('sha256').update(content, 'utf8').digest('hex') };\n } finally {\n await handle.close();\n }\n });\n}\n","import { createHash } from 'node:crypto';\n\nimport type { PoApi, PoApiContext, PoApiHandler } from '@agimon-ai/po-core/packageApi';\nimport { Hono } from 'hono';\n\nimport { PlanPointerService } from '../../services/planPointer';\nimport routes from '../../types/apiRoutes';\nimport { API_BASE_PATH, type PlanDetailView, type PlanSaveView } from '../../types/planApi';\nimport type { PlanPointerPort } from '../../types/planPointer';\nimport { overwritePlanFile, readPlanBytes } from '../planFiles';\n\n/**\n * This package's HTTP surface: the session's current plan, and the manual save.\n *\n * Each path comes from the route table the browser reads, so a route the page\n * calls and the route this serves cannot be spelled apart. Both are relative\n * to the mount its host gives it, so nothing here repeats where it was mounted. The host is one session's own server, which is what\n * makes the session id available without the page supplying it.\n *\n * Neither route takes a path. A session has exactly one current plan, and the\n * file both routes act on is the one the pointer names, so a page can address\n * the plan and nothing else; there is no traversal question to answer because\n * there is no path to traverse.\n *\n * The save refuses unless the reader proves they were looking at the content\n * that is still on disk. The agent may rewrite the plan while a tab is open,\n * and silently discarding whichever side finished second is the one outcome\n * worth ruling out.\n */\n\n/** Past this, the plan is reported rather than carried. */\nexport const MAX_PLAN_BYTES = 1024 * 1024;\n\nconst NO_PLAN = 'This session has not written a plan yet.';\nconst STALE_SAVE = 'The plan changed since it was opened.';\nconst NOT_A_FILE = 'The plan file is no longer a regular file, so it was not written.';\n\nexport interface PlanApiOptions {\n /** The session these routes answer for; absent when the host is the hub. */\n sessionId?: string;\n pointers?: PlanPointerPort;\n}\n\nfunction hashOf(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/** Reads the plan as the source view will show it, or says why it cannot. */\nasync function readPlan(\n planPath: string,\n): Promise<Pick<PlanDetailView, 'content' | 'hash' | 'unavailable' | 'reason'>> {\n let raw: Buffer;\n try {\n raw = await readPlanBytes(planPath, MAX_PLAN_BYTES);\n } catch {\n return { content: '', hash: '', unavailable: true, reason: 'the plan file no longer exists' };\n }\n if (raw.byteLength > MAX_PLAN_BYTES) {\n return { content: '', hash: '', unavailable: true, reason: `the plan is larger than ${MAX_PLAN_BYTES} bytes` };\n }\n const content = raw.toString('utf8');\n return { content, hash: hashOf(content), unavailable: false };\n}\n\nexport function createPlanApi(options: PlanApiOptions = {}): Hono {\n const app = new Hono();\n const pointers = options.pointers ?? new PlanPointerService();\n const pointerFor = (): ReturnType<PlanPointerPort['read']> =>\n options.sessionId === undefined ? undefined : pointers.read(options.sessionId);\n\n app.get(routes.current.path, async (context) => {\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n const view: PlanDetailView = {\n path: pointer.path,\n title: pointer.title,\n writtenAt: pointer.writtenAt,\n ...(pointer.planId === undefined ? {} : { planId: pointer.planId }),\n ...(await readPlan(pointer.path)),\n };\n return context.json(view);\n });\n\n app.put(routes.save.path, async (context) => {\n let request: unknown;\n try {\n request = await context.req.json();\n } catch {\n return context.json({ error: 'The save body is not JSON.' }, 400);\n }\n if (\n typeof request !== 'object' ||\n request === null ||\n Array.isArray(request) ||\n !('content' in request) ||\n typeof request.content !== 'string' ||\n !('expectedHash' in request) ||\n typeof request.expectedHash !== 'string'\n ) {\n return context.json({ error: 'A save carries the content to write and the hash it was read at.' }, 400);\n }\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n\n if (Buffer.byteLength(request.content, 'utf8') > MAX_PLAN_BYTES) {\n return context.json({ error: `The plan is larger than ${MAX_PLAN_BYTES} bytes.` }, 413);\n }\n try {\n const saved = await overwritePlanFile(pointer.path, request.content, request.expectedHash, MAX_PLAN_BYTES);\n if (saved === undefined) return context.json({ error: NOT_A_FILE }, 409);\n if (!saved.written) return context.json({ error: STALE_SAVE, hash: saved.hash }, 409);\n return context.json({ hash: saved.hash } satisfies PlanSaveView);\n } catch {\n return context.json({ error: NOT_A_FILE }, 409);\n }\n });\n\n return app;\n}\n\n/** The named export a host imports from this package's built entry. */\nexport const api: PoApi = {\n basePath: API_BASE_PATH,\n start(context: PoApiContext): PoApiHandler {\n const app = createPlanApi({\n ...(context.sessionId === undefined ? {} : { sessionId: context.sessionId }),\n pointers: new PlanPointerService({\n env: context.environment ?? {},\n homeDirectory: context.homeDirectory,\n }),\n });\n return {\n fetch: (request) => app.fetch(request),\n // Nothing outlives a request here; an API that starts a watch or a timer\n // tears it down in this callback.\n close: () => undefined,\n };\n },\n};\n","import type { Context } from '@deepseek-ai/cordis';\n\nimport { FABLE_PLAN_REQUESTER, type FablePlanRequest, type FablePlanResult } from '../fableFlow';\n\nexport const PO_FABLE_PLAN_SERVICE = 'po/fable-plan';\nexport const PO_SUBAGENT_POLICY_SERVICE = 'po/subagent-policy';\n\nexport interface PoFablePlanService {\n start(request: FablePlanRequest, signal: AbortSignal): Promise<FablePlanResult>;\n cancel(request: { requester: typeof FABLE_PLAN_REQUESTER; operationId: string; reason: string }): void;\n}\n\nexport interface SubagentPolicy {\n owner: string;\n allowedTools?: string[];\n requiredTools?: string[];\n allowMcpTools?: boolean;\n allowedExternalProfiles?: string[];\n denyExtensions?: boolean;\n}\n\nexport interface SubagentPolicyHandle {\n update(policy: SubagentPolicy): void;\n dispose(): void;\n}\n\nexport interface PoSubagentPolicyService {\n register(policy: SubagentPolicy): SubagentPolicyHandle;\n}\n\ntype StructuralServiceContext = {\n get(name: string): unknown;\n};\n\nexport function readPoFablePlanService(ctx: Context): PoFablePlanService | undefined {\n return (ctx as unknown as StructuralServiceContext).get(PO_FABLE_PLAN_SERVICE) as PoFablePlanService | undefined;\n}\n\nexport function readPoSubagentPolicyService(ctx: Context): PoSubagentPolicyService | undefined {\n return (ctx as unknown as StructuralServiceContext).get(PO_SUBAGENT_POLICY_SERVICE) as\n | PoSubagentPolicyService\n | undefined;\n}\n","import { Buffer } from 'node:buffer';\nimport path from 'node:path';\n\nimport type { IPoConfigService } from '@agimon-ai/po-config';\nimport { PO_CONFIG_SERVICE } from '@agimon-ai/po-core/config';\nimport { type PoHeadlessHostService, type PoHeadlessModelSettings } from '@agimon-ai/po-core/headless';\nimport { type PoHeadlessToolResult } from '@agimon-ai/po-core/headless';\nimport { readPackageResource, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\nimport { PO_VOICE_AUTO_MODE_ID } from '@agimon-ai/po-core/voiceTools';\nimport { serverMinorModes } from '@agimon-ai/po-minor-mode';\nimport { defineMinorMode, type MinorModeOwner, type MinorModeState } from '@agimon-ai/po-minor-mode';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { writePlanParameters } from '../../schemas/mcpTools';\nimport { resolvePlanningPlansDirectory } from '../../schemas/plan/config';\nimport {\n buildFlavorPlanningPrompt,\n buildPlanModeBasePrompt,\n type DebugEvidencePacket,\n type PlanHostCapabilities,\n type PlanningFlavor,\n} from '../../services/prompts';\nimport {\n CONTINUE_PLAN_DECISION,\n EXIT_PLAN_DECISION,\n PLAN_REVIEW_CHOICES,\n PLAN_REVIEW_TITLE,\n PLAN_STATUS_KEY,\n formatPlanStatus,\n} from '../../types/planApi';\nimport {\n PO_SUBAGENT_POLICY_SERVICE,\n readPoSubagentPolicyService,\n type SubagentPolicy,\n type SubagentPolicyHandle,\n} from '../optionalTeamServices';\nimport { readPlanText, writeNewPlanFile } from '../planFiles';\nimport { PlanPointerService } from '../planPointer';\n\nconst PLAN_ARTIFACT_SERVICE = 'po/artifacts';\ninterface PlanArtifactStorage {\n rootForSession(\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>>,\n ): Promise<string | undefined>;\n}\n\nconst RECORD_DEBUG_EVIDENCE_TOOL = 'record_debug_evidence';\nconst WRITE_PLAN_TOOL = 'write_plan';\nconst COMPLETE_PLAN_TOOL = 'complete_plan';\nconst PLAN_MODE_ID = 'plan';\nconst PLAN_MODEL_SNAPSHOT = 'plan-server-model-snapshot';\nconst PLAN_FLAVOR_SNAPSHOT = 'plan-server-flavor';\nconst PLAN_DEBUG_EVIDENCE = 'plan-debug-evidence';\nconst PLAN_DOCUMENT = 'plan-document';\n/** This host supports UI review without narrated decisions. */\nexport const PLAN_SERVER_CAPABILITIES: PlanHostCapabilities = {\n completePlanTakesDecision: false,\n narratesReview: false,\n fableAvailable: false,\n};\nconst PLAN_SUBAGENT_POLICY_OWNER = '@agimon-ai/po-plan';\n// Subagents keep every tool but `edit` and `write`, which the plan-mode restriction already withdraws from the\n// planner and, through it, from its subagents. An external runtime cannot be held to that, so none is allowed.\nconst PLAN_SUBAGENT_POLICY: SubagentPolicy = {\n owner: PLAN_SUBAGENT_POLICY_OWNER,\n allowMcpTools: true,\n allowedExternalProfiles: [],\n denyExtensions: false,\n};\n\nfunction serverPlanSubagentPolicy(host: PoHeadlessHostService): (context: Context) => void {\n return (context) => {\n context.inject([PO_SUBAGENT_POLICY_SERVICE], (child) => {\n const service = readPoSubagentPolicyService(child);\n if (!service) return undefined;\n let handle: SubagentPolicyHandle | undefined;\n const sync = (): void => {\n if (modeSelected(host)) {\n if (handle) handle.update(PLAN_SUBAGENT_POLICY);\n else handle = service.register(PLAN_SUBAGENT_POLICY);\n } else {\n handle?.dispose();\n handle = undefined;\n }\n };\n sync();\n child.effect(() => host.subscribeSelection(sync));\n return () => handle?.dispose();\n });\n };\n}\n\nfunction modeSelected(host: PoHeadlessHostService): boolean {\n return (host.context.selection.state?.['minor-mode'] ?? []).includes(PLAN_MODE_ID);\n}\n\nfunction output(value: unknown, isError = false): PoHeadlessToolResult {\n return {\n content: [{ type: 'text', text: typeof value === 'string' ? value : JSON.stringify(value, null, 2) }],\n details: value,\n ...(isError ? { isError: true } : {}),\n };\n}\n\nexport function createPlanServerSession(\n host: PoHeadlessHostService,\n options: { homeDirectory?: string },\n): Omit<PoServerSessionPlugin, 'tools'> & { tools: Parameters<PoHeadlessHostService['registerTool']>[0][] } {\n let flavor: PlanningFlavor = 'normal';\n let debugEvidence: DebugEvidencePacket | undefined;\n let modeOwner: MinorModeOwner | undefined;\n const selected = (): boolean => modeSelected(host);\n let configService: IPoConfigService | undefined;\n let artifactStorage: PlanArtifactStorage | undefined;\n const planningConfig = () => configService?.getSnapshot().settings.modes?.planning;\n // One resolution for both the prompt and write_plan.\n const plansDirectory = async (): Promise<string> => {\n const root = await artifactStorage?.rootForSession(host.context.sessionId, host.context.environment);\n if (root !== undefined) return path.join(root, 'plans');\n if (options.homeDirectory === undefined) throw new Error('Po needs a home directory to choose the plans folder.');\n return resolvePlanningPlansDirectory(\n planningConfig()?.plansDirectory,\n host.context.repoRoot,\n options.homeDirectory,\n );\n };\n const pointers = new PlanPointerService({\n env: host.context.environment,\n homeDirectory: options.homeDirectory,\n });\n /**\n * The activity group's line, and the pointer its panel reads.\n *\n * A cockpit drives this server plugin and never the Pi runtime, so both were written\n * only on the Pi side: the group never appeared, and when it did its panel\n * had no pointer to answer from.\n */\n const announcePlanDocument = (filePath: string, title: string, writtenAt: string): void => {\n try {\n pointers.write(host.context.sessionId, { path: filePath, title, writtenAt });\n } catch {\n // The plan is on disk either way. Losing the cockpit's view of it is not\n // a reason to fail the write that produced it.\n }\n host.context.client.setStatus(PLAN_STATUS_KEY, formatPlanStatus(title, planStampOf(writtenAt)));\n };\n const modeState = (): MinorModeState => {\n const active = selected();\n return {\n activation: active ? 'active' : 'inactive',\n condition: 'ready',\n ...(active ? { detail: `${flavor} - read only`, modelContextVariant: flavor } : {}),\n actions: [\n {\n id: 'activate',\n enabled: true,\n },\n {\n id: 'deactivate',\n enabled: active,\n ...(active ? {} : { disabledReason: 'Plan mode is inactive.' }),\n },\n ],\n };\n };\n const publishMode = (): void => modeOwner?.publish();\n const restoreModel = async (): Promise<void> => {\n const session = host.context.session;\n const entries = await session.entries({ type: 'custom', customType: PLAN_MODEL_SNAPSHOT, limit: 1 });\n const data = entries[0]?.data;\n if (data === undefined || data === null) return;\n if (\n typeof data !== 'object' ||\n !('thinkingLevel' in data) ||\n !['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'].includes(String(data.thinkingLevel))\n )\n throw new Error('The saved planning model settings are invalid.');\n if (!session.setModelSettings) throw new Error('This session cannot restore its model settings.');\n await session.setModelSettings(data as PoHeadlessModelSettings);\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, null);\n };\n const selectPlan = async (enabled: boolean, nextFlavor = flavor): Promise<void> => {\n const wasEnabled = selected();\n const session = host.context.session;\n if (enabled && !wasEnabled) {\n const config = planningConfig()?.main;\n if (config?.model || config?.thinking) {\n if (!session.readModelSettings || !session.setModelSettings)\n throw new Error('This session cannot apply planning model settings.');\n const previous = await session.readModelSettings();\n const settings: Partial<PoHeadlessModelSettings> = {};\n if (config.model) {\n const separator = config.model.indexOf('/');\n const provider = separator > 0 ? config.model.slice(0, separator) : previous.model?.provider;\n if (!provider) throw new Error('The planning model needs a provider.');\n settings.model = { provider, id: separator > 0 ? config.model.slice(separator + 1) : config.model };\n }\n if (config.thinking) settings.thinkingLevel = config.thinking;\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, previous);\n try {\n await session.setModelSettings(settings);\n } catch (error) {\n await session.setModelSettings(previous);\n await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, null);\n throw error;\n }\n }\n } else if (!enabled && wasEnabled) {\n await restoreModel();\n }\n const modes = (host.context.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== PLAN_MODE_ID);\n await host.changeSelection({\n axis: 'state',\n key: 'minor-mode',\n values: enabled ? [...modes, PLAN_MODE_ID] : modes,\n });\n flavor = nextFlavor;\n // Persisted because the minor mode survives a server restart while this local does not, and\n // the prompt is built from it. Without this a restored debug session silently plans as normal.\n await session.appendCustomEntry(PLAN_FLAVOR_SNAPSHOT, enabled ? { flavor } : null);\n publishMode();\n };\n\n /** Newest value for a custom entry type, or undefined when none was recorded. */\n const latestEntry = async (customType: string): Promise<unknown> => {\n const entries = await host.context.session.entries({ type: 'custom', customType, limit: 1 });\n return entries[0]?.data ?? undefined;\n };\n\n const restorePlanState = async (): Promise<void> => {\n const saved = await latestEntry(PLAN_FLAVOR_SNAPSHOT);\n if (saved !== undefined && saved !== null && typeof saved === 'object' && 'flavor' in saved) {\n const candidate = String((saved as { flavor: unknown }).flavor);\n if (candidate === 'fable') flavor = 'normal';\n else if (candidate === 'normal' || candidate === 'debug' || candidate === 'code-review') flavor = candidate;\n }\n const evidence = await latestEntry(PLAN_DEBUG_EVIDENCE);\n if (evidence === undefined || evidence === null) return;\n try {\n debugEvidence = parseDebugEvidencePacket(evidence);\n } catch {\n // A packet written by an older shape must not stop the session from planning.\n debugEvidence = undefined;\n }\n };\n modeOwner = defineMinorMode({\n descriptor: {\n source: '@agimon-ai/po-plan',\n id: PLAN_MODE_ID,\n label: 'Plan',\n description: 'Read-only planning with normal, debug, and code review flavors.',\n order: 40,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Activate plan mode or switch its planning flavor.',\n contexts: ['headless'],\n parameters: [\n {\n name: 'flavor',\n label: 'Flavor',\n kind: 'enum',\n required: true,\n choices: [\n { value: 'normal', label: 'Normal' },\n { value: 'debug', label: 'Debug' },\n { value: 'code-review', label: 'Code Review' },\n ],\n },\n ],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Exit plan mode and restore the previous agent configuration.',\n contexts: ['headless'],\n parameters: [],\n },\n ],\n },\n state: () => modeState(),\n async handleAction(_runtime, actionId, argumentsValue, { signal }) {\n signal.throwIfAborted();\n if (actionId === 'activate') {\n const nextFlavor = argumentsValue.flavor;\n if (nextFlavor !== 'normal' && nextFlavor !== 'debug' && nextFlavor !== 'code-review')\n throw new Error('A valid plan flavor is required.');\n await selectPlan(true, nextFlavor);\n return { message: `Plan mode is active with the ${nextFlavor} flavor.` };\n }\n if (actionId === 'deactivate') {\n await selectPlan(false);\n return { message: 'Plan mode deactivated.' };\n }\n throw new Error(`Unknown plan mode action: ${actionId}`);\n },\n }).createOwner(undefined);\n return {\n services: [\n serverMinorModes([modeOwner]),\n serverPlanSubagentPolicy(host),\n (context) => {\n context.inject([PO_CONFIG_SERVICE], (child) => {\n const service = child.get(PO_CONFIG_SERVICE) as IPoConfigService;\n configService = service;\n return () => {\n if (configService === service) configService = undefined;\n };\n });\n context.inject([PLAN_ARTIFACT_SERVICE], (child) => {\n const storage = child.get(PLAN_ARTIFACT_SERVICE) as PlanArtifactStorage;\n artifactStorage = storage;\n return () => {\n if (artifactStorage === storage) artifactStorage = undefined;\n };\n });\n },\n ],\n resources: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: 'po-use-plan',\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-plan/SKILL.md'),\n },\n ],\n tools: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: RECORD_DEBUG_EVIDENCE_TOOL,\n label: 'Record Debug Evidence',\n description: 'Record bounded debug evidence as optional planning context.',\n parameters: {\n type: 'object',\n properties: {\n issue: { type: 'string' },\n expectedBehavior: { type: 'string' },\n reproductionAttempt: { type: 'string' },\n actualBehavior: { type: 'string' },\n logs: { type: 'array', items: { type: 'string' } },\n correlatedTraceEvidence: { type: 'array', items: { type: 'string' } },\n processOutput: { type: 'array', items: { type: 'string' } },\n browserConsoleEvidence: { type: 'array', items: { type: 'string' } },\n correlationIds: { type: 'array', items: { type: 'string' } },\n timestamps: { type: 'array', items: { type: 'string' } },\n verifiedFacts: { type: 'array', items: { type: 'string' } },\n hypotheses: { type: 'array', items: { type: 'string' } },\n unavailableEvidence: { type: 'array', items: { type: 'string' } },\n },\n required: ['issue'],\n additionalProperties: false,\n },\n executionMode: 'serial',\n async execute(_toolCallId, parameters) {\n try {\n const parsedEvidence = parseDebugEvidencePacket(parameters);\n await host.context.session.appendCustomEntry(PLAN_DEBUG_EVIDENCE, parsedEvidence);\n // Held in memory too: the debug prompt is rebuilt every turn from this packet.\n debugEvidence = parsedEvidence;\n return output({ recorded: true });\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: WRITE_PLAN_TOOL,\n label: 'Write Plan',\n mainAgentOnly: true,\n description: 'Save the supplied Markdown plan, or the plan already presented in the local session.',\n parameters: writePlanParameters,\n executionMode: 'serial',\n async execute(toolCallId, parameters, signal) {\n try {\n signal?.throwIfAborted();\n // Remote callers supply their own visible Markdown. Only local calls may use the journal.\n let content =\n typeof parameters === 'object' && parameters !== null && 'markdown' in parameters\n ? parameters.markdown\n : undefined;\n if (content !== undefined && typeof content !== 'string')\n throw new Error('Plan Markdown must be a string.');\n if (content === undefined)\n content = visiblePlanForToolCall(await host.context.session.entries(), toolCallId);\n if (content === undefined) {\n if (host.context.selection.state?.['minor-mode']?.includes(PO_VOICE_AUTO_MODE_ID))\n throw new Error('Supply Markdown to write_plan during autonomous Voice; UI input is unavailable.');\n const requested = await host.context.client.request(\n {\n kind: 'input',\n title: 'Implementation plan',\n multiline: true,\n },\n signal,\n );\n content = typeof requested === 'string' ? requested : '';\n }\n if (typeof content !== 'string' || !content.trim())\n throw new Error('No implementation plan content was supplied.');\n const directory = await plansDirectory();\n const title = planTitleOf(content);\n const writtenAt = new Date().toISOString();\n const filename = `${planTitleSlug(content)}-${Date.now()}.md`;\n const filePath = await writeNewPlanFile(directory, filename, `${content.trim()}\\n`);\n await host.context.session.appendCustomEntry(PLAN_DOCUMENT, {\n path: filePath,\n content: content.trim(),\n title,\n writtenAt,\n });\n announcePlanDocument(filePath, title, writtenAt);\n await selectPlan(true);\n const saved = { path: filePath, written: true };\n return { ...output(saved), structuredContent: saved };\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n name: COMPLETE_PLAN_TOOL,\n label: 'Complete Plan',\n mainAgentOnly: true,\n description:\n 'Request exit-or-continue approval in the local Po UI. Requires the user to interact there; this is not a ChatGPT approval dialog.',\n // No decision parameter: this server plugin has no narrated review to answer, so a model-supplied\n // decision would be the agent approving its own plan instead of the reader approving it.\n parameters: { type: 'object', properties: {}, additionalProperties: false },\n executionMode: 'serial',\n async execute(_toolCallId, _parameters, signal) {\n try {\n if (host.context.selection.state?.['minor-mode']?.includes(PO_VOICE_AUTO_MODE_ID))\n throw new Error(\n 'UI plan review is unavailable during autonomous Voice. Wait for explicit user direction.',\n );\n // The client answers with the option's `value`, so the decision travels with the\n // question instead of the server plugin having to recognise the label it rendered.\n const decision = await host.context.client.request(\n {\n kind: 'select',\n title: PLAN_REVIEW_TITLE,\n options: PLAN_REVIEW_CHOICES.map((choice) => ({ ...choice })),\n },\n signal,\n );\n // A dismissed or aborted prompt answers with nothing, and that is not approval.\n const exited = decision === EXIT_PLAN_DECISION;\n await host.context.session.appendCustomEntry('plan-review', {\n decision: exited ? EXIT_PLAN_DECISION : CONTINUE_PLAN_DECISION,\n });\n await selectPlan(!exited);\n return {\n content: [{ type: 'text', text: exited ? PLAN_EXIT_APPROVED_TEXT : PLAN_CONTINUE_TEXT }],\n details: { exited },\n };\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n ],\n hooks: [\n {\n when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n event: 'before_agent_start',\n async handle(event) {\n const prompt = typeof event.systemPrompt === 'string' ? event.systemPrompt : '';\n const directory = await plansDirectory();\n const sections = [\n buildPlanModeBasePrompt(directory, PLAN_SERVER_CAPABILITIES),\n buildFlavorPlanningPrompt(flavor, directory, debugEvidence),\n ];\n const saved = await latestEntry(PLAN_DOCUMENT);\n if (saved !== undefined && saved !== null && typeof saved === 'object' && 'path' in saved) {\n const document = saved as { path: string; content?: string };\n // Read from disk rather than from what write_plan remembered: the plan is editable in\n // the cockpit, and a reader who corrected it expects that correction implemented.\n let content = document.content ?? '';\n try {\n content = await readPlanText(document.path);\n } catch {\n content = document.content ?? '';\n }\n if (content.trim()) sections.push(`[CURRENT PLAN]\\nSource: ${document.path}\\n\\n${content}`);\n }\n return { systemPrompt: `${prompt}\\n\\n${sections.join('\\n\\n')}`.trim() };\n },\n },\n {\n event: 'session_start',\n async handle() {\n await restorePlanState();\n // A plan written in an earlier session is still the session's plan, so\n // the dock has to hear about it again on every restart.\n const pointer = pointers.read(host.context.sessionId);\n if (pointer)\n host.context.client.setStatus(\n PLAN_STATUS_KEY,\n formatPlanStatus(pointer.title, planStampOf(pointer.writtenAt)),\n );\n // Restore a saved model override if Plan was not restored with the session.\n if (!selected()) await restoreModel();\n },\n },\n {\n // Older harness sessions persisted plan-mode context messages; keep them out of the model context.\n event: 'context',\n async handle(event) {\n if (!Array.isArray(event.messages)) return;\n return {\n messages: event.messages.filter(\n (message) => (message as { customType?: string }).customType !== PLAN_MODE_CONTEXT,\n ),\n };\n },\n },\n ],\n };\n}\n\nconst DEFAULT_PLAN_TITLE = 'implementation-plan';\nconst PLAN_TITLE_MAX_LENGTH = 64;\nconst DEBUG_EVIDENCE_MAX_BYTES = 32 * 1024;\nconst DEBUG_EVIDENCE_MAX_TEXT_BYTES = 4 * 1024;\nconst DEBUG_EVIDENCE_MAX_ITEMS = 32;\nexport const PLAN_MODE_CONTEXT = 'agent-harness-plan-mode-context';\nexport const PLAN_EXIT_APPROVED_TEXT =\n 'The user approved exiting plan mode. Full tool access is restored. Begin implementing the approved plan.';\nexport const PLAN_CONTINUE_TEXT = 'The user chose to continue planning. Remain read-only and refine the plan.';\n/** The plan's own heading, as the status line and the pointer record word it. */\nexport function planTitleOf(markdown: string): string {\n return markdown.match(/^#\\s+(.+?)\\s*$/m)?.[1] ?? DEFAULT_PLAN_TITLE;\n}\n\nexport function planTitleSlug(markdown: string): string {\n const heading = planTitleOf(markdown);\n return (\n heading\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, PLAN_TITLE_MAX_LENGTH) || DEFAULT_PLAN_TITLE\n );\n}\n\n/**\n * How the status line words when a plan was written. A malformed timestamp is\n * shown as it came rather than as an invalid date: the stamp's other job is to\n * change on a rewrite, and it can still do that.\n */\nexport function planStampOf(writtenAt: string): string {\n const at = new Date(writtenAt);\n return Number.isNaN(at.getTime()) ? writtenAt : at.toLocaleTimeString();\n}\n\nexport function visiblePlanForToolCall(entries: readonly unknown[], toolCallId: string): string | undefined {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (!entry || typeof entry !== 'object') continue;\n const candidate = entry as {\n type?: string;\n message?: { role?: string; content?: unknown };\n };\n if (candidate.type !== 'message' || candidate.message?.role !== 'assistant') continue;\n if (!Array.isArray(candidate.message.content)) continue;\n\n const toolIndex = candidate.message.content.findIndex((block) => {\n if (!block || typeof block !== 'object') return false;\n const content = block as { type?: string; id?: string; name?: string };\n return content.type === 'toolCall' && content.id === toolCallId && content.name === WRITE_PLAN_TOOL;\n });\n if (toolIndex < 0) continue;\n\n const plan = candidate.message.content\n .slice(0, toolIndex)\n .flatMap((block) => {\n if (!block || typeof block !== 'object') return [];\n const content = block as { type?: string; text?: unknown };\n return content.type === 'text' && typeof content.text === 'string' ? [content.text] : [];\n })\n .join('\\n\\n')\n .trim();\n return plan || undefined;\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nfunction boundedDebugText(value: unknown, field: string, required: boolean): string {\n if (!isString(value)) throw new Error(`${field} must be a string.`);\n const text = value.trim();\n if (required && !text) throw new Error(`${field} must not be empty.`);\n if (Buffer.byteLength(text, 'utf8') > DEBUG_EVIDENCE_MAX_TEXT_BYTES) {\n throw new Error(`${field} exceeds the bounded debug evidence limit.`);\n }\n return text;\n}\n\nfunction boundedDebugList(value: unknown, field: string): string[] {\n if (!Array.isArray(value) || value.length > DEBUG_EVIDENCE_MAX_ITEMS) {\n throw new Error(`${field} must be a bounded string array.`);\n }\n return value.map((item, index) => boundedDebugText(item, `${field}[${index}]`, false));\n}\n\nfunction optionalDebugText(value: unknown, field: string): string {\n return value === undefined ? '' : boundedDebugText(value, field, false);\n}\n\nfunction optionalDebugList(value: unknown, field: string): string[] {\n return value === undefined ? [] : boundedDebugList(value, field);\n}\n\nfunction assertExactObjectKeys(value: Record<string, unknown>, keys: readonly string[], field: string): void {\n const allowed = new Set(keys);\n const unexpected = Object.keys(value).find((key) => !allowed.has(key));\n if (unexpected) throw new Error(`${field} contains unsupported field '${unexpected}'.`);\n}\n\nexport function parseDebugEvidencePacket(value: unknown): DebugEvidencePacket {\n if (!isRecord(value)) throw new Error('Debug evidence must be an object.');\n assertExactObjectKeys(\n value,\n [\n 'issue',\n 'expectedBehavior',\n 'reproductionAttempt',\n 'actualBehavior',\n 'logs',\n 'correlatedTraceEvidence',\n 'processOutput',\n 'browserConsoleEvidence',\n 'correlationIds',\n 'timestamps',\n 'verifiedFacts',\n 'hypotheses',\n 'unavailableEvidence',\n ],\n 'Debug evidence',\n );\n const packet: DebugEvidencePacket = {\n issue: boundedDebugText(value.issue, 'issue', true),\n expectedBehavior: optionalDebugText(value.expectedBehavior, 'expectedBehavior'),\n reproductionAttempt: optionalDebugText(value.reproductionAttempt, 'reproductionAttempt'),\n actualBehavior: optionalDebugText(value.actualBehavior, 'actualBehavior'),\n logs: optionalDebugList(value.logs, 'logs'),\n correlatedTraceEvidence: optionalDebugList(value.correlatedTraceEvidence, 'correlatedTraceEvidence'),\n processOutput: optionalDebugList(value.processOutput, 'processOutput'),\n browserConsoleEvidence: optionalDebugList(value.browserConsoleEvidence, 'browserConsoleEvidence'),\n correlationIds: optionalDebugList(value.correlationIds, 'correlationIds'),\n timestamps: optionalDebugList(value.timestamps, 'timestamps'),\n verifiedFacts: optionalDebugList(value.verifiedFacts, 'verifiedFacts'),\n hypotheses: optionalDebugList(value.hypotheses, 'hypotheses'),\n unavailableEvidence: optionalDebugList(value.unavailableEvidence, 'unavailableEvidence'),\n };\n if (Buffer.byteLength(JSON.stringify(packet), 'utf8') > DEBUG_EVIDENCE_MAX_BYTES) {\n throw new Error('Debug evidence exceeds the bounded packet size.');\n }\n return packet;\n}\n","import { defineRoot, type RootDeclaration } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext, PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\n\nimport { mountMcpTools } from '../../../../services/mcpTools';\nimport { api } from '../../../../services/planApi';\nimport { createPlanServerSession } from '../../../../services/planServerSession';\n\nexport default defineRoot(\n ({ agent, host }: PoServerPluginContext): RootDeclaration<PoServerSessionPlugin, PoServerPluginContext> => {\n const value = {\n api: [api],\n ...(agent\n ? createPlanServerSession(agent, {\n homeDirectory: host.context.homeDirectory ?? host.context.environment?.HOME,\n })\n : {}),\n };\n return {\n value,\n services: [...(value.services ?? []), ...(value.tools?.length ? [mountMcpTools(value.tools)] : [])],\n };\n },\n);\n","import { defineRoute, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../../root.server').default>>['value'];\n\nexport default defineRoute((context: WithRoot<unknown, Root>) => context.root.api![0]!);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[0], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[2], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[1], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.resources?.[0], {\n cardinality: 'optional',\n});\n","import { defineToolRestriction } from '@agimon-ai/po-core/extensionFile';\nimport type { PoHeadlessToolRestriction } from '@agimon-ai/po-core/headless';\nimport { PO_VOICE_AUTO_MODE_ID } from '@agimon-ai/po-core/voiceTools';\n\nexport default defineToolRestriction({\n when: { state: { 'minor-mode': PO_VOICE_AUTO_MODE_ID } },\n excludedTools: ['complete_plan'],\n} satisfies PoHeadlessToolRestriction);\n","import { defineToolRestriction } from '@agimon-ai/po-core/extensionFile';\nimport type { PoHeadlessToolRestriction } from '@agimon-ai/po-core/headless';\n\nexport default defineToolRestriction({\n when: { state: { 'minor-mode': 'plan' } },\n excludedTools: ['edit', 'write'],\n} satisfies PoHeadlessToolRestriction);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[2], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[0], {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[1], {\n cardinality: 'optional',\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\nimport { composeServerProviderOverrides } from '@agimon-ai/po-core/serverPlugin';\nimport { composeRootHooks, composeRootInjects } from '@agimon-ai/po-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/plans/route.server';\nimport hookBeforeAgentStart from '../src/extensions/workspaces/sessions/(backend)/hook/beforeAgentStart.server';\nimport hookContext from '../src/extensions/workspaces/sessions/(backend)/hook/context.server';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server';\nimport resourcePoUsePlan from '../src/extensions/workspaces/sessions/(backend)/resource/poUsePlan.server';\nimport toolRestrictionPlan from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/plan.server';\nimport toolRestrictionPlanReadOnly from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/planReadOnly.server';\nimport toolCompletePlan from '../src/extensions/workspaces/sessions/(backend)/tool/completePlan.server';\nimport toolRecordDebugEvidence from '../src/extensions/workspaces/sessions/(backend)/tool/recordDebugEvidence.server';\nimport toolWritePlan from '../src/extensions/workspaces/sessions/(backend)/tool/writePlan.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const serverPlugin = defineServerPlugin({\n name: '@agimon-ai/po-plan',\n providerOverrides: composeServerProviderOverrides(rootSession),\n injects: composeRootInjects({ session: [rootSession] }),\n session: async (context) => {\n const scopeSession = await context.scopeRoot('session', rootSession, context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get api(): PoServerSessionPlugin['api'] { return [at(apiRoute, contextSession)]; },\n get hooks(): PoServerSessionPlugin['hooks'] { return defined([via({ event: 'before_agent_start' }, at(hookBeforeAgentStart, contextSession)), via({ event: 'context' }, at(hookContext, contextSession)), via({ event: 'session_start' }, at(hookSessionStart, contextSession))]); },\n get resources(): PoServerSessionPlugin['resources'] { return defined([at(resourcePoUsePlan, contextSession)]); },\n get toolRestrictions(): PoServerSessionPlugin['toolRestrictions'] { return [at(toolRestrictionPlan, contextSession), at(toolRestrictionPlanReadOnly, contextSession)]; },\n get tools(): PoServerSessionPlugin['tools'] { return defined([via({ name: 'complete_plan' }, at(toolCompletePlan, contextSession)), via({ name: 'record_debug_evidence' }, at(toolRecordDebugEvidence, contextSession)), via({ name: 'write_plan' }, at(toolWritePlan, contextSession))]); },\n services: [...(scopeSession.services ?? [])],\n get activities(): PoServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default serverPlugin;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/po-plan",
3
- "version": "0.0.0-alpha.32",
3
+ "version": "0.0.0-alpha.34",
4
4
  "description": "Reviewable Pi planning mode that removes file-editing tools and persists implementation plans.",
5
5
  "keywords": [
6
6
  "ai",
@@ -89,18 +89,18 @@
89
89
  "registry": "https://registry.npmjs.org/"
90
90
  },
91
91
  "dependencies": {
92
- "@agimon-ai/po-config": "0.0.0-alpha.32",
93
- "@agimon-ai/po-core": "0.0.0-alpha.32",
94
- "@agimon-ai/po-minor-mode": "0.0.0-alpha.32",
95
- "@agimon-ai/po-web-components": "0.0.0-alpha.32",
96
- "@agimon-ai/po-web-security": "0.0.0-alpha.32",
92
+ "@agimon-ai/po-config": "0.0.0-alpha.34",
93
+ "@agimon-ai/po-core": "0.0.0-alpha.34",
94
+ "@agimon-ai/po-minor-mode": "0.0.0-alpha.34",
95
+ "@agimon-ai/po-web-components": "0.0.0-alpha.34",
96
+ "@agimon-ai/po-web-security": "0.0.0-alpha.34",
97
97
  "@deepseek-ai/cordis": "4.0.5",
98
98
  "hono": "4.13.13",
99
99
  "typebox": "1.3.37"
100
100
  },
101
101
  "devDependencies": {
102
- "@agimon-ai/po-build": "0.0.0-alpha.32",
103
- "@agimon-ai/po-native-components": "0.0.0-alpha.32",
102
+ "@agimon-ai/po-build": "0.0.0-alpha.34",
103
+ "@agimon-ai/po-native-components": "0.0.0-alpha.34",
104
104
  "@earendil-works/pi-coding-agent": "1.3.0",
105
105
  "@tanstack/react-store": "0.11.2",
106
106
  "@tanstack/store": "0.11.2",
@@ -116,7 +116,7 @@
116
116
  "vitest": "5.0.4"
117
117
  },
118
118
  "peerDependencies": {
119
- "@agimon-ai/po-native-components": "0.0.0-alpha.32",
119
+ "@agimon-ai/po-native-components": "0.0.0-alpha.34",
120
120
  "@earendil-works/pi-coding-agent": "1.3.0",
121
121
  "react-native": "0.86.3",
122
122
  "react-native-unistyles": "^3.5.3"