@agimon-ai/doompi-plan 0.0.1-alpha.0

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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +42 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +1 -0
  4. package/dist/config.cjs +2 -0
  5. package/dist/config.cjs.map +1 -0
  6. package/dist/config.d.cts +14 -0
  7. package/dist/config.d.cts.map +1 -0
  8. package/dist/config.d.mts +14 -0
  9. package/dist/config.d.mts.map +1 -0
  10. package/dist/config.mjs +2 -0
  11. package/dist/config.mjs.map +1 -0
  12. package/dist/extension.cjs +2 -0
  13. package/dist/extension.cjs.map +1 -0
  14. package/dist/extension.d.cts +8 -0
  15. package/dist/extension.d.cts.map +1 -0
  16. package/dist/extension.d.mts +8 -0
  17. package/dist/extension.d.mts.map +1 -0
  18. package/dist/extension.mjs +2 -0
  19. package/dist/extension.mjs.map +1 -0
  20. package/dist/extensions/doom.cjs +2 -0
  21. package/dist/extensions/doom.cjs.map +1 -0
  22. package/dist/extensions/doom.d.cts +8 -0
  23. package/dist/extensions/doom.d.cts.map +1 -0
  24. package/dist/extensions/doom.d.mts +8 -0
  25. package/dist/extensions/doom.d.mts.map +1 -0
  26. package/dist/extensions/doom.mjs +2 -0
  27. package/dist/extensions/doom.mjs.map +1 -0
  28. package/dist/extensions/pi.cjs +2 -0
  29. package/dist/extensions/pi.cjs.map +1 -0
  30. package/dist/extensions/pi.d.cts +2 -0
  31. package/dist/extensions/pi.d.mts +2 -0
  32. package/dist/extensions/pi.mjs +2 -0
  33. package/dist/extensions/pi.mjs.map +1 -0
  34. package/dist/fableFlow.cjs +3 -0
  35. package/dist/fableFlow.cjs.map +1 -0
  36. package/dist/fableFlow.d.cts +66 -0
  37. package/dist/fableFlow.d.cts.map +1 -0
  38. package/dist/fableFlow.d.mts +66 -0
  39. package/dist/fableFlow.d.mts.map +1 -0
  40. package/dist/fableFlow.mjs +3 -0
  41. package/dist/fableFlow.mjs.map +1 -0
  42. package/dist/index.cjs +1 -0
  43. package/dist/index.d.cts +5 -0
  44. package/dist/index.d.mts +5 -0
  45. package/dist/index.mjs +1 -0
  46. package/dist/logSinkTelemetry.cjs +2 -0
  47. package/dist/logSinkTelemetry.cjs.map +1 -0
  48. package/dist/logSinkTelemetry.d.cts +24 -0
  49. package/dist/logSinkTelemetry.d.cts.map +1 -0
  50. package/dist/logSinkTelemetry.d.mts +24 -0
  51. package/dist/logSinkTelemetry.d.mts.map +1 -0
  52. package/dist/logSinkTelemetry.mjs +2 -0
  53. package/dist/logSinkTelemetry.mjs.map +1 -0
  54. package/dist/planConfig.cjs +2 -0
  55. package/dist/planConfig.cjs.map +1 -0
  56. package/dist/planConfig.mjs +2 -0
  57. package/dist/planConfig.mjs.map +1 -0
  58. package/dist/planMode.cjs +6 -0
  59. package/dist/planMode.cjs.map +1 -0
  60. package/dist/planMode.d.cts +75 -0
  61. package/dist/planMode.d.cts.map +1 -0
  62. package/dist/planMode.d.mts +75 -0
  63. package/dist/planMode.d.mts.map +1 -0
  64. package/dist/planMode.mjs +6 -0
  65. package/dist/planMode.mjs.map +1 -0
  66. package/dist/prompts.cjs +3 -0
  67. package/dist/prompts.cjs.map +1 -0
  68. package/dist/prompts.d.cts +24 -0
  69. package/dist/prompts.d.cts.map +1 -0
  70. package/dist/prompts.d.mts +24 -0
  71. package/dist/prompts.d.mts.map +1 -0
  72. package/dist/prompts.mjs +3 -0
  73. package/dist/prompts.mjs.map +1 -0
  74. package/package.json +61 -0
@@ -0,0 +1,24 @@
1
+ //#region src/logSinkTelemetry.d.ts
2
+ declare const PLAN_EVENT: {
3
+ readonly configLoadFailed: "doom_plan.config_load_failed";
4
+ readonly writePlanFailed: "doom_plan.write_plan_failed";
5
+ readonly writePlanTimedOut: "doom_plan.write_plan_timed_out";
6
+ readonly writePlanUnsafePath: "doom_plan.write_plan_unsafe_path";
7
+ readonly modelResolveFailed: "doom_plan.model_resolve_failed";
8
+ readonly modeEnabled: "doom_plan.mode_enabled";
9
+ readonly modeDisabled: "doom_plan.mode_disabled";
10
+ readonly planWritten: "doom_plan.plan_written";
11
+ readonly planReviewCompleted: "doom_plan.plan_review_completed";
12
+ };
13
+ type PlanEventName = (typeof PLAN_EVENT)[keyof typeof PLAN_EVENT];
14
+ type PlanEventAttributes = Record<string, string | number | boolean>;
15
+ interface PlanTelemetry {
16
+ recordError(event: PlanEventName, error: unknown, attributes?: PlanEventAttributes): Promise<void>;
17
+ recordWarning(event: PlanEventName, error: unknown, attributes?: PlanEventAttributes): Promise<void>;
18
+ recordEvent(event: PlanEventName, attributes?: PlanEventAttributes): Promise<void>;
19
+ flush(): Promise<void>;
20
+ shutdown(): Promise<void>;
21
+ }
22
+ //#endregion
23
+ export { PlanTelemetry };
24
+ //# sourceMappingURL=logSinkTelemetry.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logSinkTelemetry.d.mts","names":[],"sources":["../src/logSinkTelemetry.ts"],"mappings":";cAKa,UAAA;EAAA;;;;;;;;;;KAYD,aAAA,WAAwB,UAAA,eAAyB,UAAA;AAAA,KACjD,mBAAA,GAAsB,MAAA;AAAA,UAUjB,aAAA;EACf,WAAA,CAAY,KAAA,EAAO,aAAA,EAAe,KAAA,WAAgB,UAAA,GAAa,mBAAA,GAAsB,OAAA;EACrF,aAAA,CAAc,KAAA,EAAO,aAAA,EAAe,KAAA,WAAgB,UAAA,GAAa,mBAAA,GAAsB,OAAA;EACvF,WAAA,CAAY,KAAA,EAAO,aAAA,EAAe,UAAA,GAAa,mBAAA,GAAsB,OAAA;EACrE,KAAA,IAAS,OAAA;EACT,QAAA,IAAY,OAAA;AAAA"}
@@ -0,0 +1,2 @@
1
+ import{createDoomTelemetry as e}from"@agimon-ai/doompi-telemetry";const t={configLoadFailed:`doom_plan.config_load_failed`,writePlanFailed:`doom_plan.write_plan_failed`,writePlanTimedOut:`doom_plan.write_plan_timed_out`,writePlanUnsafePath:`doom_plan.write_plan_unsafe_path`,modelResolveFailed:`doom_plan.model_resolve_failed`,modeEnabled:`doom_plan.mode_enabled`,modeDisabled:`doom_plan.mode_disabled`,planWritten:`doom_plan.plan_written`,planReviewCompleted:`doom_plan.plan_review_completed`};function n(t={}){let n=e({serviceName:`doom-plan`,packageName:`@agimon-ai/doompi-plan`,cwd:t.cwd,workspaceRoot:t.workspaceRoot,env:t.env,telemetryFactory:t.telemetryFactory,warn:t.warn,enableLogs:!0,enableTraces:!0});return{recordError:(e,t,r)=>n.recordError(e,t,r),recordWarning:(e,t,r)=>n.recordWarning(e,t,r),recordEvent:(e,t)=>n.recordEvent(e,t),flush:()=>n.flush(),shutdown:()=>n.shutdown()}}export{t as PLAN_EVENT,n as createPlanTelemetry};
2
+ //# sourceMappingURL=logSinkTelemetry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logSinkTelemetry.mjs","names":[],"sources":["../src/logSinkTelemetry.ts"],"sourcesContent":["import { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\n\nconst SERVICE_NAME = 'doom-plan';\nconst PACKAGE_NAME = '@agimon-ai/doompi-plan';\n\nexport const PLAN_EVENT = {\n configLoadFailed: 'doom_plan.config_load_failed',\n writePlanFailed: 'doom_plan.write_plan_failed',\n writePlanTimedOut: 'doom_plan.write_plan_timed_out',\n writePlanUnsafePath: 'doom_plan.write_plan_unsafe_path',\n modelResolveFailed: 'doom_plan.model_resolve_failed',\n modeEnabled: 'doom_plan.mode_enabled',\n modeDisabled: 'doom_plan.mode_disabled',\n planWritten: 'doom_plan.plan_written',\n planReviewCompleted: 'doom_plan.plan_review_completed',\n} as const;\n\nexport type PlanEventName = (typeof PLAN_EVENT)[keyof typeof PLAN_EVENT];\nexport type PlanEventAttributes = Record<string, string | number | boolean>;\n\nexport interface PlanTelemetryOptions {\n cwd?: string;\n workspaceRoot?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;\n warn?: (message: string) => void;\n}\n\nexport interface PlanTelemetry {\n recordError(event: PlanEventName, error: unknown, attributes?: PlanEventAttributes): Promise<void>;\n recordWarning(event: PlanEventName, error: unknown, attributes?: PlanEventAttributes): Promise<void>;\n recordEvent(event: PlanEventName, attributes?: PlanEventAttributes): Promise<void>;\n flush(): Promise<void>;\n shutdown(): Promise<void>;\n}\n\nexport function createPlanTelemetry(options: PlanTelemetryOptions = {}): PlanTelemetry {\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: options.cwd,\n workspaceRoot: options.workspaceRoot,\n env: options.env,\n telemetryFactory: options.telemetryFactory,\n warn: options.warn,\n enableLogs: true,\n enableTraces: true,\n });\n return {\n recordError: (event, error, attributes) => telemetry.recordError(event, error, attributes),\n recordWarning: (event, error, attributes) => telemetry.recordWarning(event, error, attributes),\n recordEvent: (event, attributes) => telemetry.recordEvent(event, attributes),\n flush: () => telemetry.flush(),\n shutdown: () => telemetry.shutdown(),\n };\n}\n"],"mappings":"kEAEA,MAGa,EAAa,CACxB,iBAAkB,+BAClB,gBAAiB,8BACjB,kBAAmB,iCACnB,oBAAqB,mCACrB,mBAAoB,iCACpB,YAAa,yBACb,aAAc,0BACd,YAAa,yBACb,oBAAqB,kCACtB,CAqBD,SAAgB,EAAoB,EAAgC,EAAE,CAAiB,CACrF,IAAM,EAA2B,EAAoB,CACnD,YAAa,YACb,YAAa,yBACb,IAAK,EAAQ,IACb,cAAe,EAAQ,cACvB,IAAK,EAAQ,IACb,iBAAkB,EAAQ,iBAC1B,KAAM,EAAQ,KACd,WAAY,GACZ,aAAc,GACf,CAAC,CACF,MAAO,CACL,aAAc,EAAO,EAAO,IAAe,EAAU,YAAY,EAAO,EAAO,EAAW,CAC1F,eAAgB,EAAO,EAAO,IAAe,EAAU,cAAc,EAAO,EAAO,EAAW,CAC9F,aAAc,EAAO,IAAe,EAAU,YAAY,EAAO,EAAW,CAC5E,UAAa,EAAU,OAAO,CAC9B,aAAgB,EAAU,UAAU,CACrC"}
@@ -0,0 +1,2 @@
1
+ require(`./_virtual/_rolldown/runtime.cjs`);let e=require(`@agimon-ai/doompi-config`),t=require(`@agimon-ai/doompi-ui/config`);const n=`planning`,r=[`modes`,n],i=`main`,a=`subagents`,o=`inherit the session model`,s=`inherit`,c=[{id:`main.model`,label:`main model`,keyPath:[...r,i,`model`],placeholder:o,detail:`Model the main agent switches to while plan mode is on.`,read:e=>e?.main?.model},{id:`main.thinking`,label:`main thinking`,keyPath:[...r,i,`thinking`],placeholder:s,detail:`Thinking level appended to the main model while planning.`,options:e.DOOM_PLANNING_THINKING_LEVELS,read:e=>e?.main?.thinking},{id:`subagents.model`,label:`subagent model`,keyPath:[...r,a,`model`],placeholder:o,detail:`Model forced onto delegated planning subagents.`,read:e=>e?.subagents?.model},{id:`subagents.thinking`,label:`subagent thinking`,keyPath:[...r,a,`thinking`],placeholder:s,detail:`Thinking level appended to the subagent model.`,options:e.DOOM_PLANNING_THINKING_LEVELS,read:e=>e?.subagents?.thinking},{id:`plansdirectory`,label:`plans directory`,keyPath:[...r,`plansDirectory`],placeholder:`~/.pi/plans`,detail:`Absolute, repo-relative, or under ~. Written plans land here.`,read:e=>e?.plansDirectory}];function l(e){return c.find(t=>t.id===e)}function u(e){return e.options?.map(e=>({id:e,label:e,action:t.CONFIG_ACTION.set}))}function d(e,t){return[{id:n,title:`planning`,order:30,detail:`plan mode`,fields:c.map(t=>{let n=t.read(e),r=u(t);return{id:t.id,label:t.label,kind:r?`enum`:`text`,keyPath:t.keyPath.join(`.`),placeholder:t.placeholder,detail:t.detail,...n?{value:n}:{},...r?{choices:r}:{}}}),...t?{notice:t,noticeLevel:`error`}:{}}]}exports.planConfigSections=d,exports.planSettingByFieldId=l;
2
+ //# sourceMappingURL=planConfig.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planConfig.cjs","names":["DOOM_PLANNING_THINKING_LEVELS","CONFIG_ACTION"],"sources":["../src/planConfig.ts"],"sourcesContent":["/**\n * Plan mode's slice of the `SPC e c` config panel.\n *\n * Plan mode reads `modes.planning` from disk on every activation, so an edit\n * here lands on the next time the mode is turned on with no restart and nothing\n * to invalidate.\n *\n * The descriptor table is the whole design: the panel renders it and the write\n * handler looks the key path back up in it, so adding a setting means adding a\n * row rather than a case.\n */\n\nimport { DOOM_PLANNING_THINKING_LEVELS } from '@agimon-ai/doompi-config';\nimport type { ConfigChoice, ConfigField, ConfigSection } from '@agimon-ai/doompi-ui/config';\nimport { CONFIG_ACTION } from '@agimon-ai/doompi-ui/config';\nimport type { PlanningModeConfig } from './config.ts';\n\nexport const PLAN_CONFIG_SECTION_ID = 'planning';\nconst SECTION_ORDER = 30;\nconst PLANNING_PATH = ['modes', PLAN_CONFIG_SECTION_ID] as const;\nconst MAIN_KEY = 'main';\nconst SUBAGENTS_KEY = 'subagents';\n/** Both agents fall back to the session's own settings when left unset. */\nconst INHERIT_MODEL = 'inherit the session model';\nconst INHERIT_THINKING = 'inherit';\n\ninterface PlanSettingDescriptor {\n readonly id: string;\n readonly label: string;\n readonly keyPath: readonly string[];\n readonly placeholder: string;\n readonly detail: string;\n /** Present for a closed set; the panel offers these rather than free text. */\n readonly options?: readonly string[];\n readonly read: (config: PlanningModeConfig | undefined) => string | undefined;\n}\n\nexport const PLAN_SETTINGS: readonly PlanSettingDescriptor[] = [\n {\n id: 'main.model',\n label: 'main model',\n keyPath: [...PLANNING_PATH, MAIN_KEY, 'model'],\n placeholder: INHERIT_MODEL,\n detail: 'Model the main agent switches to while plan mode is on.',\n read: (config) => config?.main?.model,\n },\n {\n id: 'main.thinking',\n label: 'main thinking',\n keyPath: [...PLANNING_PATH, MAIN_KEY, 'thinking'],\n placeholder: INHERIT_THINKING,\n detail: 'Thinking level appended to the main model while planning.',\n options: DOOM_PLANNING_THINKING_LEVELS,\n read: (config) => config?.main?.thinking,\n },\n {\n id: 'subagents.model',\n label: 'subagent model',\n keyPath: [...PLANNING_PATH, SUBAGENTS_KEY, 'model'],\n placeholder: INHERIT_MODEL,\n detail: 'Model forced onto delegated planning subagents.',\n read: (config) => config?.subagents?.model,\n },\n {\n id: 'subagents.thinking',\n label: 'subagent thinking',\n keyPath: [...PLANNING_PATH, SUBAGENTS_KEY, 'thinking'],\n placeholder: INHERIT_THINKING,\n detail: 'Thinking level appended to the subagent model.',\n options: DOOM_PLANNING_THINKING_LEVELS,\n read: (config) => config?.subagents?.thinking,\n },\n {\n id: 'plansdirectory',\n label: 'plans directory',\n keyPath: [...PLANNING_PATH, 'plansDirectory'],\n placeholder: '~/.pi/plans',\n detail: 'Absolute, repo-relative, or under ~. Written plans land here.',\n read: (config) => config?.plansDirectory,\n },\n];\n\nexport function planSettingByFieldId(fieldId: string): PlanSettingDescriptor | undefined {\n return PLAN_SETTINGS.find((setting) => setting.id === fieldId);\n}\n\nfunction choicesFor(setting: PlanSettingDescriptor): ConfigChoice[] | undefined {\n // `set` rather than a bespoke action: choosing a level is the same write as\n // typing one, so it shares the handler.\n return setting.options?.map((option) => ({ id: option, label: option, action: CONFIG_ACTION.set }));\n}\n\nexport function planConfigSections(config: PlanningModeConfig | undefined, notice?: string): readonly ConfigSection[] {\n const fields: ConfigField[] = PLAN_SETTINGS.map((setting) => {\n const value = setting.read(config);\n const choices = choicesFor(setting);\n return {\n id: setting.id,\n label: setting.label,\n kind: choices ? ('enum' as const) : ('text' as const),\n keyPath: setting.keyPath.join('.'),\n placeholder: setting.placeholder,\n detail: setting.detail,\n ...(value ? { value } : {}),\n ...(choices ? { choices } : {}),\n };\n });\n return [\n {\n id: PLAN_CONFIG_SECTION_ID,\n title: 'planning',\n order: SECTION_ORDER,\n detail: 'plan mode',\n fields,\n ...(notice ? { notice, noticeLevel: 'error' as const } : {}),\n },\n ];\n}\n"],"mappings":"+HAiBA,MAAa,EAAyB,WAEhC,EAAgB,CAAC,QAAS,EAAuB,CACjD,EAAW,OACX,EAAgB,YAEhB,EAAgB,4BAChB,EAAmB,UAaZ,EAAkD,CAC7D,CACE,GAAI,aACJ,MAAO,aACP,QAAS,CAAC,GAAG,EAAe,EAAU,QAAQ,CAC9C,YAAa,EACb,OAAQ,0DACR,KAAO,GAAW,GAAQ,MAAM,MACjC,CACD,CACE,GAAI,gBACJ,MAAO,gBACP,QAAS,CAAC,GAAG,EAAe,EAAU,WAAW,CACjD,YAAa,EACb,OAAQ,4DACR,QAASA,EAAAA,8BACT,KAAO,GAAW,GAAQ,MAAM,SACjC,CACD,CACE,GAAI,kBACJ,MAAO,iBACP,QAAS,CAAC,GAAG,EAAe,EAAe,QAAQ,CACnD,YAAa,EACb,OAAQ,kDACR,KAAO,GAAW,GAAQ,WAAW,MACtC,CACD,CACE,GAAI,qBACJ,MAAO,oBACP,QAAS,CAAC,GAAG,EAAe,EAAe,WAAW,CACtD,YAAa,EACb,OAAQ,iDACR,QAASA,EAAAA,8BACT,KAAO,GAAW,GAAQ,WAAW,SACtC,CACD,CACE,GAAI,iBACJ,MAAO,kBACP,QAAS,CAAC,GAAG,EAAe,iBAAiB,CAC7C,YAAa,cACb,OAAQ,gEACR,KAAO,GAAW,GAAQ,eAC3B,CACF,CAED,SAAgB,EAAqB,EAAoD,CACvF,OAAO,EAAc,KAAM,GAAY,EAAQ,KAAO,EAAQ,CAGhE,SAAS,EAAW,EAA4D,CAG9E,OAAO,EAAQ,SAAS,IAAK,IAAY,CAAE,GAAI,EAAQ,MAAO,EAAQ,OAAQC,EAAAA,cAAc,IAAK,EAAE,CAGrG,SAAgB,EAAmB,EAAwC,EAA2C,CAepH,MAAO,CACL,CACE,GAAI,EACJ,MAAO,WACP,MAAO,GACP,OAAQ,YACR,OApB0B,EAAc,IAAK,GAAY,CAC3D,IAAM,EAAQ,EAAQ,KAAK,EAAO,CAC5B,EAAU,EAAW,EAAQ,CACnC,MAAO,CACL,GAAI,EAAQ,GACZ,MAAO,EAAQ,MACf,KAAM,EAAW,OAAoB,OACrC,QAAS,EAAQ,QAAQ,KAAK,IAAI,CAClC,YAAa,EAAQ,YACrB,OAAQ,EAAQ,OAChB,GAAI,EAAQ,CAAE,QAAO,CAAG,EAAE,CAC1B,GAAI,EAAU,CAAE,UAAS,CAAG,EAAE,CAC/B,EAQO,CACN,GAAI,EAAS,CAAE,SAAQ,YAAa,QAAkB,CAAG,EAAE,CAC5D,CACF"}
@@ -0,0 +1,2 @@
1
+ import{DOOM_PLANNING_THINKING_LEVELS as e}from"@agimon-ai/doompi-config";import{CONFIG_ACTION as t}from"@agimon-ai/doompi-ui/config";const n=`planning`,r=[`modes`,n],i=`main`,a=`subagents`,o=`inherit the session model`,s=`inherit`,c=[{id:`main.model`,label:`main model`,keyPath:[...r,i,`model`],placeholder:o,detail:`Model the main agent switches to while plan mode is on.`,read:e=>e?.main?.model},{id:`main.thinking`,label:`main thinking`,keyPath:[...r,i,`thinking`],placeholder:s,detail:`Thinking level appended to the main model while planning.`,options:e,read:e=>e?.main?.thinking},{id:`subagents.model`,label:`subagent model`,keyPath:[...r,a,`model`],placeholder:o,detail:`Model forced onto delegated planning subagents.`,read:e=>e?.subagents?.model},{id:`subagents.thinking`,label:`subagent thinking`,keyPath:[...r,a,`thinking`],placeholder:s,detail:`Thinking level appended to the subagent model.`,options:e,read:e=>e?.subagents?.thinking},{id:`plansdirectory`,label:`plans directory`,keyPath:[...r,`plansDirectory`],placeholder:`~/.pi/plans`,detail:`Absolute, repo-relative, or under ~. Written plans land here.`,read:e=>e?.plansDirectory}];function l(e){return c.find(t=>t.id===e)}function u(e){return e.options?.map(e=>({id:e,label:e,action:t.set}))}function d(e,t){return[{id:n,title:`planning`,order:30,detail:`plan mode`,fields:c.map(t=>{let n=t.read(e),r=u(t);return{id:t.id,label:t.label,kind:r?`enum`:`text`,keyPath:t.keyPath.join(`.`),placeholder:t.placeholder,detail:t.detail,...n?{value:n}:{},...r?{choices:r}:{}}}),...t?{notice:t,noticeLevel:`error`}:{}}]}export{d as planConfigSections,l as planSettingByFieldId};
2
+ //# sourceMappingURL=planConfig.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planConfig.mjs","names":[],"sources":["../src/planConfig.ts"],"sourcesContent":["/**\n * Plan mode's slice of the `SPC e c` config panel.\n *\n * Plan mode reads `modes.planning` from disk on every activation, so an edit\n * here lands on the next time the mode is turned on with no restart and nothing\n * to invalidate.\n *\n * The descriptor table is the whole design: the panel renders it and the write\n * handler looks the key path back up in it, so adding a setting means adding a\n * row rather than a case.\n */\n\nimport { DOOM_PLANNING_THINKING_LEVELS } from '@agimon-ai/doompi-config';\nimport type { ConfigChoice, ConfigField, ConfigSection } from '@agimon-ai/doompi-ui/config';\nimport { CONFIG_ACTION } from '@agimon-ai/doompi-ui/config';\nimport type { PlanningModeConfig } from './config.ts';\n\nexport const PLAN_CONFIG_SECTION_ID = 'planning';\nconst SECTION_ORDER = 30;\nconst PLANNING_PATH = ['modes', PLAN_CONFIG_SECTION_ID] as const;\nconst MAIN_KEY = 'main';\nconst SUBAGENTS_KEY = 'subagents';\n/** Both agents fall back to the session's own settings when left unset. */\nconst INHERIT_MODEL = 'inherit the session model';\nconst INHERIT_THINKING = 'inherit';\n\ninterface PlanSettingDescriptor {\n readonly id: string;\n readonly label: string;\n readonly keyPath: readonly string[];\n readonly placeholder: string;\n readonly detail: string;\n /** Present for a closed set; the panel offers these rather than free text. */\n readonly options?: readonly string[];\n readonly read: (config: PlanningModeConfig | undefined) => string | undefined;\n}\n\nexport const PLAN_SETTINGS: readonly PlanSettingDescriptor[] = [\n {\n id: 'main.model',\n label: 'main model',\n keyPath: [...PLANNING_PATH, MAIN_KEY, 'model'],\n placeholder: INHERIT_MODEL,\n detail: 'Model the main agent switches to while plan mode is on.',\n read: (config) => config?.main?.model,\n },\n {\n id: 'main.thinking',\n label: 'main thinking',\n keyPath: [...PLANNING_PATH, MAIN_KEY, 'thinking'],\n placeholder: INHERIT_THINKING,\n detail: 'Thinking level appended to the main model while planning.',\n options: DOOM_PLANNING_THINKING_LEVELS,\n read: (config) => config?.main?.thinking,\n },\n {\n id: 'subagents.model',\n label: 'subagent model',\n keyPath: [...PLANNING_PATH, SUBAGENTS_KEY, 'model'],\n placeholder: INHERIT_MODEL,\n detail: 'Model forced onto delegated planning subagents.',\n read: (config) => config?.subagents?.model,\n },\n {\n id: 'subagents.thinking',\n label: 'subagent thinking',\n keyPath: [...PLANNING_PATH, SUBAGENTS_KEY, 'thinking'],\n placeholder: INHERIT_THINKING,\n detail: 'Thinking level appended to the subagent model.',\n options: DOOM_PLANNING_THINKING_LEVELS,\n read: (config) => config?.subagents?.thinking,\n },\n {\n id: 'plansdirectory',\n label: 'plans directory',\n keyPath: [...PLANNING_PATH, 'plansDirectory'],\n placeholder: '~/.pi/plans',\n detail: 'Absolute, repo-relative, or under ~. Written plans land here.',\n read: (config) => config?.plansDirectory,\n },\n];\n\nexport function planSettingByFieldId(fieldId: string): PlanSettingDescriptor | undefined {\n return PLAN_SETTINGS.find((setting) => setting.id === fieldId);\n}\n\nfunction choicesFor(setting: PlanSettingDescriptor): ConfigChoice[] | undefined {\n // `set` rather than a bespoke action: choosing a level is the same write as\n // typing one, so it shares the handler.\n return setting.options?.map((option) => ({ id: option, label: option, action: CONFIG_ACTION.set }));\n}\n\nexport function planConfigSections(config: PlanningModeConfig | undefined, notice?: string): readonly ConfigSection[] {\n const fields: ConfigField[] = PLAN_SETTINGS.map((setting) => {\n const value = setting.read(config);\n const choices = choicesFor(setting);\n return {\n id: setting.id,\n label: setting.label,\n kind: choices ? ('enum' as const) : ('text' as const),\n keyPath: setting.keyPath.join('.'),\n placeholder: setting.placeholder,\n detail: setting.detail,\n ...(value ? { value } : {}),\n ...(choices ? { choices } : {}),\n };\n });\n return [\n {\n id: PLAN_CONFIG_SECTION_ID,\n title: 'planning',\n order: SECTION_ORDER,\n detail: 'plan mode',\n fields,\n ...(notice ? { notice, noticeLevel: 'error' as const } : {}),\n },\n ];\n}\n"],"mappings":"qIAiBA,MAAa,EAAyB,WAEhC,EAAgB,CAAC,QAAS,EAAuB,CACjD,EAAW,OACX,EAAgB,YAEhB,EAAgB,4BAChB,EAAmB,UAaZ,EAAkD,CAC7D,CACE,GAAI,aACJ,MAAO,aACP,QAAS,CAAC,GAAG,EAAe,EAAU,QAAQ,CAC9C,YAAa,EACb,OAAQ,0DACR,KAAO,GAAW,GAAQ,MAAM,MACjC,CACD,CACE,GAAI,gBACJ,MAAO,gBACP,QAAS,CAAC,GAAG,EAAe,EAAU,WAAW,CACjD,YAAa,EACb,OAAQ,4DACR,QAAS,EACT,KAAO,GAAW,GAAQ,MAAM,SACjC,CACD,CACE,GAAI,kBACJ,MAAO,iBACP,QAAS,CAAC,GAAG,EAAe,EAAe,QAAQ,CACnD,YAAa,EACb,OAAQ,kDACR,KAAO,GAAW,GAAQ,WAAW,MACtC,CACD,CACE,GAAI,qBACJ,MAAO,oBACP,QAAS,CAAC,GAAG,EAAe,EAAe,WAAW,CACtD,YAAa,EACb,OAAQ,iDACR,QAAS,EACT,KAAO,GAAW,GAAQ,WAAW,SACtC,CACD,CACE,GAAI,iBACJ,MAAO,kBACP,QAAS,CAAC,GAAG,EAAe,iBAAiB,CAC7C,YAAa,cACb,OAAQ,gEACR,KAAO,GAAW,GAAQ,eAC3B,CACF,CAED,SAAgB,EAAqB,EAAoD,CACvF,OAAO,EAAc,KAAM,GAAY,EAAQ,KAAO,EAAQ,CAGhE,SAAS,EAAW,EAA4D,CAG9E,OAAO,EAAQ,SAAS,IAAK,IAAY,CAAE,GAAI,EAAQ,MAAO,EAAQ,OAAQ,EAAc,IAAK,EAAE,CAGrG,SAAgB,EAAmB,EAAwC,EAA2C,CAepH,MAAO,CACL,CACE,GAAI,EACJ,MAAO,WACP,MAAO,GACP,OAAQ,YACR,OApB0B,EAAc,IAAK,GAAY,CAC3D,IAAM,EAAQ,EAAQ,KAAK,EAAO,CAC5B,EAAU,EAAW,EAAQ,CACnC,MAAO,CACL,GAAI,EAAQ,GACZ,MAAO,EAAQ,MACf,KAAM,EAAW,OAAoB,OACrC,QAAS,EAAQ,QAAQ,KAAK,IAAI,CAClC,YAAa,EAAQ,YACrB,OAAQ,EAAQ,OAChB,GAAI,EAAQ,CAAE,QAAO,CAAG,EAAE,CAC1B,GAAI,EAAU,CAAE,UAAS,CAAG,EAAE,CAC/B,EAQO,CACN,GAAI,EAAS,CAAE,SAAQ,YAAa,QAAkB,CAAG,EAAE,CAC5D,CACF"}
@@ -0,0 +1,6 @@
1
+ const e=require(`./_virtual/_rolldown/runtime.cjs`),t=require(`./config.cjs`),n=require(`./fableFlow.cjs`),r=require(`./planConfig.cjs`),i=require(`./prompts.cjs`),a=require(`./logSinkTelemetry.cjs`);let o=require(`@agimon-ai/doompi-config`),s=require(`node:buffer`),c=require(`node:crypto`),l=require(`node:fs`);l=e.__toESM(l,1);let ee=require(`node:os`);ee=e.__toESM(ee,1);let u=require(`node:path`);u=e.__toESM(u,1);let d=require(`@agimon-ai/doompi-config/configWriter`),f=require(`@agimon-ai/doompi-ui/config`),p=require(`@agimon-ai/doompi-ui/leader`),te=require(`@agimon-ai/doompi-ui/mode`),m=require(`@agimon-ai/doompi-extension-contracts/protocol`),ne=require(`@agimon-ai/doompi-extension-contracts/fable-plan`),h=require(`@agimon-ai/doompi-extension-contracts/subagent-policy`),g=require(`@agimon-ai/doompi-extension-contracts/subagent-tool`);const _=`agent-harness-plan-mode`,re=`agent-harness-plan-document`,v=`complete_plan`,y=`write_plan`,b=`ask_user_question`,ie=`bash`,x=`find`,S=`grep`,C=`read`,w=`subagent`,T=`task`,E=`record_debug_evidence`,D=`run_fable_plan`,O=`implementation-plan`,k=`@agimon-ai/doompi-plan`,A=`warning`,ae=`info`,j=`Refused to write the plan because its destination is not a regular file.`,M=`plan.trigger`,oe=`plan.model`,N=`plan.flavor`,se=`not_found`,ce=`unauthenticated`,le=`restore_failed`,ue=new Set,P=5e3,de=`Exit plan mode and start implementation`,fe=new Set([`add_directory`,b,ie,v,x,S,`intercom`,`ls`,C,`search_external_files`,w,`subagent_supervisor`,`subagent_wait`,T,y]),F=[C,ie,S,x,`ls`],pe=[...F,`mcp`],I=`leader`,L=[`off`,`minimal`,`low`,`medium`,`high`,`xhigh`,`max`],R=[`idle`,`draft`,`review`,`completed`,`failed`,`cancelled`,`interrupted`];function me(e){return(e.match(/^#\s+(.+?)\s*$/m)?.[1]??O).normalize(`NFKD`).replace(/[\u0300-\u036f]/g,``).toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).slice(0,64)||O}function he(e){return`${encodeURIComponent(e).slice(0,48)||`session`}--${(0,c.createHash)(`sha256`).update(e).digest(`hex`)}`}function z(e=new Date,t=(0,c.randomUUID)()){return`${e.toISOString().replace(/[-:]/g,``).replace(/\.\d{3}Z$/,`Z`)}--${t}`}function ge(e,t){for(let n=e.length-1;n>=0;--n){let r=e[n];if(!r||typeof r!=`object`)continue;let i=r;if(i.type!==`message`||i.message?.role!==`assistant`||!Array.isArray(i.message.content))continue;let a=i.message.content.findIndex(e=>{if(!e||typeof e!=`object`)return!1;let n=e;return n.type===`toolCall`&&n.id===t&&n.name===y});if(!(a<0))return i.message.content.slice(0,a).flatMap(e=>{if(!e||typeof e!=`object`)return[];let t=e;return t.type===`text`&&typeof t.text==`string`?[t.text]:[]}).join(`
2
+
3
+ `).trim()||void 0}}function _e(e){return e.reason instanceof Error?e.reason:Error(`Plan write cancelled.`)}async function B(e,t){if(t.aborted)throw _e(t);let n,r=new Promise((e,r)=>{n=()=>r(_e(t)),t.addEventListener(`abort`,n,{once:!0})});try{return await Promise.race([e(),r])}finally{n&&t.removeEventListener(`abort`,n)}}function V(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function H(e){return typeof e==`string`}function U(e){if(!(!V(e)||!H(e.provider)||!H(e.id))&&!(!e.provider||!e.id||e.provider.length>128||e.id.length>128))return{provider:e.provider,id:e.id}}function W(e){return H(e)&&L.includes(e)?e:void 0}function G(e){return H(e)&&R.includes(e)?e:void 0}function ve(e){if(!(!Array.isArray(e)||e.some(e=>!H(e))))return e.map(e=>e)}function K(e){if(!V(e))return;let t=ve(e.tools),n=W(e.thinking);if(!t||n===void 0)return;let r=e.model===void 0?void 0:U(e.model);if(!(e.model!==void 0&&!r))return{tools:t,...r?{model:r}:{},thinking:n}}function ye(e){return e===`normal`||e===`debug`||e===`fable`?e:void 0}function be(e){if(e.version!==2)return;let t=e.activeFlavor===void 0?void 0:ye(e.activeFlavor);if(e.activeFlavor!==void 0&&!t)return;let n=e.originalSnapshot===void 0?void 0:K(e.originalSnapshot);if(e.originalSnapshot!==void 0&&!n)return;let r=e.planId===void 0?void 0:H(e.planId)?e.planId:void 0;if(e.planId!==void 0&&r===void 0)return;let i=e.interruptedFableStage===void 0?void 0:G(e.interruptedFableStage);if(!(e.interruptedFableStage!==void 0&&!i))return{version:2,...t?{activeFlavor:t}:{},...n?{originalSnapshot:n}:{},...r?{planId:r}:{},...i?{interruptedFableStage:i}:{}}}function xe(e){if(e.enabled!==!0&&e.enabled!==!1)return;let t=e.toolsBeforePlanMode===void 0?void 0:ve(e.toolsBeforePlanMode);if(e.toolsBeforePlanMode!==void 0&&!t)return;let n=e.modelBeforePlanMode===void 0?void 0:U(e.modelBeforePlanMode);if(e.modelBeforePlanMode!==void 0&&!n)return;let r=e.thinkingBeforePlanMode===void 0?void 0:W(e.thinkingBeforePlanMode);if(e.thinkingBeforePlanMode!==void 0&&r===void 0)return;let i=e.planId===void 0?void 0:H(e.planId)?e.planId:void 0;if(e.planId!==void 0&&i===void 0)return;let a=t&&r!==void 0?{tools:t,...n?{model:n}:{},thinking:r}:void 0;return{version:2,...e.enabled?{activeFlavor:`normal`}:{},...a?{originalSnapshot:a}:{},...i?{planId:i}:{}}}function Se(e){if(V(e))return be(e)??xe(e)}function Ce(e){if(!V(e)||!H(e.content)||!H(e.path)||!H(e.sessionId)||!H(e.title)||!H(e.writtenAt))return;let t=e.planId===void 0?void 0:H(e.planId)?e.planId:void 0;if(!(e.planId!==void 0&&t===void 0))return{content:e.content,path:e.path,sessionId:e.sessionId,...t?{planId:t}:{},title:e.title,writtenAt:e.writtenAt}}function q(e,t,n){if(!H(e))throw Error(`${t} must be a string.`);let r=e.trim();if(n&&!r)throw Error(`${t} must not be empty.`);if(s.Buffer.byteLength(r,`utf8`)>4096)throw Error(`${t} exceeds the bounded debug evidence limit.`);return r}function we(e,t){if(!Array.isArray(e)||e.length>32)throw Error(`${t} must be a bounded string array.`);return e.map((e,n)=>q(e,`${t}[${n}]`,!1))}function Te(e,t){return e===void 0?``:q(e,t,!1)}function J(e,t){return e===void 0?[]:we(e,t)}function Ee(e,t,n){let r=new Set(t),i=Object.keys(e).find(e=>!r.has(e));if(i)throw Error(`${n} contains unsupported field '${i}'.`)}function De(e){if(!V(e))throw Error(`Debug evidence must be an object.`);Ee(e,[`issue`,`expectedBehavior`,`reproductionAttempt`,`actualBehavior`,`logs`,`correlatedTraceEvidence`,`processOutput`,`browserConsoleEvidence`,`correlationIds`,`timestamps`,`verifiedFacts`,`hypotheses`,`unavailableEvidence`],`Debug evidence`);let t={issue:q(e.issue,`issue`,!0),expectedBehavior:Te(e.expectedBehavior,`expectedBehavior`),reproductionAttempt:Te(e.reproductionAttempt,`reproductionAttempt`),actualBehavior:Te(e.actualBehavior,`actualBehavior`),logs:J(e.logs,`logs`),correlatedTraceEvidence:J(e.correlatedTraceEvidence,`correlatedTraceEvidence`),processOutput:J(e.processOutput,`processOutput`),browserConsoleEvidence:J(e.browserConsoleEvidence,`browserConsoleEvidence`),correlationIds:J(e.correlationIds,`correlationIds`),timestamps:J(e.timestamps,`timestamps`),verifiedFacts:J(e.verifiedFacts,`verifiedFacts`),hypotheses:J(e.hypotheses,`hypotheses`),unavailableEvidence:J(e.unavailableEvidence,`unavailableEvidence`)};if(s.Buffer.byteLength(JSON.stringify(t),`utf8`)>32768)throw Error(`Debug evidence exceeds the bounded packet size.`);return t}function Oe(e,t){let n=new Set(t),r=e.filter(e=>fe.has(e)),i=F.filter(e=>n.has(e)),a=[b,v,T,y].filter(e=>n.has(e));return[...new Set([...r,...i,...a])]}function ke(e,t,n,r){let i=new Set(t),a=Oe(e,t),o=n===`debug`?[E,...r].filter(e=>i.has(e)):[];return n===`fable`&&i.has(D)&&o.push(D),[...new Set([...a,...o])]}function Y(e){if(e.output=!1,e.progress=!1,e.worktree=!1,Array.isArray(e.parallel))for(let t of e.parallel)Y(t);else e.parallel&&Y(e.parallel)}function Ae(e){if(e.action!==void 0){(0,g.isSubagentAction)(e.action)&&(0,g.subagentActionAcceptsField)(e.action,`artifacts`)&&(e.artifacts=!1);return}e.artifacts=!1,e.output=!1,e.share=!1,e.progress=!1,e.worktree=!1,delete e.chainDir,delete e.outputSchema,delete e.sessionDir;for(let t of e.tasks??[])Y(t);for(let t of e.chain??[])Y(t)}function je(e,t){if(!e?.model&&!e?.thinking)return;let n=e.model??(t?`${t.provider}/${t.id}`:void 0);if(n)return e.thinking?`${n.replace(/:(?:off|minimal|low|medium|high|xhigh|max)$/,``)}:${e.thinking}`:n}function Me(e,t){if(e.action===`run`)for(let n of e.requests??[])n.model=t}function Ne(e,t){e.action===`assign`&&(e.model=t)}function Pe(e){return new Set([`append-step`,`create`,`delete`,`disable`,`eject`,`enable`,`grant-spawn-budget`,`reset`,`schedule`,`schedule-cancel`,`update`,`watchdog.configure`]).has(e??``)}function Fe(e,t){let n=e.indexOf(`/`);if(n>0)return t.modelRegistry.find(e.slice(0,n),e.slice(n+1));let r=t.modelRegistry.getAvailable().filter(t=>t.id===e);return r.find(e=>e.provider===t.model?.provider)??(r.length===1?r[0]:void 0)}function Ie(e=process.env,n=process.cwd()){return t.loadDoomConfig((0,o.loadHarnessState)(e).state.root??n).modes?.planning}function Le(e){let t={key:`p`,label:`plan`,order:60};return[{id:`plan.normal`,path:[t,{key:`p`,label:`normal`,detail:`read-only planning`}],action:{name:`plan.normal`}},{id:`plan.debug`,path:[t,{key:`d`,label:`debug`,detail:`adaptive debug planning`}],action:{name:`plan.debug`}},{id:`plan.fable`,path:[t,{key:`f`,label:`fable`,detail:`repository-aware draft`}],action:{name:`plan.fable`}},...e?[{id:`plan.exit`,path:[t,{key:`e`,label:`exit`,detail:`restore and exit`}],action:{name:`plan.exit`}}]:[]]}function Re(e,t=Ie,c=a.createPlanTelemetry(),g={}){let b=!1,x,S,C,O,F,L,R=!1,V,H=`idle`,U,W,G,ve=Promise.resolve(),K=g.doomIntegrations??!0,ye=new Set(g.debugDiagnosticTools??ue),be=(0,ne.createFablePlanBrokerClient)(()=>W?.sessionManager.getSessionId()),xe=g.fableBroker??{start:(e,t)=>be.start(e,t),cancel:(e,t)=>be.cancel({requester:ne.FABLE_PLAN_REQUESTER,operationId:e,reason:t})},q=()=>g.fableBroker!==void 0||be.isAvailable(),we=K?(0,te.registerDoomModeContribution)(e,{source:k,id:`plan`,order:40}):{update:()=>void 0},Te=K?(0,p.createDoomLeaderContribution)(e,{source:k,bindings:Le(!1)}):{update:()=>void 0},J,Ee=K?(0,f.registerDoomConfigContribution)(e,{source:k,listSections:()=>{try{return r.planConfigSections(t(),J)}catch(e){return r.planConfigSections(void 0,e instanceof Error?e.message:String(e))}},handlers:{[f.CONFIG_ACTION.set]:async({fieldId:e,value:t})=>{let n=r.planSettingByFieldId(e);!n||!t||(J=void 0,await(0,d.setDoomConfigValue)((0,o.globalDoomConfigPath)(),[...n.keyPath],t))},[f.CONFIG_ACTION.clear]:async({fieldId:e})=>{let t=r.planSettingByFieldId(e);t&&(J=void 0,await(0,d.unsetDoomConfigValue)((0,o.globalDoomConfigPath)(),[...t.keyPath]))}},onError:e=>{J=e instanceof Error?e.message:String(e)}}):{dispose:()=>void 0,update:()=>void 0};function Oe(){Te.update(Le(b))}function Y(e){Oe();let t=x,n=b&&t?`plan:${t}`:void 0,r=t===`fable`&&H!==`idle`?` · ${H}`:``;e.ui.setStatus(`plan-mode`,n?e.ui.theme.fg(A,n):void 0),we.update(b&&t?{label:`PLAN`,detail:`${t}${r} - read only`,color:A}:void 0)}function Re(){if(!K||!b||!x||!W)return;let t={owner:k,allowedTools:[...pe],requiredTools:[ie,`mcp`],allowMcpTools:!0,allowedExternalProfiles:x===`fable`?[n.FABLE_PLAN_PROFILE]:[],denyExtensions:!1};O?O.update(t):O=(0,h.registerSubagentPolicy)((0,m.createProtocolRuntime)({bus:e.events,source:k,sessionId:W.sessionManager.getSessionId()}),t)}function X(){e.appendEntry(_,{version:2,...b&&x?{activeFlavor:x}:{},...S?{originalSnapshot:{tools:[...S.tools],...S.model?{model:{...S.model}}:{},thinking:S.thinking}}:{},...L?{planId:L}:{},...U?{interruptedFableStage:U}:{}})}function Z(e,t,n){c.recordWarning(a.PLAN_EVENT.modelResolveFailed,`Planning model ${n}: ${t}`,{[oe]:t,"plan.model.phase":e,"plan.model.reason":n})}async function ze(t){let n=C?.main;if(n){if(n.model){let r=Fe(n.model,t);r?await e.setModel(r)||(t.ui.notify(`Planning model is unavailable without authentication: ${n.model}`,A),Z(`apply`,n.model,ce)):(t.ui.notify(`Planning model not found: ${n.model}`,A),Z(`apply`,n.model,se))}n.thinking&&e.setThinkingLevel(n.thinking)}}async function Be(t,n){if(!n)return!1;if(n.model){let r=`${n.model.provider}/${n.model.id}`,i=t.modelRegistry.find(n.model.provider,n.model.id);if(!i)return t.ui.notify(`Previous model not found: ${r}`,A),Z(`restore`,r,se),!1;try{if(!await e.setModel(i))return t.ui.notify(`Previous model is unavailable without authentication: ${r}`,A),Z(`restore`,r,ce),!1}catch(e){return t.ui.notify(`Previous model could not be restored: ${r}`,A),Z(`restore`,r,le),c.recordError(a.PLAN_EVENT.modelResolveFailed,e,{[oe]:r,"plan.model.phase":`restore`,"plan.model.reason":le}),!1}}return e.setThinkingLevel(n.thinking),!0}function Ve(e){b&&x?e.ui.notify(`Already in plan:${x}.`,ae):e.ui.notify(`Plan mode is inactive.`,ae)}function Q(e){let t=ve.then(e,e);return ve=t.then(()=>void 0,()=>void 0),t}async function He(e){if(!G&&!H.match(/^(draft|review)$/u))return;(H===`draft`||H===`review`)&&(U=H),We.cancel(e);let t=G;if(t)try{await t}catch(e){c.recordError(a.PLAN_EVENT.modeDisabled,e,{[N]:`fable`,"plan.fable.reason":`cancel_failed`})}G=void 0,U&&(H=`interrupted`),W&&Y(W),X()}async function $(n,r,i,o){if(W=n,b){if(x===r){Ve(n);return}x===`fable`&&await He(`Leaving Fable for plan:${r}.`),x=r,Re(),e.setActiveTools(ke(S?.tools??[],e.getAllTools().map(e=>e.name),r,ye)),Y(n),X(),c.recordEvent(a.PLAN_EVENT.modeEnabled,{[M]:i,[N]:r,"plan.tool.count":e.getActiveTools().length});return}let s;try{s=t()}catch(e){throw c.recordError(a.PLAN_EVENT.configLoadFailed,e,{[M]:i}),e}o?L??=z():(F=void 0,R=!1,L=z(),U=void 0,H=`idle`),C=s,S??={tools:[...e.getActiveTools()],...n.model?{model:{provider:n.model.provider,id:n.model.id}}:{},thinking:e.getThinkingLevel()},b=!0,x=r,e.setActiveTools(ke(S.tools,e.getAllTools().map(e=>e.name),r,ye)),Re(),await ze(n),Y(n),X(),c.recordEvent(a.PLAN_EVENT.modeEnabled,{[M]:i,[N]:r,"plan.tool.count":e.getActiveTools().length,...C?.main?.model?{[oe]:C.main.model}:{},...C?.main?.thinking?{"plan.thinking":C.main.thinking}:{}})}async function Ue(t,n){if(!b)return Ve(t),!1;await He(`Plan mode is exiting.`);let r=S;if(!await Be(t,r))return t.ui.notify(`Previous model was not restored. Plan mode remains read-only.`,A),Y(t),X(),c.recordWarning(a.PLAN_EVENT.modeDisabled,`Plan mode restoration failed.`,{[M]:n,[N]:x??`unknown`,"plan.restored":!1}),!1;let i=!!F;return e.setActiveTools([...r?.tools??[]]),O?.dispose(),O=void 0,b=!1,x=void 0,C=void 0,S=void 0,V=void 0,H=`idle`,U=void 0,Y(t),X(),c.recordEvent(a.PLAN_EVENT.modeDisabled,{[M]:n,[N]:`normal`,"plan.written":i,"plan.restored":!0}),!0}let We=n.createFablePlanFlow({broker:xe,isAuthorized:()=>b&&x===`fable`&&q(),onStage:e=>{H=e,(e===`completed`||e===`failed`||e===`cancelled`)&&(U=void 0),W&&Y(W),b&&X()},onError:e=>{c.recordError(a.PLAN_EVENT.modeEnabled,e,{[N]:`fable`,"plan.fable.reason":`flow_error`})}});e.registerTool({name:E,label:`Record Debug Evidence`,description:`Record optional bounded debug evidence while planning a repository fix.`,promptSnippet:`Record the issue and any relevant reproduction, logs, traces, process output, or browser evidence`,parameters:{type:`object`,properties:{issue:{type:`string`},expectedBehavior:{type:`string`},reproductionAttempt:{type:`string`},actualBehavior:{type:`string`},logs:{type:`array`,items:{type:`string`}},correlatedTraceEvidence:{type:`array`,items:{type:`string`}},processOutput:{type:`array`,items:{type:`string`}},browserConsoleEvidence:{type:`array`,items:{type:`string`}},correlationIds:{type:`array`,items:{type:`string`}},timestamps:{type:`array`,items:{type:`string`}},verifiedFacts:{type:`array`,items:{type:`string`}},hypotheses:{type:`array`,items:{type:`string`}},unavailableEvidence:{type:`array`,items:{type:`string`}}},required:[`issue`],additionalProperties:!1},async execute(e,t){if(!b||x!==`debug`)return{content:[{type:`text`,text:`Debug planning is not active.`}],details:{recorded:!1}};try{V=De(t)}catch(e){throw c.recordWarning(a.PLAN_EVENT.modeEnabled,e,{[N]:`debug`,"plan.debug.reason":`invalid_evidence`}),e}return W&&Y(W),{content:[{type:`text`,text:`Debug evidence recorded as optional planning context.`}],details:{recorded:!0}}}}),e.registerTool({name:D,label:`Run Fable Plan`,description:`Send a bounded, sanitized planning packet to the local Fable broker for one repository-aware draft.`,promptSnippet:`Run the local Fable draft with the bounded planning packet`,parameters:{type:`object`,properties:{goal:{type:`array`,items:{type:`string`}},constraints:{type:`array`,items:{type:`string`}},decisions:{type:`array`,items:{type:`string`}},verifiedFindings:{type:`array`,items:{type:`object`}},inferredFindings:{type:`array`,items:{type:`string`}},unresolvedQuestions:{type:`array`,items:{type:`string`}},currentPlan:{type:`string`}},additionalProperties:!1},async execute(e,t,n){if(!b||x!==`fable`)return{content:[{type:`text`,text:`Fable planning is not active.`}],details:{started:!1}};if(!q())return{content:[{type:`text`,text:`The local Fable broker is unavailable. Fable planning remains disabled.`}],details:{started:!1,errorCode:`broker_unavailable`}};let r=We.run(t,n);G=r;try{let e=await r;return{content:[{type:`text`,text:e.draft?`Fable draft:\n${e.draft}`:`Fable planning ${e.status}: ${e.errorCode??`no output`}.`}],details:{...e,started:!0}}}finally{G===r&&(G=void 0)}}}),e.registerTool({name:y,label:`Write Plan`,description:`After presenting the complete implementation plan as Markdown in chat, save that visible plan to a unique Markdown file in the configured plans directory.`,promptSnippet:`Save the implementation plan already presented in chat to the configured plans directory`,parameters:{type:`object`,properties:{},additionalProperties:!1},async execute(t,n,r,i,d){if(!b)return{content:[{type:`text`,text:`Plan mode is disabled. Use normal file tools instead.`}],details:{written:!1}};let f=ge(d.sessionManager.getBranch(),t);if(!f){let e=Error(`Present the complete implementation plan as visible Markdown in chat before calling write_plan.`);throw c.recordError(a.PLAN_EVENT.writePlanFailed,e,{"plan.reason":`missing_visible_plan`}),e}let p=Date.now(),te=(0,o.getHarnessState)().root??d.cwd,m=(0,o.resolvePlanningPlansDirectory)(C?.plansDirectory,te,ee.default.homedir()),ne=he(d.sessionManager.getSessionId());L??=z();let h=F?.planId===L&&u.default.dirname(F.path)===m?F.path:void 0,g=me(f),_=L,v=h??u.default.join(m,`${g}--${_}.md`),y=new AbortController,ie=Error(`Writing ${v} timed out after ${P}ms.`),x=setTimeout(()=>y.abort(ie),P),S=r?AbortSignal.any([r,y.signal]):y.signal,w=`checking`,T=()=>{i?.({content:[{type:`text`,text:`${w===`checking`?`Checking`:`Writing`} ${v}...`}],details:{phase:w,path:v,startedAt:p}})},E=(e,t)=>{c.recordWarning(a.PLAN_EVENT.writePlanUnsafePath,t,{"plan.phase":w,"plan.refusal":e})};try{T();try{await B(()=>l.default.promises.mkdir(m,{recursive:!0,mode:448}),S)}catch(e){throw S.aborted?_e(S):Error(`Could not create the configured plans directory ${m}.`,{cause:e})}let t=await B(()=>l.default.promises.lstat(m),S),n=await B(()=>l.default.promises.realpath(m),S);if(t.isSymbolicLink()||!t.isDirectory())return E(`unsafe_plans_directory`,`Refused to write the plan because the configured path is unsafe.`),{content:[{type:`text`,text:`Refused to write the plan because the configured path is unsafe.`}],details:{written:!1,path:v,phase:w,durationMs:Date.now()-p}};w=`writing`,T();let r;try{for(let e=0;e<3;e+=1)try{let e=h?0:l.default.constants.O_EXCL;r=await B(()=>l.default.promises.open(v,l.default.constants.O_CREAT|l.default.constants.O_WRONLY|l.default.constants.O_NONBLOCK|l.default.constants.O_NOFOLLOW|e,384),S);break}catch(t){if(!(!h&&t instanceof Error&&`code`in t&&String(t.code)===`EEXIST`)||e===2)throw t;_=z(),L=_,v=u.default.join(m,`${g}--${_}.md`),X()}if(!r)throw Error(`Could not allocate a unique plan filename in ${m}.`);let e=await B(()=>l.default.promises.realpath(m),S),t=await B(()=>r.stat(),S);if(e!==n||!t.isFile()||t.nlink!==1)return E(`invalid_destination`,j),{content:[{type:`text`,text:j}],details:{written:!1,path:v,phase:w,durationMs:Date.now()-p}};await B(()=>r.truncate(0),S),await B(()=>r.writeFile(f,{encoding:`utf8`,signal:S}),S)}catch(e){if(e instanceof Error&&`code`in e&&[`EISDIR`,`ELOOP`,`ENXIO`].includes(String(e.code)))return E(`invalid_destination`,j),{content:[{type:`text`,text:j}],details:{written:!1,path:v,phase:w,durationMs:Date.now()-p}};throw e}finally{await r?.close()}return F={content:f,path:v,sessionId:ne,planId:_,title:g,writtenAt:new Date().toISOString()},e.appendEntry(re,F),R=!0,c.recordEvent(a.PLAN_EVENT.planWritten,{"plan.written":!0,"plan.bytes":s.Buffer.byteLength(f,`utf8`),"plan.duration_ms":Date.now()-p,"plan.revised":!!h}),{content:[{type:`text`,text:`Wrote implementation plan to ${v}.`}],details:{written:!0,path:v,phase:w,durationMs:Date.now()-p}}}catch(e){let t={"plan.phase":w,"plan.duration_ms":Date.now()-p};if(y.signal.aborted&&!r?.aborted){let n=Error(`write_plan timed out during ${w} for ${v}.`,{cause:e});throw c.recordError(a.PLAN_EVENT.writePlanTimedOut,n,{...t,"plan.timeout_ms":P}),n}throw c.recordError(a.PLAN_EVENT.writePlanFailed,e,{...t,"plan.cancelled":r?.aborted??!1}),e}finally{clearTimeout(x)}}}),e.registerTool({name:v,label:`Complete Plan`,description:`Use only after presenting a concrete implementation plan. Ask the user whether to exit plan mode and begin implementation or continue planning.`,promptSnippet:`Ask the user whether to exit plan mode after the implementation plan is complete`,parameters:{type:`object`,properties:{},additionalProperties:!1},async execute(e,t,n,r,i){if(!b)return{content:[{type:`text`,text:`Plan mode is already disabled.`}],details:{exited:!1}};if(!R)return{content:[{type:`text`,text:`Present the complete plan in chat and save it with write_plan before requesting approval.`}],details:{exited:!1}};if(!i.hasUI)return c.recordEvent(a.PLAN_EVENT.planReviewCompleted,{"plan.outcome":`no_ui`}),{content:[{type:`text`,text:`The plan is complete, but this run cannot ask the user interactively. Remain in plan mode until the user uses SPC p e.`}],details:{exited:!1}};let o=await i.ui.select(`Plan complete. What would you like to do?`,[de,`Continue planning`]);if(c.recordEvent(a.PLAN_EVENT.planReviewCompleted,{"plan.outcome":o===de?`exited`:`continued`}),o===de){let e=await Q(()=>Ue(i,`plan_approved`));return{content:[{type:`text`,text:e?`The user approved exiting plan mode. Full tool access is restored. Begin implementing the approved plan.`:`The previous model could not be restored. Plan mode remains read-only.`}],details:{exited:e}}}return R=!1,{content:[{type:`text`,text:`The user chose to continue planning. Remain read-only and refine the plan.`}],details:{exited:!1}}}}),K&&(0,p.registerDoomLeaderActionHandlers)(e,{source:k,handlers:{"plan.normal":()=>{let e=W;return e?Q(()=>$(e,`normal`,I,!1)):void 0},"plan.exit":()=>{let e=W;return e?Q(async()=>{await Ue(e,I)}):void 0},"plan.debug":()=>{let e=W;return e?Q(()=>$(e,`debug`,I,!1)):void 0},"plan.fable":()=>{let e=W;return e?Q(()=>$(e,`fable`,I,!1)):void 0}},onError:(e,t)=>{W?.hasUI&&W.ui.notify(`Leader action ${t} failed. Plan mode remains read-only.`,A),c.recordError(a.PLAN_EVENT.modeEnabled,e,{[M]:I,"plan.action":t})}}),e.on(`tool_call`,async(e,t)=>{if(!b)return;let n=x===`debug`&&(e.toolName===E||ye.has(e.toolName))||x===`fable`&&e.toolName===D;if(!fe.has(e.toolName)&&!n)return{block:!0,reason:`Plan mode blocks the ${e.toolName} tool. Use SPC p e to restore access.`};let r=je(C?.subagents,t.model);if(e.toolName===T){r&&Ne(e.input,r);return}if(e.toolName!==w)return;let i=e.input;if(Pe(i.action))return{block:!0,reason:`Plan mode blocks subagent management action '${i.action}'. Use SPC p e first.`};Ae(i),r&&Me(i,r)}),e.on(`before_agent_start`,async(e,t)=>{let n=[];if(b){let e=(0,o.getHarnessState)().root??t.cwd,r=(0,o.resolvePlanningPlansDirectory)(C?.plansDirectory,e,ee.default.homedir());n.push(`[PLAN MODE ACTIVE]\nYou are in repository read-only plan mode. The dedicated write_plan tool may write one unique Markdown plan file under ${r}.\n\nExplore the codebase and produce a concrete implementation plan. For every plan, first call subagent with action "agents", cluster the exploration by independent domain, subsystem, or integration boundary, and create a provisional task graph with the task tool. Select specialized agents by matching their names and descriptions to each cluster. Assign every unblocked delegated task through the task tool, and use a one-shot inlineAgent with a focused systemPrompt when no discovered specialist fits. Treat the initial graph as provisional, not as a fixed contract. After findings arrive, review the entire graph at least once and perform one to three review passes in total. In each pass, use the evidence to add, rewrite, delete, cancel, reassign, or change blockedBy relationships for tasks when warranted. Do not keep following tasks that new information has made stale. Stop revising early when the graph is stable, or after the third pass.\n\nEvery plan must end with a delegated planning-draft stage blocked by all exploration and decision tasks. A single-boundary plan gets one planning draft. A complex plan spanning multiple subsystems, domains, packages, apps, or integration boundaries gets two planning drafts concurrently. Use three concurrent drafts instead when the work is cross-layer, migration-sensitive, security-sensitive, or similarly high risk. Assign each draft through the task tool to the discovered "planner" agent with context "fork" so it receives the conversation and gathered evidence. If the planner agent is unavailable, assign the same draft task through the task tool with a focused inlineAgent. All children receive read, Bash, grep, find, ls, and configured MCP tools with artifacts disabled. Bash and MCP tools are for read-only inspection and must not modify files, external systems, or repository state. Doom Team runs asynchronously, so do not poll. After launch, continue non-overlapping exploration or end the turn and wait for completion notifications.\n\nAfter all planning drafts complete, the main agent must compare the candidates, pick the strongest draft, cross-check it against the gathered evidence and the other drafts, resolve conflicts and gaps, and ask the user only for product decisions. A child produces the draft, but the main agent owns and synthesizes the final plan. Do not modify files or repository state except through write_plan. Start the final plan with a meaningful Markdown H1 because write_plan derives the filename from it. Present the complete plan as visible Markdown in chat, then call write_plan with no arguments. After write_plan succeeds, clear the completed durable task graph and call complete_plan so the user can review the plan and choose whether to begin implementation or continue planning. Do not exit plan mode without that approval.`,i.buildFlavorPlanningPrompt(x,r,V,H))}if(F&&n.push(`[CURRENT PLAN]\nSource: ${F.path}\n\n${F.content}`),n.length!==0)return{systemPrompt:`${e.systemPrompt}\n\n${n.join(`
4
+
5
+ `)}`}}),e.on(`context`,async e=>({messages:e.messages.filter(e=>e.customType!==`agent-harness-plan-mode-context`)})),e.on(`session_start`,async(t,n)=>{let r=n.sessionManager.getEntries(),i=r.flatMap(e=>e.type===`custom`&&e.customType===_?[Se(e.data)]:[]).filter(e=>e!==void 0).at(-1),a=he(n.sessionManager.getSessionId()),o=r.flatMap(e=>e.type===`custom`&&e.customType===re?[Ce(e.data)]:[]).filter(e=>e!==void 0).at(-1),s=S;if(O?.dispose(),O=void 0,F=o?.sessionId===a?o:void 0,L=i?.planId??F?.planId,R=!1,C=void 0,V=void 0,b=!1,x=void 0,Oe(),S=i?.originalSnapshot,U=i?.interruptedFableStage,H=U?`interrupted`:`idle`,W=n,i?.activeFlavor)await $(n,i.activeFlavor,`session_restore`,!0);else{let t=i?.originalSnapshot??s;t?await Be(n,t)&&e.setActiveTools([...t.tools]):e.setActiveTools(e.getActiveTools().filter(e=>e!==v&&e!==y&&e!==E&&e!==D)),S=void 0,Y(n)}}),e.on(`session_shutdown`,async(t,n)=>{await He(`Plan host session is shutting down.`),b&&S&&await Be(n,S)&&e.setActiveTools([...S.tools]),O?.dispose(),O=void 0,Ee.dispose(),W=void 0,await c.shutdown()})}exports.WRITE_PLAN_TIMEOUT_MS=P,exports.configurePlanningSubagentInput=Me,exports.configurePlanningTaskInput=Ne,exports.constrainSubagentInput=Ae,exports.createPlanIdentifier=z,exports.isBlockedSubagentManagementAction=Pe,exports.loadPlanningModeConfig=Ie,exports.parseDebugEvidencePacket=De,exports.parsePersistedPlanState=Se,exports.planModeExtension=Re,exports.planModeTools=Oe,exports.planSessionIdentifier=he,exports.planTitleSlug=me,exports.planningSubagentModel=je,exports.visiblePlanForToolCall=ge;
6
+ //# sourceMappingURL=planMode.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planMode.cjs","names":["Buffer","loadDoomConfig","createPlanTelemetry","CONTRACT_FABLE_PLAN_REQUESTER","planConfigSections","CONFIG_ACTION","planSettingByFieldId","FABLE_PLAN_PROFILE","PLAN_EVENT","createFablePlanFlow","os","path","fs","buildFlavorPlanningPrompt","custom"],"sources":["../src/planMode.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport { createHash, randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { globalDoomConfigPath } from '@agimon-ai/doompi-config';\nimport { setDoomConfigValue, unsetDoomConfigValue } from '@agimon-ai/doompi-config/configWriter';\nimport { CONFIG_ACTION, registerDoomConfigContribution } from '@agimon-ai/doompi-ui/config';\nimport {\n createDoomLeaderContribution,\n registerDoomLeaderActionHandlers,\n type DoomLeaderBinding,\n} from '@agimon-ai/doompi-ui/leader';\nimport { registerDoomModeContribution } from '@agimon-ai/doompi-ui/mode';\nimport { createProtocolRuntime } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport {\n createFablePlanBrokerClient,\n FABLE_PLAN_REQUESTER as CONTRACT_FABLE_PLAN_REQUESTER,\n} from '@agimon-ai/doompi-extension-contracts/fable-plan';\nimport {\n registerSubagentPolicy,\n type SubagentPolicyHandle,\n} from '@agimon-ai/doompi-extension-contracts/subagent-policy';\nimport { isSubagentAction, subagentActionAcceptsField } from '@agimon-ai/doompi-extension-contracts/subagent-tool';\nimport type { ExtensionAPI, ExtensionContext, ToolCallEvent } from '@earendil-works/pi-coding-agent';\nimport {\n getHarnessState,\n loadDoomConfig,\n loadHarnessState,\n resolvePlanningPlansDirectory,\n type PlanningAgentConfig,\n type PlanningModeConfig,\n type PlanningThinkingLevel,\n} from './config.ts';\nimport { planConfigSections, planSettingByFieldId } from './planConfig.ts';\nimport {\n createFablePlanFlow,\n FABLE_PLAN_PROFILE,\n type FablePlanBroker,\n type FablePlanResult,\n type FableStage,\n} from './fableFlow.ts';\nimport { buildFlavorPlanningPrompt, type DebugEvidencePacket, type PlanningFlavor } from './prompts.ts';\nimport { createPlanTelemetry, PLAN_EVENT, type PlanTelemetry } from './logSinkTelemetry.ts';\n\nconst PLAN_MODE_ENTRY = 'agent-harness-plan-mode';\nconst PLAN_MODE_CONTEXT = 'agent-harness-plan-mode-context';\nconst PLAN_DOCUMENT_ENTRY = 'agent-harness-plan-document';\nconst COMPLETE_PLAN_TOOL = 'complete_plan';\nconst WRITE_PLAN_TOOL = 'write_plan';\nconst ASK_USER_TOOL = 'ask_user_question';\nconst BASH_TOOL = 'bash';\nconst FIND_TOOL = 'find';\nconst GREP_TOOL = 'grep';\nconst LIST_TOOL = 'ls';\nconst MCP_TOOL = 'mcp';\nconst READ_TOOL = 'read';\nconst SUBAGENT_TOOL = 'subagent';\nconst TASK_TOOL = 'task';\nconst RECORD_DEBUG_EVIDENCE_TOOL = 'record_debug_evidence';\nconst RUN_FABLE_PLAN_TOOL = 'run_fable_plan';\nconst DEFAULT_PLAN_TITLE = 'implementation-plan';\nconst PLAN_TITLE_MAX_LENGTH = 64;\nconst SESSION_ID_MAX_LENGTH = 48;\nconst PLAN_MODE_STATUS_KEY = 'plan-mode';\nconst PLAN_LEADER_SOURCE = '@agimon-ai/doompi-plan';\nconst PLAN_LEADER_GROUP_ORDER = 60;\n/** This mode's slot on the shared mode line doom-pi-ui renders. */\nconst MODE_CONTRIBUTION_ID = 'plan';\n/** Just the name; the flavour and read-only state ride along as detail. */\nconst MODE_LABEL = 'PLAN';\nconst READ_ONLY_DETAIL = 'read only';\n/** Between workflow mode and the loop, matching the leader order. */\nconst MODE_CONTRIBUTION_ORDER = 40;\nconst WARNING_STYLE = 'warning';\nconst INFO_STYLE = 'info';\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst PLAN_ALLOCATION_ATTEMPTS = 3;\nconst INVALID_PLAN_DESTINATION = 'Refused to write the plan because its destination is not a regular file.';\nconst PLAN_TRIGGER_ATTRIBUTE = 'plan.trigger';\nconst PLAN_MODEL_ATTRIBUTE = 'plan.model';\nconst PLAN_FLAVOR_ATTRIBUTE = 'plan.flavor';\nconst MODEL_NOT_FOUND_REASON = 'not_found';\nconst MODEL_UNAUTHENTICATED_REASON = 'unauthenticated';\nconst MODEL_RESTORE_FAILED_REASON = 'restore_failed';\nconst DEBUG_EVIDENCE_MAX_BYTES = 32 * 1024;\nconst DEBUG_EVIDENCE_MAX_TEXT_BYTES = 4 * 1024;\nconst DEBUG_EVIDENCE_MAX_ITEMS = 32;\nconst DEBUG_DIAGNOSTIC_TOOLS = new Set<string>();\nexport const WRITE_PLAN_TIMEOUT_MS = 5_000;\nconst EXIT_PLAN_MODE_CHOICE = 'Exit plan mode and start implementation';\nconst CONTINUE_PLANNING_CHOICE = 'Continue planning';\nconst PLAN_MODE_PARENT_TOOLS = new Set([\n 'add_directory',\n ASK_USER_TOOL,\n BASH_TOOL,\n COMPLETE_PLAN_TOOL,\n FIND_TOOL,\n GREP_TOOL,\n 'intercom',\n LIST_TOOL,\n READ_TOOL,\n 'search_external_files',\n SUBAGENT_TOOL,\n 'subagent_supervisor',\n 'subagent_wait',\n TASK_TOOL,\n WRITE_PLAN_TOOL,\n]);\nconst PLAN_MODE_EXPLORATION_TOOLS = [READ_TOOL, BASH_TOOL, GREP_TOOL, FIND_TOOL, LIST_TOOL] as const;\nconst CHILD_EXPLORATION_TOOLS = [...PLAN_MODE_EXPLORATION_TOOLS, MCP_TOOL] as const;\nconst PLAN_MODE_TRIGGER_LEADER = 'leader' as const;\nconst PLAN_MODE_TRIGGER_SESSION_RESTORE = 'session_restore' as const;\nconst PLAN_MODE_TRIGGER_PLAN_APPROVED = 'plan_approved' as const;\nconst PLAN_MODE_TRIGGER_SESSION_SHUTDOWN = 'session_shutdown' as const;\nconst PLAN_STATE_VERSION = 2 as const;\nconst VALID_THINKING_LEVELS: readonly PlanningThinkingLevel[] = [\n 'off',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'max',\n];\nconst VALID_FABLE_STAGES: readonly FableStage[] = [\n 'idle',\n 'draft',\n 'review',\n 'completed',\n 'failed',\n 'cancelled',\n 'interrupted',\n];\n\nexport type { PlanningFlavor } from './prompts.ts';\n\nexport interface ModelIdentity {\n provider: string;\n id: string;\n}\n\nexport interface PlanSnapshot {\n tools: string[];\n model?: ModelIdentity;\n thinking: PlanningThinkingLevel;\n}\n\ninterface PersistedPlanModeState {\n version: typeof PLAN_STATE_VERSION;\n activeFlavor?: PlanningFlavor;\n originalSnapshot?: PlanSnapshot;\n planId?: string;\n interruptedFableStage?: FableStage;\n}\n\ninterface PlanDocument {\n content: string;\n path: string;\n sessionId: string;\n planId?: string;\n title: string;\n writtenAt: string;\n}\n\ntype PlanWritePhase = 'checking' | 'writing';\n\n/** Why plan mode changed state, so the sink can tell a user toggle from a session restore. */\ntype PlanModeTrigger =\n | typeof PLAN_MODE_TRIGGER_LEADER\n | typeof PLAN_MODE_TRIGGER_SESSION_RESTORE\n | typeof PLAN_MODE_TRIGGER_PLAN_APPROVED\n | typeof PLAN_MODE_TRIGGER_SESSION_SHUTDOWN;\n\nexport interface PlanModeExtensionOptions {\n fableBroker?: FablePlanBroker;\n debugDiagnosticTools?: readonly string[];\n doomIntegrations?: boolean;\n}\n\nexport function planTitleSlug(markdown: string): string {\n const heading = markdown.match(/^#\\s+(.+?)\\s*$/m)?.[1] ?? DEFAULT_PLAN_TITLE;\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\nexport function planSessionIdentifier(sessionId: string): string {\n const readable = encodeURIComponent(sessionId).slice(0, SESSION_ID_MAX_LENGTH) || 'session';\n const digest = createHash('sha256').update(sessionId).digest('hex');\n return `${readable}--${digest}`;\n}\n\nexport function createPlanIdentifier(now = new Date(), id = randomUUID()): string {\n const timestamp = now\n .toISOString()\n .replace(/[-:]/g, '')\n .replace(/\\.\\d{3}Z$/, 'Z');\n return `${timestamp}--${id}`;\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 abortReason(signal: AbortSignal): Error {\n return signal.reason instanceof Error ? signal.reason : new Error('Plan write cancelled.');\n}\n\nasync function waitForAbortable<T>(operation: () => Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) throw abortReason(signal);\n let onAbort: (() => void) | undefined;\n const aborted = new Promise<never>((_resolve, reject) => {\n onAbort = () => reject(abortReason(signal));\n signal.addEventListener('abort', onAbort, { once: true });\n });\n try {\n return await Promise.race([operation(), aborted]);\n } finally {\n if (onAbort) signal.removeEventListener('abort', onAbort);\n }\n}\n\ntype MutableSubagentStep = {\n model?: string;\n output?: string | boolean;\n progress?: boolean;\n worktree?: boolean;\n parallel?: MutableSubagentStep | MutableSubagentStep[];\n};\n\ntype MutableSubagentRunRequest = {\n [key: string]: unknown;\n model?: string;\n};\n\ntype MutableSubagentInput = MutableSubagentStep & {\n action?: string;\n artifacts?: boolean;\n outputSchema?: Record<string, unknown>;\n share?: boolean;\n tasks?: MutableSubagentStep[];\n chain?: MutableSubagentStep[];\n chainDir?: string;\n sessionDir?: string;\n requests?: MutableSubagentRunRequest[];\n};\n\ntype MutableTaskInput = {\n action?: string;\n model?: string;\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 parseModelIdentity(value: unknown): ModelIdentity | undefined {\n if (!isRecord(value) || !isString(value.provider) || !isString(value.id)) return undefined;\n if (!value.provider || !value.id || value.provider.length > 128 || value.id.length > 128) return undefined;\n return { provider: value.provider, id: value.id };\n}\n\nfunction parseThinkingLevel(value: unknown): PlanningThinkingLevel | undefined {\n return isString(value) && VALID_THINKING_LEVELS.includes(value as PlanningThinkingLevel)\n ? (value as PlanningThinkingLevel)\n : undefined;\n}\n\nfunction parseFableStage(value: unknown): FableStage | undefined {\n return isString(value) && VALID_FABLE_STAGES.includes(value as FableStage) ? (value as FableStage) : undefined;\n}\n\nfunction parseStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value) || value.some((item) => !isString(item))) return undefined;\n return value.map((item) => item);\n}\n\nfunction parsePlanSnapshot(value: unknown): PlanSnapshot | undefined {\n if (!isRecord(value)) return undefined;\n const tools = parseStringArray(value.tools);\n const thinking = parseThinkingLevel(value.thinking);\n if (!tools || thinking === undefined) return undefined;\n const model = value.model === undefined ? undefined : parseModelIdentity(value.model);\n if (value.model !== undefined && !model) return undefined;\n return { tools, ...(model ? { model } : {}), thinking };\n}\n\nfunction parsePlanningFlavor(value: unknown): PlanningFlavor | undefined {\n return value === 'normal' || value === 'debug' || value === 'fable' ? value : undefined;\n}\n\nfunction parseVersionedPlanState(value: Record<string, unknown>): PersistedPlanModeState | undefined {\n if (value.version !== PLAN_STATE_VERSION) return undefined;\n const activeFlavor = value.activeFlavor === undefined ? undefined : parsePlanningFlavor(value.activeFlavor);\n if (value.activeFlavor !== undefined && !activeFlavor) return undefined;\n const originalSnapshot = value.originalSnapshot === undefined ? undefined : parsePlanSnapshot(value.originalSnapshot);\n if (value.originalSnapshot !== undefined && !originalSnapshot) return undefined;\n const planId = value.planId === undefined ? undefined : isString(value.planId) ? value.planId : undefined;\n if (value.planId !== undefined && planId === undefined) return undefined;\n const interruptedFableStage =\n value.interruptedFableStage === undefined ? undefined : parseFableStage(value.interruptedFableStage);\n if (value.interruptedFableStage !== undefined && !interruptedFableStage) return undefined;\n return {\n version: PLAN_STATE_VERSION,\n ...(activeFlavor ? { activeFlavor } : {}),\n ...(originalSnapshot ? { originalSnapshot } : {}),\n ...(planId ? { planId } : {}),\n ...(interruptedFableStage ? { interruptedFableStage } : {}),\n };\n}\n\nfunction parseLegacyPlanState(value: Record<string, unknown>): PersistedPlanModeState | undefined {\n if (value.enabled !== true && value.enabled !== false) return undefined;\n const tools = value.toolsBeforePlanMode === undefined ? undefined : parseStringArray(value.toolsBeforePlanMode);\n if (value.toolsBeforePlanMode !== undefined && !tools) return undefined;\n const model = value.modelBeforePlanMode === undefined ? undefined : parseModelIdentity(value.modelBeforePlanMode);\n if (value.modelBeforePlanMode !== undefined && !model) return undefined;\n const thinking =\n value.thinkingBeforePlanMode === undefined ? undefined : parseThinkingLevel(value.thinkingBeforePlanMode);\n if (value.thinkingBeforePlanMode !== undefined && thinking === undefined) return undefined;\n const planId = value.planId === undefined ? undefined : isString(value.planId) ? value.planId : undefined;\n if (value.planId !== undefined && planId === undefined) return undefined;\n const originalSnapshot =\n tools && thinking !== undefined ? { tools, ...(model ? { model } : {}), thinking } : undefined;\n return {\n version: PLAN_STATE_VERSION,\n ...(value.enabled ? { activeFlavor: 'normal' as const } : {}),\n ...(originalSnapshot ? { originalSnapshot } : {}),\n ...(planId ? { planId } : {}),\n };\n}\n\nexport function parsePersistedPlanState(value: unknown): PersistedPlanModeState | undefined {\n if (!isRecord(value)) return undefined;\n return parseVersionedPlanState(value) ?? parseLegacyPlanState(value);\n}\n\nfunction parsePlanDocument(value: unknown): PlanDocument | undefined {\n if (!isRecord(value)) return undefined;\n if (!isString(value.content) || !isString(value.path) || !isString(value.sessionId) || !isString(value.title)) {\n return undefined;\n }\n if (!isString(value.writtenAt)) return undefined;\n const planId = value.planId === undefined ? undefined : isString(value.planId) ? value.planId : undefined;\n if (value.planId !== undefined && planId === undefined) return undefined;\n return {\n content: value.content,\n path: value.path,\n sessionId: value.sessionId,\n ...(planId ? { planId } : {}),\n title: value.title,\n writtenAt: value.writtenAt,\n };\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\nexport function planModeTools(activeTools: string[], availableTools: string[]): string[] {\n const available = new Set(availableTools);\n const retained = activeTools.filter((name) => PLAN_MODE_PARENT_TOOLS.has(name));\n const exploration = PLAN_MODE_EXPLORATION_TOOLS.filter((name) => available.has(name));\n const planTools = [ASK_USER_TOOL, COMPLETE_PLAN_TOOL, TASK_TOOL, WRITE_PLAN_TOOL].filter((name) =>\n available.has(name),\n );\n return [...new Set([...retained, ...exploration, ...planTools])];\n}\n\nfunction planningToolsForFlavor(\n snapshotTools: string[],\n availableTools: string[],\n flavor: PlanningFlavor,\n diagnosticTools: ReadonlySet<string>,\n): string[] {\n const available = new Set(availableTools);\n const base = planModeTools(snapshotTools, availableTools);\n const extras =\n flavor === 'debug' ? [RECORD_DEBUG_EVIDENCE_TOOL, ...diagnosticTools].filter((name) => available.has(name)) : [];\n if (flavor === 'fable' && available.has(RUN_FABLE_PLAN_TOOL)) extras.push(RUN_FABLE_PLAN_TOOL);\n return [...new Set([...base, ...extras])];\n}\n\nfunction disableStepOutput(step: MutableSubagentStep): void {\n step.output = false;\n step.progress = false;\n step.worktree = false;\n if (Array.isArray(step.parallel)) {\n for (const child of step.parallel) disableStepOutput(child);\n } else if (step.parallel) {\n disableStepOutput(step.parallel);\n }\n}\n\nexport function constrainSubagentInput(input: MutableSubagentInput): void {\n if (input.action !== undefined) {\n if (isSubagentAction(input.action) && subagentActionAcceptsField(input.action, 'artifacts')) {\n input.artifacts = false;\n }\n return;\n }\n\n input.artifacts = false;\n input.output = false;\n input.share = false;\n input.progress = false;\n input.worktree = false;\n delete input.chainDir;\n delete input.outputSchema;\n delete input.sessionDir;\n for (const task of input.tasks ?? []) disableStepOutput(task);\n for (const step of input.chain ?? []) disableStepOutput(step);\n}\n\nexport function planningSubagentModel(\n config: PlanningAgentConfig | undefined,\n currentModel: ModelIdentity | undefined,\n): string | undefined {\n if (!config?.model && !config?.thinking) return undefined;\n const baseModel = config.model ?? (currentModel ? `${currentModel.provider}/${currentModel.id}` : undefined);\n if (!baseModel) return undefined;\n if (!config.thinking) return baseModel;\n return `${baseModel.replace(/:(?:off|minimal|low|medium|high|xhigh|max)$/, '')}:${config.thinking}`;\n}\n\nexport function configurePlanningSubagentInput(input: MutableSubagentInput, model: string): void {\n if (input.action !== 'run') return;\n for (const request of input.requests ?? []) request.model = model;\n}\n\nexport function configurePlanningTaskInput(input: MutableTaskInput, model: string): void {\n if (input.action === 'assign') input.model = model;\n}\n\nexport function isBlockedSubagentManagementAction(action: string | undefined): boolean {\n return new Set([\n 'append-step',\n 'create',\n 'delete',\n 'disable',\n 'eject',\n 'enable',\n 'grant-spawn-budget',\n 'reset',\n 'schedule',\n 'schedule-cancel',\n 'update',\n 'watchdog.configure',\n ]).has(action ?? '');\n}\n\nfunction resolvePlanningModel(\n modelSpec: string,\n ctx: ExtensionContext,\n): NonNullable<ExtensionContext['model']> | undefined {\n const separator = modelSpec.indexOf('/');\n if (separator > 0) {\n return ctx.modelRegistry.find(modelSpec.slice(0, separator), modelSpec.slice(separator + 1));\n }\n\n const matches = ctx.modelRegistry.getAvailable().filter((model) => model.id === modelSpec);\n return (\n matches.find((model) => model.provider === ctx.model?.provider) ?? (matches.length === 1 ? matches[0] : undefined)\n );\n}\n\nexport type PlanningConfigProvider = () => PlanningModeConfig | undefined;\n\n/** Reads Doom settings from disk so each plan-mode activation sees current configuration. */\nexport function loadPlanningModeConfig(\n environment: NodeJS.ProcessEnv = process.env,\n currentDirectory = process.cwd(),\n): PlanningModeConfig | undefined {\n return loadDoomConfig(loadHarnessState(environment).state.root ?? currentDirectory).modes?.planning;\n}\n\n/**\n * The plan menu as it stands with the mode on or off.\n *\n * `exit` is published only while the mode is on. It is the one entry that can\n * do nothing otherwise, and a menu offering a way out of a mode reads as\n * though you are in it.\n */\nfunction planLeaderBindings(active: boolean): DoomLeaderBinding[] {\n const group = { key: 'p', label: 'plan', order: PLAN_LEADER_GROUP_ORDER } as const;\n return [\n {\n id: 'plan.normal',\n path: [group, { key: 'p', label: 'normal', detail: 'read-only planning' }],\n action: { name: 'plan.normal' },\n },\n {\n id: 'plan.debug',\n path: [group, { key: 'd', label: 'debug', detail: 'adaptive debug planning' }],\n action: { name: 'plan.debug' },\n },\n {\n id: 'plan.fable',\n path: [group, { key: 'f', label: 'fable', detail: 'repository-aware draft' }],\n action: { name: 'plan.fable' },\n },\n ...(active\n ? [\n {\n id: 'plan.exit',\n path: [group, { key: 'e', label: 'exit', detail: 'restore and exit' }] as DoomLeaderBinding['path'],\n action: { name: 'plan.exit' },\n },\n ]\n : []),\n ];\n}\n\nexport function planModeExtension(\n pi: ExtensionAPI,\n planningConfigProvider: PlanningConfigProvider = loadPlanningModeConfig,\n telemetry: PlanTelemetry = createPlanTelemetry(),\n options: PlanModeExtensionOptions = {},\n): void {\n let enabled = false;\n let activeFlavor: PlanningFlavor | undefined;\n let planSnapshot: PlanSnapshot | undefined;\n let activePlanningConfig: PlanningModeConfig | undefined;\n let capabilityCeiling: SubagentPolicyHandle | undefined;\n let currentPlan: PlanDocument | undefined;\n let activePlanId: string | undefined;\n let planReadyForReview = false;\n let debugEvidence: DebugEvidencePacket | undefined;\n let fableStage: FableStage = 'idle';\n let interruptedFableStage: FableStage | undefined;\n let activeContext: ExtensionContext | undefined;\n let activeFableRun: Promise<FablePlanResult> | undefined;\n let transitionQueue: Promise<void> = Promise.resolve();\n const doomIntegrations = options.doomIntegrations ?? true;\n const diagnosticTools = new Set(options.debugDiagnosticTools ?? DEBUG_DIAGNOSTIC_TOOLS);\n const sessionBroker = createFablePlanBrokerClient(() => activeContext?.sessionManager.getSessionId());\n const fableBroker: FablePlanBroker = options.fableBroker ?? {\n start: (request, signal) => sessionBroker.start(request, signal),\n cancel: (operationId, reason) =>\n sessionBroker.cancel({ requester: CONTRACT_FABLE_PLAN_REQUESTER, operationId, reason }),\n };\n const isFableBrokerAvailable = (): boolean => options.fableBroker !== undefined || sessionBroker.isAvailable();\n const modeContribution = doomIntegrations\n ? registerDoomModeContribution(pi, {\n source: PLAN_LEADER_SOURCE,\n id: MODE_CONTRIBUTION_ID,\n order: MODE_CONTRIBUTION_ORDER,\n })\n : { update: () => undefined };\n const leaderContribution = doomIntegrations\n ? createDoomLeaderContribution(pi, {\n source: PLAN_LEADER_SOURCE,\n bindings: planLeaderBindings(false),\n })\n : { update: () => undefined };\n let planConfigNotice: string | undefined;\n const planConfigContribution = doomIntegrations\n ? registerDoomConfigContribution(pi, {\n source: PLAN_LEADER_SOURCE,\n // Read at publish time, not cached: plan mode re-reads this file on every\n // activation anyway, so the panel should show whatever is on disk now.\n listSections: () => {\n try {\n return planConfigSections(planningConfigProvider(), planConfigNotice);\n } catch (error) {\n // A malformed config file must not take session start down with it. The\n // panel is where someone would go to repair it, so it has to still draw.\n return planConfigSections(undefined, error instanceof Error ? error.message : String(error));\n }\n },\n handlers: {\n [CONFIG_ACTION.set]: async ({ fieldId, value }) => {\n const setting = planSettingByFieldId(fieldId);\n if (!setting || !value) return;\n planConfigNotice = undefined;\n await setDoomConfigValue(globalDoomConfigPath(), [...setting.keyPath], value);\n },\n [CONFIG_ACTION.clear]: async ({ fieldId }) => {\n const setting = planSettingByFieldId(fieldId);\n if (!setting) return;\n planConfigNotice = undefined;\n await unsetDoomConfigValue(globalDoomConfigPath(), [...setting.keyPath]);\n },\n },\n onError: (error) => {\n planConfigNotice = error instanceof Error ? error.message : String(error);\n },\n })\n : { dispose: () => undefined, update: () => undefined };\n\n /** Identical bindings are dropped by the handle, so this can ride along with every state change. */\n function updateLeader(): void {\n leaderContribution.update(planLeaderBindings(enabled));\n }\n\n function updateStatus(ctx: ExtensionContext): void {\n updateLeader();\n const flavor = activeFlavor;\n const status = enabled && flavor ? `plan:${flavor}` : undefined;\n const stage = flavor === 'fable' && fableStage !== 'idle' ? ` · ${fableStage}` : '';\n ctx.ui.setStatus(PLAN_MODE_STATUS_KEY, status ? ctx.ui.theme.fg(WARNING_STYLE, status) : undefined);\n // The flavour, the fable stage and the read-only warning are all sub-state\n // of one mode, so they ride in the detail rather than each claiming a slot\n // on a line shared with every other mode: `PLAN (normal - read only)`.\n modeContribution.update(\n enabled && flavor\n ? {\n label: MODE_LABEL,\n detail: `${flavor}${stage} - ${READ_ONLY_DETAIL}`,\n color: WARNING_STYLE,\n }\n : undefined,\n );\n }\n\n function updateCapabilityCeiling(): void {\n if (!doomIntegrations || !enabled || !activeFlavor || !activeContext) return;\n const allowedTools = [...CHILD_EXPLORATION_TOOLS];\n const allowedExternalProfiles = activeFlavor === 'fable' ? [FABLE_PLAN_PROFILE] : [];\n const policy = {\n owner: PLAN_LEADER_SOURCE,\n allowedTools,\n requiredTools: [BASH_TOOL, MCP_TOOL],\n allowMcpTools: true,\n allowedExternalProfiles,\n denyExtensions: false,\n };\n if (capabilityCeiling) capabilityCeiling.update(policy);\n else {\n capabilityCeiling = registerSubagentPolicy(\n createProtocolRuntime({\n bus: pi.events,\n source: PLAN_LEADER_SOURCE,\n sessionId: activeContext.sessionManager.getSessionId(),\n }),\n policy,\n );\n }\n }\n\n function persistState(): void {\n pi.appendEntry(PLAN_MODE_ENTRY, {\n version: PLAN_STATE_VERSION,\n ...(enabled && activeFlavor ? { activeFlavor } : {}),\n ...(planSnapshot\n ? {\n originalSnapshot: {\n tools: [...planSnapshot.tools],\n ...(planSnapshot.model ? { model: { ...planSnapshot.model } } : {}),\n thinking: planSnapshot.thinking,\n },\n }\n : {}),\n ...(activePlanId ? { planId: activePlanId } : {}),\n ...(interruptedFableStage ? { interruptedFableStage } : {}),\n } satisfies PersistedPlanModeState);\n }\n\n function reportModelFailure(\n phase: 'apply' | 'restore',\n model: string,\n reason: typeof MODEL_NOT_FOUND_REASON | typeof MODEL_UNAUTHENTICATED_REASON | typeof MODEL_RESTORE_FAILED_REASON,\n ): void {\n void telemetry.recordWarning(PLAN_EVENT.modelResolveFailed, `Planning model ${reason}: ${model}`, {\n [PLAN_MODEL_ATTRIBUTE]: model,\n 'plan.model.phase': phase,\n 'plan.model.reason': reason,\n });\n }\n\n async function applyMainPlanningConfig(ctx: ExtensionContext): Promise<void> {\n const config = activePlanningConfig?.main;\n if (!config) return;\n if (config.model) {\n const model = resolvePlanningModel(config.model, ctx);\n if (!model) {\n ctx.ui.notify(`Planning model not found: ${config.model}`, WARNING_STYLE);\n reportModelFailure('apply', config.model, MODEL_NOT_FOUND_REASON);\n } else if (!(await pi.setModel(model))) {\n ctx.ui.notify(`Planning model is unavailable without authentication: ${config.model}`, WARNING_STYLE);\n reportModelFailure('apply', config.model, MODEL_UNAUTHENTICATED_REASON);\n }\n }\n if (config.thinking) pi.setThinkingLevel(config.thinking);\n }\n\n async function restoreMainAgent(ctx: ExtensionContext, snapshot: PlanSnapshot | undefined): Promise<boolean> {\n if (!snapshot) return false;\n if (snapshot.model) {\n const identity = `${snapshot.model.provider}/${snapshot.model.id}`;\n const model = ctx.modelRegistry.find(snapshot.model.provider, snapshot.model.id);\n if (!model) {\n ctx.ui.notify(`Previous model not found: ${identity}`, WARNING_STYLE);\n reportModelFailure('restore', identity, MODEL_NOT_FOUND_REASON);\n return false;\n }\n try {\n if (!(await pi.setModel(model))) {\n ctx.ui.notify(`Previous model is unavailable without authentication: ${identity}`, WARNING_STYLE);\n reportModelFailure('restore', identity, MODEL_UNAUTHENTICATED_REASON);\n return false;\n }\n } catch (error) {\n ctx.ui.notify(`Previous model could not be restored: ${identity}`, WARNING_STYLE);\n reportModelFailure('restore', identity, MODEL_RESTORE_FAILED_REASON);\n void telemetry.recordError(PLAN_EVENT.modelResolveFailed, error, {\n [PLAN_MODEL_ATTRIBUTE]: identity,\n 'plan.model.phase': 'restore',\n 'plan.model.reason': MODEL_RESTORE_FAILED_REASON,\n });\n return false;\n }\n }\n pi.setThinkingLevel(snapshot.thinking);\n return true;\n }\n\n function reportCurrentFlavor(ctx: ExtensionContext): void {\n if (enabled && activeFlavor) ctx.ui.notify(`Already in plan:${activeFlavor}.`, INFO_STYLE);\n else ctx.ui.notify('Plan mode is inactive.', INFO_STYLE);\n }\n\n function queueTransition<T>(transition: () => Promise<T>): Promise<T> {\n const queued = transitionQueue.then(transition, transition);\n transitionQueue = queued.then(\n () => undefined,\n () => undefined,\n );\n return queued;\n }\n\n async function cancelFableOperation(reason: string): Promise<void> {\n if (!activeFableRun && !fableStage.match(/^(draft|review)$/u)) return;\n if (fableStage === 'draft' || fableStage === 'review') interruptedFableStage = fableStage;\n fableFlow.cancel(reason);\n const pending = activeFableRun;\n if (pending) {\n try {\n await pending;\n } catch (error) {\n void telemetry.recordError(PLAN_EVENT.modeDisabled, error, {\n [PLAN_FLAVOR_ATTRIBUTE]: 'fable',\n 'plan.fable.reason': 'cancel_failed',\n });\n }\n }\n activeFableRun = undefined;\n if (interruptedFableStage) fableStage = 'interrupted';\n if (activeContext) updateStatus(activeContext);\n persistState();\n }\n\n async function activateFlavor(\n ctx: ExtensionContext,\n flavor: PlanningFlavor,\n trigger: PlanModeTrigger,\n restoring: boolean,\n ): Promise<void> {\n activeContext = ctx;\n if (enabled) {\n if (activeFlavor === flavor) {\n reportCurrentFlavor(ctx);\n return;\n }\n if (activeFlavor === 'fable') await cancelFableOperation(`Leaving Fable for plan:${flavor}.`);\n activeFlavor = flavor;\n updateCapabilityCeiling();\n pi.setActiveTools(\n planningToolsForFlavor(\n planSnapshot?.tools ?? [],\n pi.getAllTools().map((tool) => tool.name),\n flavor,\n diagnosticTools,\n ),\n );\n updateStatus(ctx);\n persistState();\n void telemetry.recordEvent(PLAN_EVENT.modeEnabled, {\n [PLAN_TRIGGER_ATTRIBUTE]: trigger,\n [PLAN_FLAVOR_ATTRIBUTE]: flavor,\n 'plan.tool.count': pi.getActiveTools().length,\n });\n return;\n }\n\n let nextPlanningConfig: PlanningModeConfig | undefined;\n try {\n nextPlanningConfig = planningConfigProvider();\n } catch (error) {\n void telemetry.recordError(PLAN_EVENT.configLoadFailed, error, { [PLAN_TRIGGER_ATTRIBUTE]: trigger });\n throw error;\n }\n\n if (!restoring) {\n currentPlan = undefined;\n planReadyForReview = false;\n activePlanId = createPlanIdentifier();\n interruptedFableStage = undefined;\n fableStage = 'idle';\n } else {\n activePlanId ??= createPlanIdentifier();\n }\n activePlanningConfig = nextPlanningConfig;\n planSnapshot ??= {\n tools: [...pi.getActiveTools()],\n ...(ctx.model ? { model: { provider: ctx.model.provider, id: ctx.model.id } } : {}),\n thinking: pi.getThinkingLevel(),\n };\n enabled = true;\n activeFlavor = flavor;\n pi.setActiveTools(\n planningToolsForFlavor(\n planSnapshot.tools,\n pi.getAllTools().map((tool) => tool.name),\n flavor,\n diagnosticTools,\n ),\n );\n updateCapabilityCeiling();\n await applyMainPlanningConfig(ctx);\n updateStatus(ctx);\n persistState();\n void telemetry.recordEvent(PLAN_EVENT.modeEnabled, {\n [PLAN_TRIGGER_ATTRIBUTE]: trigger,\n [PLAN_FLAVOR_ATTRIBUTE]: flavor,\n 'plan.tool.count': pi.getActiveTools().length,\n ...(activePlanningConfig?.main?.model ? { [PLAN_MODEL_ATTRIBUTE]: activePlanningConfig.main.model } : {}),\n ...(activePlanningConfig?.main?.thinking ? { 'plan.thinking': activePlanningConfig.main.thinking } : {}),\n });\n }\n\n async function exitPlanMode(ctx: ExtensionContext, trigger: PlanModeTrigger): Promise<boolean> {\n if (!enabled) {\n reportCurrentFlavor(ctx);\n return false;\n }\n await cancelFableOperation('Plan mode is exiting.');\n const snapshot = planSnapshot;\n const restored = await restoreMainAgent(ctx, snapshot);\n if (!restored) {\n ctx.ui.notify('Previous model was not restored. Plan mode remains read-only.', WARNING_STYLE);\n updateStatus(ctx);\n persistState();\n void telemetry.recordWarning(PLAN_EVENT.modeDisabled, 'Plan mode restoration failed.', {\n [PLAN_TRIGGER_ATTRIBUTE]: trigger,\n [PLAN_FLAVOR_ATTRIBUTE]: activeFlavor ?? 'unknown',\n 'plan.restored': false,\n });\n return false;\n }\n\n const hadPlan = Boolean(currentPlan);\n pi.setActiveTools([...(snapshot?.tools ?? [])]);\n capabilityCeiling?.dispose();\n capabilityCeiling = undefined;\n enabled = false;\n activeFlavor = undefined;\n activePlanningConfig = undefined;\n planSnapshot = undefined;\n debugEvidence = undefined;\n fableStage = 'idle';\n interruptedFableStage = undefined;\n updateStatus(ctx);\n persistState();\n void telemetry.recordEvent(PLAN_EVENT.modeDisabled, {\n [PLAN_TRIGGER_ATTRIBUTE]: trigger,\n [PLAN_FLAVOR_ATTRIBUTE]: 'normal',\n 'plan.written': hadPlan,\n 'plan.restored': true,\n });\n return true;\n }\n\n const fableFlow = createFablePlanFlow({\n broker: fableBroker,\n isAuthorized: () => enabled && activeFlavor === 'fable' && isFableBrokerAvailable(),\n onStage: (stage) => {\n fableStage = stage;\n if (stage === 'completed' || stage === 'failed' || stage === 'cancelled') interruptedFableStage = undefined;\n if (activeContext) updateStatus(activeContext);\n if (enabled) persistState();\n },\n onError: (error) => {\n void telemetry.recordError(PLAN_EVENT.modeEnabled, error, {\n [PLAN_FLAVOR_ATTRIBUTE]: 'fable',\n 'plan.fable.reason': 'flow_error',\n });\n },\n });\n\n pi.registerTool({\n name: RECORD_DEBUG_EVIDENCE_TOOL,\n label: 'Record Debug Evidence',\n description: 'Record optional bounded debug evidence while planning a repository fix.',\n promptSnippet: 'Record the issue and any relevant reproduction, logs, traces, process output, or browser evidence',\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 async execute(_toolCallId, params) {\n if (!enabled || activeFlavor !== 'debug') {\n return { content: [{ type: 'text', text: 'Debug planning is not active.' }], details: { recorded: false } };\n }\n try {\n debugEvidence = parseDebugEvidencePacket(params);\n } catch (error) {\n void telemetry.recordWarning(PLAN_EVENT.modeEnabled, error, {\n [PLAN_FLAVOR_ATTRIBUTE]: 'debug',\n 'plan.debug.reason': 'invalid_evidence',\n });\n throw error;\n }\n if (activeContext) updateStatus(activeContext);\n return {\n content: [{ type: 'text', text: 'Debug evidence recorded as optional planning context.' }],\n details: { recorded: true },\n };\n },\n });\n\n pi.registerTool({\n name: RUN_FABLE_PLAN_TOOL,\n label: 'Run Fable Plan',\n description: 'Send a bounded, sanitized planning packet to the local Fable broker for one repository-aware draft.',\n promptSnippet: 'Run the local Fable draft with the bounded planning packet',\n parameters: {\n type: 'object',\n properties: {\n goal: { type: 'array', items: { type: 'string' } },\n constraints: { type: 'array', items: { type: 'string' } },\n decisions: { type: 'array', items: { type: 'string' } },\n verifiedFindings: { type: 'array', items: { type: 'object' } },\n inferredFindings: { type: 'array', items: { type: 'string' } },\n unresolvedQuestions: { type: 'array', items: { type: 'string' } },\n currentPlan: { type: 'string' },\n },\n additionalProperties: false,\n },\n async execute(_toolCallId, params, signal) {\n if (!enabled || activeFlavor !== 'fable') {\n return {\n content: [{ type: 'text', text: 'Fable planning is not active.' }],\n details: { started: false } as Record<string, unknown>,\n };\n }\n if (!isFableBrokerAvailable()) {\n return {\n content: [{ type: 'text', text: 'The local Fable broker is unavailable. Fable planning remains disabled.' }],\n details: { started: false, errorCode: 'broker_unavailable' } as Record<string, unknown>,\n };\n }\n const operation = fableFlow.run(params, signal);\n activeFableRun = operation;\n try {\n const result = await operation;\n const text = result.draft\n ? `Fable draft:\\n${result.draft}`\n : `Fable planning ${result.status}: ${result.errorCode ?? 'no output'}.`;\n return {\n content: [{ type: 'text', text }],\n details: { ...result, started: true } as Record<string, unknown>,\n };\n } finally {\n if (activeFableRun === operation) activeFableRun = undefined;\n }\n },\n });\n\n pi.registerTool({\n name: WRITE_PLAN_TOOL,\n label: 'Write Plan',\n description:\n 'After presenting the complete implementation plan as Markdown in chat, save that visible plan to a unique Markdown file in the configured plans directory.',\n promptSnippet: 'Save the implementation plan already presented in chat to the configured plans directory',\n parameters: { type: 'object', properties: {}, additionalProperties: false },\n async execute(toolCallId, _params, signal, onUpdate, ctx) {\n if (!enabled) {\n return {\n content: [{ type: 'text', text: 'Plan mode is disabled. Use normal file tools instead.' }],\n details: { written: false },\n };\n }\n const content = visiblePlanForToolCall(ctx.sessionManager.getBranch(), toolCallId);\n if (!content) {\n const error = new Error(\n 'Present the complete implementation plan as visible Markdown in chat before calling write_plan.',\n );\n void telemetry.recordError(PLAN_EVENT.writePlanFailed, error, { 'plan.reason': 'missing_visible_plan' });\n throw error;\n }\n\n const startedAt = Date.now();\n const repoRoot = getHarnessState().root ?? ctx.cwd;\n const plansDirectory = resolvePlanningPlansDirectory(\n activePlanningConfig?.plansDirectory,\n repoRoot,\n os.homedir(),\n );\n const sessionId = planSessionIdentifier(ctx.sessionManager.getSessionId());\n activePlanId ??= createPlanIdentifier();\n const storedPlanPath =\n currentPlan?.planId === activePlanId && path.dirname(currentPlan.path) === plansDirectory\n ? currentPlan.path\n : undefined;\n const title = planTitleSlug(content);\n let planId = activePlanId;\n let planPath = storedPlanPath ?? path.join(plansDirectory, `${title}--${planId}.md`);\n const timeoutController = new AbortController();\n const timeoutError = new Error(`Writing ${planPath} timed out after ${WRITE_PLAN_TIMEOUT_MS}ms.`);\n const timeout = setTimeout(() => timeoutController.abort(timeoutError), WRITE_PLAN_TIMEOUT_MS);\n const writeSignal = signal ? AbortSignal.any([signal, timeoutController.signal]) : timeoutController.signal;\n let phase: PlanWritePhase = 'checking';\n const reportPhase = (): void => {\n onUpdate?.({\n content: [{ type: 'text', text: `${phase === 'checking' ? 'Checking' : 'Writing'} ${planPath}...` }],\n details: { phase, path: planPath, startedAt },\n });\n };\n const recordRefusal = (refusal: string, message: string): void => {\n void telemetry.recordWarning(PLAN_EVENT.writePlanUnsafePath, message, {\n 'plan.phase': phase,\n 'plan.refusal': refusal,\n });\n };\n\n try {\n reportPhase();\n try {\n await waitForAbortable(\n () => fs.promises.mkdir(plansDirectory, { recursive: true, mode: PRIVATE_DIRECTORY_MODE }),\n writeSignal,\n );\n } catch (error) {\n if (writeSignal.aborted) throw abortReason(writeSignal);\n throw new Error(`Could not create the configured plans directory ${plansDirectory}.`, { cause: error });\n }\n const directoryStats = await waitForAbortable(() => fs.promises.lstat(plansDirectory), writeSignal);\n const resolvedPlansDirectory = await waitForAbortable(() => fs.promises.realpath(plansDirectory), writeSignal);\n if (directoryStats.isSymbolicLink() || !directoryStats.isDirectory()) {\n recordRefusal('unsafe_plans_directory', 'Refused to write the plan because the configured path is unsafe.');\n return {\n content: [{ type: 'text', text: 'Refused to write the plan because the configured path is unsafe.' }],\n details: { written: false, path: planPath, phase, durationMs: Date.now() - startedAt },\n };\n }\n\n phase = 'writing';\n reportPhase();\n let planFile: Awaited<ReturnType<typeof fs.promises.open>> | undefined;\n try {\n for (let attempt = 0; attempt < PLAN_ALLOCATION_ATTEMPTS; attempt += 1) {\n try {\n const createFlags = storedPlanPath ? 0 : fs.constants.O_EXCL;\n planFile = await waitForAbortable(\n () =>\n fs.promises.open(\n planPath,\n fs.constants.O_CREAT |\n fs.constants.O_WRONLY |\n fs.constants.O_NONBLOCK |\n fs.constants.O_NOFOLLOW |\n createFlags,\n PRIVATE_FILE_MODE,\n ),\n writeSignal,\n );\n break;\n } catch (error) {\n const collision =\n !storedPlanPath && error instanceof Error && 'code' in error && String(error.code) === 'EEXIST';\n if (!collision || attempt === PLAN_ALLOCATION_ATTEMPTS - 1) throw error;\n planId = createPlanIdentifier();\n activePlanId = planId;\n planPath = path.join(plansDirectory, `${title}--${planId}.md`);\n persistState();\n }\n }\n if (!planFile) throw new Error(`Could not allocate a unique plan filename in ${plansDirectory}.`);\n const resolvedAfterOpen = await waitForAbortable(() => fs.promises.realpath(plansDirectory), writeSignal);\n const stats = await waitForAbortable(() => planFile!.stat(), writeSignal);\n if (resolvedAfterOpen !== resolvedPlansDirectory || !stats.isFile() || stats.nlink !== 1) {\n recordRefusal('invalid_destination', INVALID_PLAN_DESTINATION);\n return {\n content: [{ type: 'text', text: INVALID_PLAN_DESTINATION }],\n details: { written: false, path: planPath, phase, durationMs: Date.now() - startedAt },\n };\n }\n await waitForAbortable(() => planFile!.truncate(0), writeSignal);\n await waitForAbortable(\n () => planFile!.writeFile(content, { encoding: 'utf8', signal: writeSignal }),\n writeSignal,\n );\n } catch (error) {\n if (error instanceof Error && 'code' in error && ['EISDIR', 'ELOOP', 'ENXIO'].includes(String(error.code))) {\n recordRefusal('invalid_destination', INVALID_PLAN_DESTINATION);\n return {\n content: [{ type: 'text', text: INVALID_PLAN_DESTINATION }],\n details: { written: false, path: planPath, phase, durationMs: Date.now() - startedAt },\n };\n }\n throw error;\n } finally {\n await planFile?.close();\n }\n currentPlan = { content, path: planPath, sessionId, planId, title, writtenAt: new Date().toISOString() };\n pi.appendEntry(PLAN_DOCUMENT_ENTRY, currentPlan);\n planReadyForReview = true;\n void telemetry.recordEvent(PLAN_EVENT.planWritten, {\n 'plan.written': true,\n 'plan.bytes': Buffer.byteLength(content, 'utf8'),\n 'plan.duration_ms': Date.now() - startedAt,\n 'plan.revised': Boolean(storedPlanPath),\n });\n return {\n content: [{ type: 'text', text: `Wrote implementation plan to ${planPath}.` }],\n details: { written: true, path: planPath, phase, durationMs: Date.now() - startedAt },\n };\n } catch (error) {\n const attributes = {\n 'plan.phase': phase,\n 'plan.duration_ms': Date.now() - startedAt,\n };\n if (timeoutController.signal.aborted && !signal?.aborted) {\n const timedOut = new Error(`write_plan timed out during ${phase} for ${planPath}.`, { cause: error });\n void telemetry.recordError(PLAN_EVENT.writePlanTimedOut, timedOut, {\n ...attributes,\n 'plan.timeout_ms': WRITE_PLAN_TIMEOUT_MS,\n });\n throw timedOut;\n }\n void telemetry.recordError(PLAN_EVENT.writePlanFailed, error, {\n ...attributes,\n 'plan.cancelled': signal?.aborted ?? false,\n });\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n },\n });\n\n pi.registerTool({\n name: COMPLETE_PLAN_TOOL,\n label: 'Complete Plan',\n description:\n 'Use only after presenting a concrete implementation plan. Ask the user whether to exit plan mode and begin implementation or continue planning.',\n promptSnippet: 'Ask the user whether to exit plan mode after the implementation plan is complete',\n parameters: { type: 'object', properties: {}, additionalProperties: false },\n async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {\n if (!enabled) {\n return {\n content: [{ type: 'text', text: 'Plan mode is already disabled.' }],\n details: { exited: false },\n };\n }\n if (!planReadyForReview) {\n return {\n content: [\n {\n type: 'text',\n text: 'Present the complete plan in chat and save it with write_plan before requesting approval.',\n },\n ],\n details: { exited: false },\n };\n }\n if (!ctx.hasUI) {\n void telemetry.recordEvent(PLAN_EVENT.planReviewCompleted, { 'plan.outcome': 'no_ui' });\n return {\n content: [\n {\n type: 'text',\n text: 'The plan is complete, but this run cannot ask the user interactively. Remain in plan mode until the user uses SPC p e.',\n },\n ],\n details: { exited: false },\n };\n }\n\n const choice = await ctx.ui.select('Plan complete. What would you like to do?', [\n EXIT_PLAN_MODE_CHOICE,\n CONTINUE_PLANNING_CHOICE,\n ]);\n void telemetry.recordEvent(PLAN_EVENT.planReviewCompleted, {\n 'plan.outcome': choice === EXIT_PLAN_MODE_CHOICE ? 'exited' : 'continued',\n });\n if (choice === EXIT_PLAN_MODE_CHOICE) {\n const exited = await queueTransition(() => exitPlanMode(ctx, PLAN_MODE_TRIGGER_PLAN_APPROVED));\n return {\n content: [\n {\n type: 'text',\n text: exited\n ? 'The user approved exiting plan mode. Full tool access is restored. Begin implementing the approved plan.'\n : 'The previous model could not be restored. Plan mode remains read-only.',\n },\n ],\n details: { exited },\n };\n }\n\n planReadyForReview = false;\n return {\n content: [{ type: 'text', text: 'The user chose to continue planning. Remain read-only and refine the plan.' }],\n details: { exited: false },\n };\n },\n });\n\n if (doomIntegrations) {\n registerDoomLeaderActionHandlers(pi, {\n source: PLAN_LEADER_SOURCE,\n handlers: {\n 'plan.normal': () => {\n const ctx = activeContext;\n return ctx\n ? queueTransition(() => activateFlavor(ctx, 'normal', PLAN_MODE_TRIGGER_LEADER, false))\n : undefined;\n },\n 'plan.exit': () => {\n const ctx = activeContext;\n return ctx\n ? queueTransition(async () => {\n await exitPlanMode(ctx, PLAN_MODE_TRIGGER_LEADER);\n })\n : undefined;\n },\n 'plan.debug': () => {\n const ctx = activeContext;\n return ctx ? queueTransition(() => activateFlavor(ctx, 'debug', PLAN_MODE_TRIGGER_LEADER, false)) : undefined;\n },\n 'plan.fable': () => {\n const ctx = activeContext;\n return ctx ? queueTransition(() => activateFlavor(ctx, 'fable', PLAN_MODE_TRIGGER_LEADER, false)) : undefined;\n },\n },\n onError: (error, actionName) => {\n if (activeContext?.hasUI) {\n activeContext.ui.notify(`Leader action ${actionName} failed. Plan mode remains read-only.`, WARNING_STYLE);\n }\n void telemetry.recordError(PLAN_EVENT.modeEnabled, error, {\n [PLAN_TRIGGER_ATTRIBUTE]: PLAN_MODE_TRIGGER_LEADER,\n 'plan.action': actionName,\n });\n },\n });\n }\n\n pi.on('tool_call', async (event: ToolCallEvent, ctx) => {\n if (!enabled) return undefined;\n const isFlavorTool =\n (activeFlavor === 'debug' &&\n (event.toolName === RECORD_DEBUG_EVIDENCE_TOOL || diagnosticTools.has(event.toolName))) ||\n (activeFlavor === 'fable' && event.toolName === RUN_FABLE_PLAN_TOOL);\n if (!PLAN_MODE_PARENT_TOOLS.has(event.toolName) && !isFlavorTool) {\n return { block: true, reason: `Plan mode blocks the ${event.toolName} tool. Use SPC p e to restore access.` };\n }\n const model = planningSubagentModel(activePlanningConfig?.subagents, ctx.model);\n if (event.toolName === TASK_TOOL) {\n if (model) configurePlanningTaskInput(event.input as MutableTaskInput, model);\n return undefined;\n }\n if (event.toolName !== SUBAGENT_TOOL) return undefined;\n\n const input = event.input as MutableSubagentInput;\n if (isBlockedSubagentManagementAction(input.action)) {\n return {\n block: true,\n reason: `Plan mode blocks subagent management action '${input.action}'. Use SPC p e first.`,\n };\n }\n constrainSubagentInput(input);\n if (model) configurePlanningSubagentInput(input, model);\n return undefined;\n });\n\n pi.on('before_agent_start', async (event, ctx) => {\n const sections: string[] = [];\n if (enabled) {\n const repoRoot = getHarnessState().root ?? ctx.cwd;\n const plansDirectory = resolvePlanningPlansDirectory(\n activePlanningConfig?.plansDirectory,\n repoRoot,\n os.homedir(),\n );\n sections.push(\n `[PLAN MODE ACTIVE]\\nYou are in repository read-only plan mode. The dedicated write_plan tool may write one unique Markdown plan file under ${plansDirectory}.\\n\\nExplore the codebase and produce a concrete implementation plan. For every plan, first call subagent with action \"agents\", cluster the exploration by independent domain, subsystem, or integration boundary, and create a provisional task graph with the task tool. Select specialized agents by matching their names and descriptions to each cluster. Assign every unblocked delegated task through the task tool, and use a one-shot inlineAgent with a focused systemPrompt when no discovered specialist fits. Treat the initial graph as provisional, not as a fixed contract. After findings arrive, review the entire graph at least once and perform one to three review passes in total. In each pass, use the evidence to add, rewrite, delete, cancel, reassign, or change blockedBy relationships for tasks when warranted. Do not keep following tasks that new information has made stale. Stop revising early when the graph is stable, or after the third pass.\\n\\nEvery plan must end with a delegated planning-draft stage blocked by all exploration and decision tasks. A single-boundary plan gets one planning draft. A complex plan spanning multiple subsystems, domains, packages, apps, or integration boundaries gets two planning drafts concurrently. Use three concurrent drafts instead when the work is cross-layer, migration-sensitive, security-sensitive, or similarly high risk. Assign each draft through the task tool to the discovered \"planner\" agent with context \"fork\" so it receives the conversation and gathered evidence. If the planner agent is unavailable, assign the same draft task through the task tool with a focused inlineAgent. All children receive read, Bash, grep, find, ls, and configured MCP tools with artifacts disabled. Bash and MCP tools are for read-only inspection and must not modify files, external systems, or repository state. Doom Team runs asynchronously, so do not poll. After launch, continue non-overlapping exploration or end the turn and wait for completion notifications.\\n\\nAfter all planning drafts complete, the main agent must compare the candidates, pick the strongest draft, cross-check it against the gathered evidence and the other drafts, resolve conflicts and gaps, and ask the user only for product decisions. A child produces the draft, but the main agent owns and synthesizes the final plan. Do not modify files or repository state except through write_plan. Start the final plan with a meaningful Markdown H1 because write_plan derives the filename from it. Present the complete plan as visible Markdown in chat, then call write_plan with no arguments. After write_plan succeeds, clear the completed durable task graph and call complete_plan so the user can review the plan and choose whether to begin implementation or continue planning. Do not exit plan mode without that approval.`,\n buildFlavorPlanningPrompt(activeFlavor!, plansDirectory, debugEvidence, fableStage),\n );\n }\n if (currentPlan) {\n sections.push(`[CURRENT PLAN]\\nSource: ${currentPlan.path}\\n\\n${currentPlan.content}`);\n }\n if (sections.length === 0) return undefined;\n return { systemPrompt: `${event.systemPrompt}\\n\\n${sections.join('\\n\\n')}` };\n });\n\n pi.on('context', async (event) => ({\n messages: event.messages.filter((message) => {\n const custom = message as { customType?: string };\n return custom.customType !== PLAN_MODE_CONTEXT;\n }),\n }));\n\n pi.on('session_start', async (_event, ctx) => {\n const entries = ctx.sessionManager.getEntries();\n const state = entries\n .flatMap((entry) =>\n entry.type === 'custom' && entry.customType === PLAN_MODE_ENTRY ? [parsePersistedPlanState(entry.data)] : [],\n )\n .filter((value): value is PersistedPlanModeState => value !== undefined)\n .at(-1);\n const sessionId = planSessionIdentifier(ctx.sessionManager.getSessionId());\n const storedPlan = entries\n .flatMap((entry) =>\n entry.type === 'custom' && entry.customType === PLAN_DOCUMENT_ENTRY ? [parsePlanDocument(entry.data)] : [],\n )\n .filter((value): value is PlanDocument => value !== undefined)\n .at(-1);\n\n const snapshotFromPreviousSession = planSnapshot;\n capabilityCeiling?.dispose();\n capabilityCeiling = undefined;\n currentPlan = storedPlan?.sessionId === sessionId ? storedPlan : undefined;\n activePlanId = state?.planId ?? currentPlan?.planId;\n planReadyForReview = false;\n activePlanningConfig = undefined;\n debugEvidence = undefined;\n enabled = false;\n activeFlavor = undefined;\n // A session that restores nothing never reaches updateStatus, and the menu\n // would otherwise still offer the exit the previous session left on it.\n updateLeader();\n planSnapshot = state?.originalSnapshot;\n interruptedFableStage = state?.interruptedFableStage;\n fableStage = interruptedFableStage ? 'interrupted' : 'idle';\n activeContext = ctx;\n if (state?.activeFlavor) {\n await activateFlavor(ctx, state.activeFlavor, PLAN_MODE_TRIGGER_SESSION_RESTORE, true);\n } else {\n const snapshotToRestore = state?.originalSnapshot ?? snapshotFromPreviousSession;\n if (snapshotToRestore) {\n const restored = await restoreMainAgent(ctx, snapshotToRestore);\n if (restored) pi.setActiveTools([...snapshotToRestore.tools]);\n } else {\n pi.setActiveTools(\n pi\n .getActiveTools()\n .filter(\n (name) =>\n name !== COMPLETE_PLAN_TOOL &&\n name !== WRITE_PLAN_TOOL &&\n name !== RECORD_DEBUG_EVIDENCE_TOOL &&\n name !== RUN_FABLE_PLAN_TOOL,\n ),\n );\n }\n planSnapshot = undefined;\n updateStatus(ctx);\n }\n });\n\n pi.on('session_shutdown', async (_event, ctx) => {\n await cancelFableOperation('Plan host session is shutting down.');\n if (enabled && planSnapshot) {\n const restored = await restoreMainAgent(ctx, planSnapshot);\n if (restored) pi.setActiveTools([...planSnapshot.tools]);\n }\n capabilityCeiling?.dispose();\n capabilityCeiling = undefined;\n planConfigContribution.dispose();\n activeContext = undefined;\n await telemetry.shutdown();\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import { PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel } from "./config.cjs";
2
+ import { FablePlanBroker, FableStage } from "./fableFlow.cjs";
3
+ import { DebugEvidencePacket, PlanningFlavor } from "./prompts.cjs";
4
+ import { PlanTelemetry } from "./logSinkTelemetry.cjs";
5
+ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
6
+
7
+ //#region src/planMode.d.ts
8
+ declare const WRITE_PLAN_TIMEOUT_MS = 5000;
9
+ declare const PLAN_STATE_VERSION: 2;
10
+ interface ModelIdentity {
11
+ provider: string;
12
+ id: string;
13
+ }
14
+ interface PlanSnapshot {
15
+ tools: string[];
16
+ model?: ModelIdentity;
17
+ thinking: PlanningThinkingLevel;
18
+ }
19
+ interface PersistedPlanModeState {
20
+ version: typeof PLAN_STATE_VERSION;
21
+ activeFlavor?: PlanningFlavor;
22
+ originalSnapshot?: PlanSnapshot;
23
+ planId?: string;
24
+ interruptedFableStage?: FableStage;
25
+ }
26
+ interface PlanModeExtensionOptions {
27
+ fableBroker?: FablePlanBroker;
28
+ debugDiagnosticTools?: readonly string[];
29
+ doomIntegrations?: boolean;
30
+ }
31
+ declare function planTitleSlug(markdown: string): string;
32
+ declare function planSessionIdentifier(sessionId: string): string;
33
+ declare function createPlanIdentifier(now?: Date, id?: `${string}-${string}-${string}-${string}-${string}`): string;
34
+ declare function visiblePlanForToolCall(entries: readonly unknown[], toolCallId: string): string | undefined;
35
+ type MutableSubagentStep = {
36
+ model?: string;
37
+ output?: string | boolean;
38
+ progress?: boolean;
39
+ worktree?: boolean;
40
+ parallel?: MutableSubagentStep | MutableSubagentStep[];
41
+ };
42
+ type MutableSubagentRunRequest = {
43
+ [key: string]: unknown;
44
+ model?: string;
45
+ };
46
+ type MutableSubagentInput = MutableSubagentStep & {
47
+ action?: string;
48
+ artifacts?: boolean;
49
+ outputSchema?: Record<string, unknown>;
50
+ share?: boolean;
51
+ tasks?: MutableSubagentStep[];
52
+ chain?: MutableSubagentStep[];
53
+ chainDir?: string;
54
+ sessionDir?: string;
55
+ requests?: MutableSubagentRunRequest[];
56
+ };
57
+ type MutableTaskInput = {
58
+ action?: string;
59
+ model?: string;
60
+ };
61
+ declare function parsePersistedPlanState(value: unknown): PersistedPlanModeState | undefined;
62
+ declare function parseDebugEvidencePacket(value: unknown): DebugEvidencePacket;
63
+ declare function planModeTools(activeTools: string[], availableTools: string[]): string[];
64
+ declare function constrainSubagentInput(input: MutableSubagentInput): void;
65
+ declare function planningSubagentModel(config: PlanningAgentConfig | undefined, currentModel: ModelIdentity | undefined): string | undefined;
66
+ declare function configurePlanningSubagentInput(input: MutableSubagentInput, model: string): void;
67
+ declare function configurePlanningTaskInput(input: MutableTaskInput, model: string): void;
68
+ declare function isBlockedSubagentManagementAction(action: string | undefined): boolean;
69
+ type PlanningConfigProvider = () => PlanningModeConfig | undefined;
70
+ /** Reads Doom settings from disk so each plan-mode activation sees current configuration. */
71
+ declare function loadPlanningModeConfig(environment?: NodeJS.ProcessEnv, currentDirectory?: string): PlanningModeConfig | undefined;
72
+ declare function planModeExtension(pi: ExtensionAPI, planningConfigProvider?: PlanningConfigProvider, telemetry?: PlanTelemetry, options?: PlanModeExtensionOptions): void;
73
+ //#endregion
74
+ export { ModelIdentity, PlanModeExtensionOptions, PlanSnapshot, PlanningConfigProvider, WRITE_PLAN_TIMEOUT_MS, configurePlanningSubagentInput, configurePlanningTaskInput, constrainSubagentInput, createPlanIdentifier, isBlockedSubagentManagementAction, loadPlanningModeConfig, parseDebugEvidencePacket, parsePersistedPlanState, planModeExtension, planModeTools, planSessionIdentifier, planTitleSlug, planningSubagentModel, visiblePlanForToolCall };
75
+ //# sourceMappingURL=planMode.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planMode.d.cts","names":[],"sources":["../src/planMode.ts"],"mappings":";;;;;;;cA0Fa,qBAAA;AAAA,cA0BP,kBAAA;AAAA,UAsBW,aAAA;EACf,QAAA;EACA,EAAA;AAAA;AAAA,UAGe,YAAA;EACf,KAAA;EACA,KAAA,GAAQ,aAAA;EACR,QAAA,EAAU,qBAAA;AAAA;AAAA,UAGF,sBAAA;EACR,OAAA,SAAgB,kBAAA;EAChB,YAAA,GAAe,cAAA;EACf,gBAAA,GAAmB,YAAA;EACnB,MAAA;EACA,qBAAA,GAAwB,UAAA;AAAA;AAAA,UAqBT,wBAAA;EACf,WAAA,GAAc,eAAA;EACd,oBAAA;EACA,gBAAA;AAAA;AAAA,iBAGc,aAAA,CAAc,QAAA;AAAA,iBAad,qBAAA,CAAsB,SAAA;AAAA,iBAMtB,oBAAA,CAAqB,GAAA,GAAG,IAAA,EAAe,EAAA;AAAA,iBAQvC,sBAAA,CAAuB,OAAA,sBAA6B,UAAA;AAAA,KAkD/D,mBAAA;EACH,KAAA;EACA,MAAA;EACA,QAAA;EACA,QAAA;EACA,QAAA,GAAW,mBAAA,GAAsB,mBAAA;AAAA;AAAA,KAG9B,yBAAA;EAAA,CACF,GAAA;EACD,KAAA;AAAA;AAAA,KAGG,oBAAA,GAAuB,mBAAA;EAC1B,MAAA;EACA,SAAA;EACA,YAAA,GAAe,MAAA;EACf,KAAA;EACA,KAAA,GAAQ,mBAAA;EACR,KAAA,GAAQ,mBAAA;EACR,QAAA;EACA,UAAA;EACA,QAAA,GAAW,yBAAA;AAAA;AAAA,KAGR,gBAAA;EACH,MAAA;EACA,KAAA;AAAA;AAAA,iBAuFc,uBAAA,CAAwB,KAAA,YAAiB,sBAAA;AAAA,iBAsDzC,wBAAA,CAAyB,KAAA,YAAiB,mBAAA;AAAA,iBA0C1C,aAAA,CAAc,WAAA,YAAuB,cAAA;AAAA,iBAmCrC,sBAAA,CAAuB,KAAA,EAAO,oBAAA;AAAA,iBAoB9B,qBAAA,CACd,MAAA,EAAQ,mBAAA,cACR,YAAA,EAAc,aAAA;AAAA,iBASA,8BAAA,CAA+B,KAAA,EAAO,oBAAA,EAAsB,KAAA;AAAA,iBAK5D,0BAAA,CAA2B,KAAA,EAAO,gBAAA,EAAkB,KAAA;AAAA,iBAIpD,iCAAA,CAAkC,MAAA;AAAA,KAgCtC,sBAAA,SAA+B,kBAAA;AA7X3C;AAAA,iBAgYgB,sBAAA,CACd,WAAA,GAAa,MAAA,CAAO,UAAA,EACpB,gBAAA,YACC,kBAAA;AAAA,iBAyCa,iBAAA,CACd,EAAA,EAAI,YAAA,EACJ,sBAAA,GAAwB,sBAAA,EACxB,SAAA,GAAW,aAAA,EACX,OAAA,GAAS,wBAAA"}
@@ -0,0 +1,75 @@
1
+ import { PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel } from "./config.mjs";
2
+ import { FablePlanBroker, FableStage } from "./fableFlow.mjs";
3
+ import { DebugEvidencePacket, PlanningFlavor } from "./prompts.mjs";
4
+ import { PlanTelemetry } from "./logSinkTelemetry.mjs";
5
+ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
6
+
7
+ //#region src/planMode.d.ts
8
+ declare const WRITE_PLAN_TIMEOUT_MS = 5000;
9
+ declare const PLAN_STATE_VERSION: 2;
10
+ interface ModelIdentity {
11
+ provider: string;
12
+ id: string;
13
+ }
14
+ interface PlanSnapshot {
15
+ tools: string[];
16
+ model?: ModelIdentity;
17
+ thinking: PlanningThinkingLevel;
18
+ }
19
+ interface PersistedPlanModeState {
20
+ version: typeof PLAN_STATE_VERSION;
21
+ activeFlavor?: PlanningFlavor;
22
+ originalSnapshot?: PlanSnapshot;
23
+ planId?: string;
24
+ interruptedFableStage?: FableStage;
25
+ }
26
+ interface PlanModeExtensionOptions {
27
+ fableBroker?: FablePlanBroker;
28
+ debugDiagnosticTools?: readonly string[];
29
+ doomIntegrations?: boolean;
30
+ }
31
+ declare function planTitleSlug(markdown: string): string;
32
+ declare function planSessionIdentifier(sessionId: string): string;
33
+ declare function createPlanIdentifier(now?: Date, id?: `${string}-${string}-${string}-${string}-${string}`): string;
34
+ declare function visiblePlanForToolCall(entries: readonly unknown[], toolCallId: string): string | undefined;
35
+ type MutableSubagentStep = {
36
+ model?: string;
37
+ output?: string | boolean;
38
+ progress?: boolean;
39
+ worktree?: boolean;
40
+ parallel?: MutableSubagentStep | MutableSubagentStep[];
41
+ };
42
+ type MutableSubagentRunRequest = {
43
+ [key: string]: unknown;
44
+ model?: string;
45
+ };
46
+ type MutableSubagentInput = MutableSubagentStep & {
47
+ action?: string;
48
+ artifacts?: boolean;
49
+ outputSchema?: Record<string, unknown>;
50
+ share?: boolean;
51
+ tasks?: MutableSubagentStep[];
52
+ chain?: MutableSubagentStep[];
53
+ chainDir?: string;
54
+ sessionDir?: string;
55
+ requests?: MutableSubagentRunRequest[];
56
+ };
57
+ type MutableTaskInput = {
58
+ action?: string;
59
+ model?: string;
60
+ };
61
+ declare function parsePersistedPlanState(value: unknown): PersistedPlanModeState | undefined;
62
+ declare function parseDebugEvidencePacket(value: unknown): DebugEvidencePacket;
63
+ declare function planModeTools(activeTools: string[], availableTools: string[]): string[];
64
+ declare function constrainSubagentInput(input: MutableSubagentInput): void;
65
+ declare function planningSubagentModel(config: PlanningAgentConfig | undefined, currentModel: ModelIdentity | undefined): string | undefined;
66
+ declare function configurePlanningSubagentInput(input: MutableSubagentInput, model: string): void;
67
+ declare function configurePlanningTaskInput(input: MutableTaskInput, model: string): void;
68
+ declare function isBlockedSubagentManagementAction(action: string | undefined): boolean;
69
+ type PlanningConfigProvider = () => PlanningModeConfig | undefined;
70
+ /** Reads Doom settings from disk so each plan-mode activation sees current configuration. */
71
+ declare function loadPlanningModeConfig(environment?: NodeJS.ProcessEnv, currentDirectory?: string): PlanningModeConfig | undefined;
72
+ declare function planModeExtension(pi: ExtensionAPI, planningConfigProvider?: PlanningConfigProvider, telemetry?: PlanTelemetry, options?: PlanModeExtensionOptions): void;
73
+ //#endregion
74
+ export { ModelIdentity, PlanModeExtensionOptions, PlanSnapshot, PlanningConfigProvider, WRITE_PLAN_TIMEOUT_MS, configurePlanningSubagentInput, configurePlanningTaskInput, constrainSubagentInput, createPlanIdentifier, isBlockedSubagentManagementAction, loadPlanningModeConfig, parseDebugEvidencePacket, parsePersistedPlanState, planModeExtension, planModeTools, planSessionIdentifier, planTitleSlug, planningSubagentModel, visiblePlanForToolCall };
75
+ //# sourceMappingURL=planMode.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planMode.d.mts","names":[],"sources":["../src/planMode.ts"],"mappings":";;;;;;;cA0Fa,qBAAA;AAAA,cA0BP,kBAAA;AAAA,UAsBW,aAAA;EACf,QAAA;EACA,EAAA;AAAA;AAAA,UAGe,YAAA;EACf,KAAA;EACA,KAAA,GAAQ,aAAA;EACR,QAAA,EAAU,qBAAA;AAAA;AAAA,UAGF,sBAAA;EACR,OAAA,SAAgB,kBAAA;EAChB,YAAA,GAAe,cAAA;EACf,gBAAA,GAAmB,YAAA;EACnB,MAAA;EACA,qBAAA,GAAwB,UAAA;AAAA;AAAA,UAqBT,wBAAA;EACf,WAAA,GAAc,eAAA;EACd,oBAAA;EACA,gBAAA;AAAA;AAAA,iBAGc,aAAA,CAAc,QAAA;AAAA,iBAad,qBAAA,CAAsB,SAAA;AAAA,iBAMtB,oBAAA,CAAqB,GAAA,GAAG,IAAA,EAAe,EAAA;AAAA,iBAQvC,sBAAA,CAAuB,OAAA,sBAA6B,UAAA;AAAA,KAkD/D,mBAAA;EACH,KAAA;EACA,MAAA;EACA,QAAA;EACA,QAAA;EACA,QAAA,GAAW,mBAAA,GAAsB,mBAAA;AAAA;AAAA,KAG9B,yBAAA;EAAA,CACF,GAAA;EACD,KAAA;AAAA;AAAA,KAGG,oBAAA,GAAuB,mBAAA;EAC1B,MAAA;EACA,SAAA;EACA,YAAA,GAAe,MAAA;EACf,KAAA;EACA,KAAA,GAAQ,mBAAA;EACR,KAAA,GAAQ,mBAAA;EACR,QAAA;EACA,UAAA;EACA,QAAA,GAAW,yBAAA;AAAA;AAAA,KAGR,gBAAA;EACH,MAAA;EACA,KAAA;AAAA;AAAA,iBAuFc,uBAAA,CAAwB,KAAA,YAAiB,sBAAA;AAAA,iBAsDzC,wBAAA,CAAyB,KAAA,YAAiB,mBAAA;AAAA,iBA0C1C,aAAA,CAAc,WAAA,YAAuB,cAAA;AAAA,iBAmCrC,sBAAA,CAAuB,KAAA,EAAO,oBAAA;AAAA,iBAoB9B,qBAAA,CACd,MAAA,EAAQ,mBAAA,cACR,YAAA,EAAc,aAAA;AAAA,iBASA,8BAAA,CAA+B,KAAA,EAAO,oBAAA,EAAsB,KAAA;AAAA,iBAK5D,0BAAA,CAA2B,KAAA,EAAO,gBAAA,EAAkB,KAAA;AAAA,iBAIpD,iCAAA,CAAkC,MAAA;AAAA,KAgCtC,sBAAA,SAA+B,kBAAA;AA7X3C;AAAA,iBAgYgB,sBAAA,CACd,WAAA,GAAa,MAAA,CAAO,UAAA,EACpB,gBAAA,YACC,kBAAA;AAAA,iBAyCa,iBAAA,CACd,EAAA,EAAI,YAAA,EACJ,sBAAA,GAAwB,sBAAA,EACxB,SAAA,GAAW,aAAA,EACX,OAAA,GAAS,wBAAA"}