@agimon-ai/doompi-plan 0.0.1-alpha.7 → 0.0.1-alpha.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -20
- package/dist/_virtual/_rolldown/runtime.cjs +1 -1
- package/dist/api-contracts.cjs +1 -0
- package/dist/api-contracts.d.cts +2 -0
- package/dist/api-contracts.d.mts +2 -0
- package/dist/api-contracts.mjs +1 -0
- package/dist/config.cjs +1 -2
- package/dist/config.d.cts +2 -14
- package/dist/config.d.mts +2 -14
- package/dist/config.mjs +1 -2
- package/dist/controllers/planApi.cjs +2 -0
- package/dist/controllers/planApi.cjs.map +1 -0
- package/dist/controllers/planApi.mjs +2 -0
- package/dist/controllers/planApi.mjs.map +1 -0
- package/dist/controllers/planMode.cjs +7 -0
- package/dist/controllers/planMode.cjs.map +1 -0
- package/dist/controllers/planMode.d.cts +91 -0
- package/dist/controllers/planMode.d.cts.map +1 -0
- package/dist/controllers/planMode.d.mts +91 -0
- package/dist/controllers/planMode.d.mts.map +1 -0
- package/dist/controllers/planMode.mjs +7 -0
- package/dist/controllers/planMode.mjs.map +1 -0
- package/dist/controllers/planServerSession.cjs +2 -0
- package/dist/controllers/planServerSession.cjs.map +1 -0
- package/dist/controllers/planServerSession.mjs +2 -0
- package/dist/controllers/planServerSession.mjs.map +1 -0
- package/dist/extensions/pi.cjs +1 -1
- package/dist/extensions/pi.cjs.map +1 -1
- package/dist/extensions/pi.d.cts +5 -2
- package/dist/extensions/pi.d.cts.map +1 -0
- package/dist/extensions/pi.d.mts +5 -2
- package/dist/extensions/pi.d.mts.map +1 -0
- package/dist/extensions/pi.mjs +1 -1
- package/dist/extensions/pi.mjs.map +1 -1
- package/dist/extensions/server.cjs +2 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.cts +5 -0
- package/dist/extensions/server.d.cts.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +2 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/fable-flow.cjs +1 -0
- package/dist/fable-flow.d.cts +2 -0
- package/dist/fable-flow.d.mts +2 -0
- package/dist/fable-flow.mjs +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +1 -1
- package/dist/log-sink-telemetry.cjs +1 -0
- package/dist/log-sink-telemetry.d.cts +2 -0
- package/dist/log-sink-telemetry.d.mts +2 -0
- package/dist/log-sink-telemetry.mjs +1 -0
- package/dist/plan-config.cjs +1 -0
- package/dist/plan-config.d.cts +3 -0
- package/dist/plan-config.d.mts +3 -0
- package/dist/plan-config.mjs +1 -0
- package/dist/plan-mode.cjs +1 -0
- package/dist/plan-mode.d.cts +3 -0
- package/dist/plan-mode.d.mts +3 -0
- package/dist/plan-mode.mjs +1 -0
- package/dist/prompts.cjs +1 -3
- package/dist/prompts.d.cts +2 -24
- package/dist/prompts.d.mts +2 -24
- package/dist/prompts.mjs +1 -3
- package/dist/schemas/apiContracts.cjs +2 -0
- package/dist/schemas/apiContracts.cjs.map +1 -0
- package/dist/schemas/apiContracts.d.cts +53 -0
- package/dist/schemas/apiContracts.d.cts.map +1 -0
- package/dist/schemas/apiContracts.d.mts +53 -0
- package/dist/schemas/apiContracts.d.mts.map +1 -0
- package/dist/schemas/apiContracts.mjs +2 -0
- package/dist/schemas/apiContracts.mjs.map +1 -0
- package/dist/schemas/plan/config.cjs +2 -0
- package/dist/schemas/plan/config.cjs.map +1 -0
- package/dist/schemas/plan/config.d.cts +13 -0
- package/dist/schemas/plan/config.d.cts.map +1 -0
- package/dist/schemas/plan/config.d.mts +13 -0
- package/dist/schemas/plan/config.d.mts.map +1 -0
- package/dist/schemas/plan/config.mjs +2 -0
- package/dist/schemas/plan/config.mjs.map +1 -0
- package/dist/schemas/plan/planConfig.cjs +2 -0
- package/dist/schemas/plan/planConfig.cjs.map +1 -0
- package/dist/schemas/plan/planConfig.d.cts +23 -0
- package/dist/schemas/plan/planConfig.d.cts.map +1 -0
- package/dist/schemas/plan/planConfig.d.mts +23 -0
- package/dist/schemas/plan/planConfig.d.mts.map +1 -0
- package/dist/schemas/plan/planConfig.mjs +2 -0
- package/dist/schemas/plan/planConfig.mjs.map +1 -0
- package/dist/services/fableFlow/index.cjs +3 -0
- package/dist/services/fableFlow/index.cjs.map +1 -0
- package/dist/services/fableFlow/index.d.cts +67 -0
- package/dist/services/fableFlow/index.d.cts.map +1 -0
- package/dist/services/fableFlow/index.d.mts +67 -0
- package/dist/services/fableFlow/index.d.mts.map +1 -0
- package/dist/services/fableFlow/index.mjs +3 -0
- package/dist/services/fableFlow/index.mjs.map +1 -0
- package/dist/services/logSinkTelemetry/index.cjs +2 -0
- package/dist/services/logSinkTelemetry/index.cjs.map +1 -0
- package/dist/services/logSinkTelemetry/index.d.cts +33 -0
- package/dist/services/logSinkTelemetry/index.d.cts.map +1 -0
- package/dist/services/logSinkTelemetry/index.d.mts +33 -0
- package/dist/services/logSinkTelemetry/index.d.mts.map +1 -0
- package/dist/services/logSinkTelemetry/index.mjs +2 -0
- package/dist/services/logSinkTelemetry/index.mjs.map +1 -0
- package/dist/services/optionalTeamServices/index.cjs +2 -0
- package/dist/services/optionalTeamServices/index.cjs.map +1 -0
- package/dist/services/optionalTeamServices/index.mjs +2 -0
- package/dist/services/optionalTeamServices/index.mjs.map +1 -0
- package/dist/services/planPointer/index.cjs +2 -0
- package/dist/services/planPointer/index.cjs.map +1 -0
- package/dist/services/planPointer/index.mjs +2 -0
- package/dist/services/planPointer/index.mjs.map +1 -0
- package/dist/services/prompts/index.cjs +3 -0
- package/dist/services/prompts/index.cjs.map +1 -0
- package/dist/services/prompts/index.d.cts +25 -0
- package/dist/services/prompts/index.d.cts.map +1 -0
- package/dist/services/prompts/index.d.mts +25 -0
- package/dist/services/prompts/index.d.mts.map +1 -0
- package/dist/services/prompts/index.mjs +3 -0
- package/dist/services/prompts/index.mjs.map +1 -0
- package/dist/types/planApi.cjs +2 -0
- package/dist/types/planApi.cjs.map +1 -0
- package/dist/types/planApi.d.cts +17 -0
- package/dist/types/planApi.d.cts.map +1 -0
- package/dist/types/planApi.d.mts +17 -0
- package/dist/types/planApi.d.mts.map +1 -0
- package/dist/types/planApi.mjs +2 -0
- package/dist/types/planApi.mjs.map +1 -0
- package/dist/types/planPointer.d.cts +26 -0
- package/dist/types/planPointer.d.cts.map +1 -0
- package/dist/types/planPointer.d.mts +26 -0
- package/dist/types/planPointer.d.mts.map +1 -0
- package/dist/types/planSettings.cjs +2 -0
- package/dist/types/planSettings.cjs.map +1 -0
- package/dist/types/planSettings.d.cts +27 -0
- package/dist/types/planSettings.d.cts.map +1 -0
- package/dist/types/planSettings.d.mts +27 -0
- package/dist/types/planSettings.d.mts.map +1 -0
- package/dist/types/planSettings.mjs +2 -0
- package/dist/types/planSettings.mjs.map +1 -0
- package/llms.txt +9 -0
- package/package.json +122 -23
- package/src/extensions/web.ts +62 -0
- package/src/prompts/doompi-use-plan/SKILL.md +25 -0
- package/src/types/planApi.ts +137 -0
- package/src/types/planSettings.ts +78 -0
- package/src/web/api/planApi.ts +82 -0
- package/src/web/components/PlanActivitySection.tsx +63 -0
- package/src/web/components/PlanPanel.tsx +201 -0
- package/src/web/components/PlanReviewPrompt.tsx +80 -0
- package/src/web/components/PlanToolMessage.tsx +43 -0
- package/src/web/lib/planSettings.ts +31 -0
- package/src/web/lib/planToolRender.ts +242 -0
- package/src/web/tsconfig.json +23 -0
- package/dist/config.cjs.map +0 -1
- package/dist/config.d.cts.map +0 -1
- package/dist/config.d.mts.map +0 -1
- package/dist/config.mjs.map +0 -1
- package/dist/extension.cjs +0 -2
- package/dist/extension.cjs.map +0 -1
- package/dist/extension.d.cts +0 -8
- package/dist/extension.d.cts.map +0 -1
- package/dist/extension.d.mts +0 -8
- package/dist/extension.d.mts.map +0 -1
- package/dist/extension.mjs +0 -2
- package/dist/extension.mjs.map +0 -1
- package/dist/extensions/doom.cjs +0 -2
- package/dist/extensions/doom.cjs.map +0 -1
- package/dist/extensions/doom.d.cts +0 -8
- package/dist/extensions/doom.d.cts.map +0 -1
- package/dist/extensions/doom.d.mts +0 -8
- package/dist/extensions/doom.d.mts.map +0 -1
- package/dist/extensions/doom.mjs +0 -2
- package/dist/extensions/doom.mjs.map +0 -1
- package/dist/fableFlow.cjs +0 -3
- package/dist/fableFlow.cjs.map +0 -1
- package/dist/fableFlow.d.cts +0 -66
- package/dist/fableFlow.d.cts.map +0 -1
- package/dist/fableFlow.d.mts +0 -66
- package/dist/fableFlow.d.mts.map +0 -1
- package/dist/fableFlow.mjs +0 -3
- package/dist/fableFlow.mjs.map +0 -1
- package/dist/logSinkTelemetry.cjs +0 -2
- package/dist/logSinkTelemetry.cjs.map +0 -1
- package/dist/logSinkTelemetry.d.cts +0 -24
- package/dist/logSinkTelemetry.d.cts.map +0 -1
- package/dist/logSinkTelemetry.d.mts +0 -24
- package/dist/logSinkTelemetry.d.mts.map +0 -1
- package/dist/logSinkTelemetry.mjs +0 -2
- package/dist/logSinkTelemetry.mjs.map +0 -1
- package/dist/planConfig.cjs +0 -2
- package/dist/planConfig.cjs.map +0 -1
- package/dist/planConfig.mjs +0 -2
- package/dist/planConfig.mjs.map +0 -1
- package/dist/planMode.cjs +0 -6
- package/dist/planMode.cjs.map +0 -1
- package/dist/planMode.d.cts +0 -75
- package/dist/planMode.d.cts.map +0 -1
- package/dist/planMode.d.mts +0 -75
- package/dist/planMode.d.mts.map +0 -1
- package/dist/planMode.mjs +0 -6
- package/dist/planMode.mjs.map +0 -1
- package/dist/prompts.cjs.map +0 -1
- package/dist/prompts.d.cts.map +0 -1
- package/dist/prompts.d.mts.map +0 -1
- package/dist/prompts.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,41 +1,124 @@
|
|
|
1
1
|
# @agimon-ai/doompi-plan
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Create and review stored plans in Pi with narrowed tools, explicit completion, and normal, debug, or Fable-assisted flows.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
it toggles mid-session and reports itself on the shared `MODES` line.
|
|
5
|
+
Part of the [DoomPi distribution](https://www.npmjs.com/package/@agimon-ai/doompi).
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
Plan mode removes `edit` and `write` from the active tool set and directs writes through
|
|
8
|
+
`write_plan`. It does not sandbox Bash, external tools, or the operating system, so treat it as
|
|
9
|
+
tool-level workflow protection rather than a repository permission boundary.
|
|
10
|
+
|
|
11
|
+
> **Alpha:** planning flows and tool contracts may change between releases.
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Node.js 22.19.0 or newer
|
|
16
|
+
- Pi 0.85.0
|
|
11
17
|
|
|
12
18
|
## Install
|
|
13
19
|
|
|
20
|
+
The seeded `modes.yaml` selects Plan in `default.packages`. Keep it there or select it through a
|
|
21
|
+
layer; Plan remains inactive until requested. For standalone Pi:
|
|
22
|
+
|
|
14
23
|
```bash
|
|
15
|
-
|
|
24
|
+
pi install npm:@agimon-ai/doompi-plan
|
|
16
25
|
```
|
|
17
26
|
|
|
18
|
-
|
|
27
|
+
DoomPi and standalone Pi use the same `@agimon-ai/doompi-plan/extensions/pi` extension.
|
|
19
28
|
|
|
20
|
-
|
|
29
|
+
## Start and exit
|
|
21
30
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
| Key | Flavor |
|
|
32
|
+
| --------- | ------------------------------------------------------ |
|
|
33
|
+
| `SPC p e` | Normal planning, and the way out once any flavor is on |
|
|
34
|
+
| `SPC p d` | Debug planning with a bounded evidence packet |
|
|
35
|
+
| `SPC p f` | Fable-assisted drafting followed by Pi verification |
|
|
36
|
+
|
|
37
|
+
`SPC p e` reads `enter` while the mode is off and `exit` while it is on, where exiting restores the
|
|
38
|
+
prior model, thinking level, and tool state.
|
|
39
|
+
|
|
40
|
+
Normal planning expects repository exploration and delegation where available. Debug planning
|
|
41
|
+
separates verified evidence from hypotheses. Fable is an optional Team-provided planning service.
|
|
42
|
+
When Team provides `doom/fable-plan`, Plan treats returned text as untrusted and requires Pi to
|
|
43
|
+
verify and synthesize the final plan. Its child capability ceiling comes from
|
|
44
|
+
`doom/subagent-policy` and is removed when either provider or Plan unloads.
|
|
45
|
+
|
|
46
|
+
A model or tool restoration failure leaves the narrowed Plan state active and reports the failure
|
|
47
|
+
rather than pretending the session was restored.
|
|
48
|
+
|
|
49
|
+
## Write and complete a plan
|
|
50
|
+
|
|
51
|
+
`write_plan` accepts visible Markdown plan content and writes a unique file under `~/.pi/plans` by
|
|
52
|
+
default. It refuses a plan that is empty or was not presented in visible assistant output, and it
|
|
53
|
+
validates the destination before writing. The plan path and content become visible session state.
|
|
54
|
+
|
|
55
|
+
After a plan exists, `complete_plan` asks whether to exit or continue planning. The user must
|
|
56
|
+
explicitly approve exit. If the selected mode already exposes `ask_user_question`, Plan reuses it;
|
|
57
|
+
it does not activate an omitted feedback layer.
|
|
58
|
+
|
|
59
|
+
In autonomous Voice mode, review choices are narrated, the turn terminates, and the next user
|
|
60
|
+
message carries the decision.
|
|
26
61
|
|
|
27
|
-
|
|
28
|
-
|
|
62
|
+
## Read and edit the plan in the cockpit
|
|
63
|
+
|
|
64
|
+
Once `write_plan` succeeds, a `plan` group appears in the cockpit's activity dock and stays for the
|
|
65
|
+
rest of the session, including after Plan mode is exited: that is when the agent starts
|
|
66
|
+
implementing, which is when the plan is most worth having open. The row opens a temporary tab that
|
|
67
|
+
renders the plan as Markdown, with a `source` view that edits it and saves back to the plan file.
|
|
68
|
+
|
|
69
|
+
The agent reads the plan file at the start of every turn, so a saved edit is what it implements. A
|
|
70
|
+
save carries the hash the reader loaded and is refused if the agent rewrote the plan in the
|
|
71
|
+
meantime, rather than overwriting it.
|
|
72
|
+
|
|
73
|
+
The cockpit reaches the plan through this package's session API, mounted at `/api/plugin/plans`.
|
|
74
|
+
Because a host imports the built entry, a change here needs `pnpm build` and `doompi sync` before a
|
|
75
|
+
running cockpit sees it.
|
|
76
|
+
|
|
77
|
+
## Configure models and storage
|
|
78
|
+
|
|
79
|
+
Put planning settings in the repository's `.doom/config.yaml` or the global
|
|
80
|
+
`~/.pi/.doom/config.yaml`:
|
|
81
|
+
|
|
82
|
+
```yaml
|
|
83
|
+
modes:
|
|
84
|
+
planning:
|
|
85
|
+
main:
|
|
86
|
+
model: provider/planning-model
|
|
87
|
+
thinking: high
|
|
88
|
+
subagents:
|
|
89
|
+
model: provider/research-model
|
|
90
|
+
thinking: medium
|
|
91
|
+
plansDirectory: ~/.pi/plans
|
|
29
92
|
```
|
|
30
93
|
|
|
31
|
-
|
|
94
|
+
`main` controls the planning model, `subagents` controls delegated research defaults, and
|
|
95
|
+
`plansDirectory` can be absolute, repository-relative, or under `~`. Planning and delegated model
|
|
96
|
+
calls consume provider quota.
|
|
97
|
+
|
|
98
|
+
## Public API
|
|
99
|
+
|
|
100
|
+
The root exports planning configuration schemas, prompts, Fable flow helpers, and the Plan mode
|
|
101
|
+
service. Focused exports include `/config`, `/plan-config`, `/plan-mode`, `/fable-flow`, and `/prompts`.
|
|
102
|
+
The session-scoped server plugin owns the cockpit plan API. Pi and server entries live in
|
|
103
|
+
`src/extensions`; their public modules are `/extensions/pi` and `/extensions/server`.
|
|
104
|
+
Controllers compose tools and services. Services live in named folders, and `src/exports`
|
|
105
|
+
contains only flat public exports.
|
|
32
106
|
|
|
33
|
-
|
|
34
|
-
the
|
|
107
|
+
The Pi plugin constructs declarations, installs optional Cordis services, and then becomes ready.
|
|
108
|
+
Its `onStop` hook cancels pending work and restores the previous agent configuration before
|
|
109
|
+
registrations are removed. `onDispose` also handles partial startup cleanup. Session events and
|
|
110
|
+
Plan flavor changes remain separate from plugin startup and shutdown.
|
|
35
111
|
|
|
36
|
-
##
|
|
112
|
+
## Development
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pnpm build
|
|
116
|
+
pnpm typecheck
|
|
117
|
+
pnpm test
|
|
118
|
+
pnpm lint
|
|
119
|
+
```
|
|
37
120
|
|
|
38
|
-
|
|
121
|
+
Maintained by [Agimon](https://agimon.ai/about).
|
|
39
122
|
|
|
40
123
|
## License
|
|
41
124
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));exports.__toESM=s;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("./schemas/apiContracts.cjs");exports.apiContracts=e.apiContracts,exports.default=e.apiContracts;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{apiContracts as e}from"./schemas/apiContracts.mjs";export{e as apiContracts,e as default};
|
package/dist/config.cjs
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
require(
|
|
2
|
-
//# sourceMappingURL=config.cjs.map
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./schemas/plan/config.cjs");let t=require("@agimon-ai/doompi-config");exports.getHarnessState=t.getHarnessState,exports.globalDoomConfigPath=t.globalDoomConfigPath,exports.loadDoomConfig=e.loadDoomConfig,exports.loadHarnessState=t.loadHarnessState,exports.mergeDoomConfigs=e.mergeDoomConfigs,exports.parseDoomConfig=e.parseDoomConfig,exports.parsePlanningModeConfig=t.parsePlanningModeConfig,exports.repositoryDoomConfigPath=t.repositoryDoomConfigPath,exports.resolvePlanningPlansDirectory=t.resolvePlanningPlansDirectory;
|
package/dist/config.d.cts
CHANGED
|
@@ -1,14 +1,2 @@
|
|
|
1
|
-
import { PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, getHarnessState, globalDoomConfigPath, loadHarnessState, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory } from "
|
|
2
|
-
|
|
3
|
-
//#region src/config.d.ts
|
|
4
|
-
interface DoomConfig {
|
|
5
|
-
modes?: {
|
|
6
|
-
planning?: PlanningModeConfig;
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
declare function parseDoomConfig(content: string, filePath: string): DoomConfig;
|
|
10
|
-
declare function mergeDoomConfigs(globalConfig: DoomConfig, repositoryConfig: DoomConfig): DoomConfig;
|
|
11
|
-
declare function loadDoomConfig(repoRoot: string, homeDirectory?: string): DoomConfig;
|
|
12
|
-
//#endregion
|
|
13
|
-
export { DoomConfig, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, getHarnessState, globalDoomConfigPath, loadDoomConfig, loadHarnessState, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory };
|
|
14
|
-
//# sourceMappingURL=config.d.cts.map
|
|
1
|
+
import { DoomConfig, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, getHarnessState, globalDoomConfigPath, loadDoomConfig, loadHarnessState, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory } from "./schemas/plan/config.cjs";
|
|
2
|
+
export { DoomConfig, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, getHarnessState, globalDoomConfigPath, loadDoomConfig, loadHarnessState, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory };
|
package/dist/config.d.mts
CHANGED
|
@@ -1,14 +1,2 @@
|
|
|
1
|
-
import { PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, getHarnessState, globalDoomConfigPath
|
|
2
|
-
|
|
3
|
-
//#region src/config.d.ts
|
|
4
|
-
interface DoomConfig {
|
|
5
|
-
modes?: {
|
|
6
|
-
planning?: PlanningModeConfig;
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
declare function parseDoomConfig$1(content: string, filePath: string): DoomConfig;
|
|
10
|
-
declare function mergeDoomConfigs$1(globalConfig: DoomConfig, repositoryConfig: DoomConfig): DoomConfig;
|
|
11
|
-
declare function loadDoomConfig$1(repoRoot: string, homeDirectory?: string): DoomConfig;
|
|
12
|
-
//#endregion
|
|
13
|
-
export { DoomConfig, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, getHarnessState, globalDoomConfigPath$1 as globalDoomConfigPath, loadDoomConfig$1 as loadDoomConfig, loadHarnessState, mergeDoomConfigs$1 as mergeDoomConfigs, parseDoomConfig$1 as parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory };
|
|
14
|
-
//# sourceMappingURL=config.d.mts.map
|
|
1
|
+
import { DoomConfig, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, getHarnessState, globalDoomConfigPath, loadDoomConfig, loadHarnessState, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory } from "./schemas/plan/config.mjs";
|
|
2
|
+
export { DoomConfig, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, getHarnessState, globalDoomConfigPath, loadDoomConfig, loadHarnessState, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory };
|
package/dist/config.mjs
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import{getHarnessState as e,globalDoomConfigPath as t,loadDoomConfig as n,loadHarnessState as r,mergeDoomConfigs as i,parseDoomConfig as a,parsePlanningModeConfig as o,repositoryDoomConfigPath as s,resolvePlanningPlansDirectory as c}from"
|
|
2
|
-
//# sourceMappingURL=config.mjs.map
|
|
1
|
+
import{getHarnessState as e,globalDoomConfigPath as t,loadDoomConfig as n,loadHarnessState as r,mergeDoomConfigs as i,parseDoomConfig as a,parsePlanningModeConfig as o,repositoryDoomConfigPath as s,resolvePlanningPlansDirectory as c}from"./schemas/plan/config.mjs";export{e as getHarnessState,t as globalDoomConfigPath,n as loadDoomConfig,r as loadHarnessState,i as mergeDoomConfigs,a as parseDoomConfig,o as parsePlanningModeConfig,s as repositoryDoomConfigPath,c as resolvePlanningPlansDirectory};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../services/planPointer/index.cjs"),n=require("../types/planApi.cjs");let r=require("node:crypto"),i=require("node:fs/promises");i=e.__toESM(i,1);let a=require("hono");const o=1048576,s=`This session has not written a plan yet.`;function c(e){return(0,r.createHash)(`sha256`).update(e,`utf8`).digest(`hex`)}async function l(e){let t;try{t=await i.default.readFile(e)}catch{return{content:``,hash:``,unavailable:!0,reason:`the plan file no longer exists`}}if(t.byteLength>1048576)return{content:``,hash:``,unavailable:!0,reason:`the plan is larger than ${o} bytes`};let n=t.toString(`utf8`);return{content:n,hash:c(n),unavailable:!1}}function u(e={}){let r=new a.Hono,o=e.pointers??new t.PlanPointerService({env:process.env}),u=()=>e.sessionId===void 0?void 0:o.read(e.sessionId);return r.get(n.currentPath(),async e=>{let t=u();if(t===void 0)return e.json({error:s},404);let n={path:t.path,title:t.title,writtenAt:t.writtenAt,...t.planId===void 0?{}:{planId:t.planId},...await l(t.path)};return e.json(n)}),r.put(n.contentPath(),async e=>{let t;try{t=await e.req.json()}catch{return e.json({error:`The save body is not JSON.`},400)}if(typeof t.content!=`string`||typeof t.expectedHash!=`string`)return e.json({error:`A save carries the content to write and the hash it was read at.`},400);let n=u();if(n===void 0)return e.json({error:s},404);let r=await l(n.path);if(r.unavailable)return e.json({error:r.reason??s},409);if(r.hash!==t.expectedHash)return e.json({error:`The plan changed since it was opened.`,hash:r.hash},409);let a=await i.default.lstat(n.path);return!a.isFile()||a.nlink!==1?e.json({error:`The plan file is no longer a regular file, so it was not written.`},409):(await i.default.writeFile(n.path,t.content,{encoding:`utf8`,mode:384}),e.json({hash:c(t.content)}))}),r}const d={basePath:n.API_BASE_PATH,start(e){let t=u(e.sessionId===void 0?{}:{sessionId:e.sessionId});return{fetch:e=>t.fetch(e),close:()=>void 0}}};exports.MAX_PLAN_BYTES=o,exports.api=d,exports.createPlanApi=u;
|
|
2
|
+
//# sourceMappingURL=planApi.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planApi.cjs","names":["createHash","fs","Hono","PlanPointerService","currentPath","contentPath","API_BASE_PATH"],"sources":["../../src/controllers/planApi.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs/promises';\n\nimport type { DoomApi, DoomApiContext, DoomApiHandler } from '@agimon-ai/doompi-core/package-api';\nimport { Hono } from 'hono';\n\nimport { PlanPointerService } from '../services/planPointer';\nimport {\n API_BASE_PATH,\n contentPath,\n currentPath,\n type PlanDetailView,\n type PlanSaveRequest,\n type PlanSaveView,\n} from '../types/planApi';\nimport type { PlanPointerPort } from '../types/planPointer';\n\n/**\n * This package's HTTP surface: the session's current plan, and the manual save.\n *\n * Routes are relative to the mount its host gives it, so nothing here repeats\n * where it was mounted. The host is one session's own server, which is what\n * makes the session id available without the page supplying it.\n *\n * Neither route takes a path. A session has exactly one current plan, and the\n * file both routes act on is the one the pointer names, so a page can address\n * the plan and nothing else; there is no traversal question to answer because\n * there is no path to traverse.\n *\n * The save refuses unless the reader proves they were looking at the content\n * that is still on disk. The agent may rewrite the plan while a tab is open,\n * and silently discarding whichever side finished second is the one outcome\n * worth ruling out.\n */\n\n/** Past this, the plan is reported rather than carried. */\nexport const MAX_PLAN_BYTES = 1024 * 1024;\n\nconst NO_PLAN = 'This session has not written a plan yet.';\nconst STALE_SAVE = 'The plan changed since it was opened.';\nconst NOT_A_FILE = 'The plan file is no longer a regular file, so it was not written.';\n\nexport interface PlanApiOptions {\n /** The session these routes answer for; absent when the host is the hub. */\n sessionId?: string;\n pointers?: PlanPointerPort;\n}\n\nfunction hashOf(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/** Reads the plan as the source view will show it, or says why it cannot. */\nasync function readPlan(\n planPath: string,\n): Promise<Pick<PlanDetailView, 'content' | 'hash' | 'unavailable' | 'reason'>> {\n let raw: Buffer;\n try {\n raw = await fs.readFile(planPath);\n } catch {\n return { content: '', hash: '', unavailable: true, reason: 'the plan file no longer exists' };\n }\n if (raw.byteLength > MAX_PLAN_BYTES) {\n return { content: '', hash: '', unavailable: true, reason: `the plan is larger than ${MAX_PLAN_BYTES} bytes` };\n }\n const content = raw.toString('utf8');\n return { content, hash: hashOf(content), unavailable: false };\n}\n\nexport function createPlanApi(options: PlanApiOptions = {}): Hono {\n const app = new Hono();\n const pointers = options.pointers ?? new PlanPointerService({ env: process.env });\n const pointerFor = (): ReturnType<PlanPointerPort['read']> =>\n options.sessionId === undefined ? undefined : pointers.read(options.sessionId);\n\n app.get(currentPath(), async (context) => {\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n const view: PlanDetailView = {\n path: pointer.path,\n title: pointer.title,\n writtenAt: pointer.writtenAt,\n ...(pointer.planId === undefined ? {} : { planId: pointer.planId }),\n ...(await readPlan(pointer.path)),\n };\n return context.json(view);\n });\n\n app.put(contentPath(), async (context) => {\n let request: PlanSaveRequest;\n try {\n request = (await context.req.json()) as PlanSaveRequest;\n } catch {\n return context.json({ error: 'The save body is not JSON.' }, 400);\n }\n if (typeof request.content !== 'string' || typeof request.expectedHash !== 'string') {\n return context.json({ error: 'A save carries the content to write and the hash it was read at.' }, 400);\n }\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n\n const current = await readPlan(pointer.path);\n if (current.unavailable) return context.json({ error: current.reason ?? NO_PLAN }, 409);\n if (current.hash !== request.expectedHash) {\n return context.json({ error: STALE_SAVE, hash: current.hash }, 409);\n }\n // The same guard write_plan applies before it writes: a plan whose\n // destination has become a symlink or gained a second name is not written\n // through, whatever the pointer still says.\n const stats = await fs.lstat(pointer.path);\n if (!stats.isFile() || stats.nlink !== 1) return context.json({ error: NOT_A_FILE }, 409);\n\n await fs.writeFile(pointer.path, request.content, { encoding: 'utf8', mode: 0o600 });\n return context.json({ hash: hashOf(request.content) } satisfies PlanSaveView);\n });\n\n return app;\n}\n\n/** The named export a host imports from this package's built entry. */\nexport const api: DoomApi = {\n basePath: API_BASE_PATH,\n start(context: DoomApiContext): DoomApiHandler {\n const app = createPlanApi(context.sessionId === undefined ? {} : { sessionId: context.sessionId });\n return {\n fetch: (request) => app.fetch(request),\n // Nothing outlives a request here; an API that starts a watch or a timer\n // tears it down in this callback.\n close: () => undefined,\n };\n },\n};\n"],"mappings":"wOAoCA,MAAa,EAAiB,QAExB,EAAU,2CAUhB,SAAS,EAAO,EAAyB,CACvC,OAAA,EAAOA,EAAAA,WAAAA,CAAW,QAAQ,CAAC,CAAC,OAAO,EAAS,MAAM,CAAC,CAAC,OAAO,KAAK,CAClE,CAGA,eAAe,EACb,EAC8E,CAC9E,IAAI,EACJ,GAAI,CACF,EAAM,MAAMC,EAAAA,QAAG,SAAS,CAAQ,CAClC,MAAQ,CACN,MAAO,CAAE,QAAS,GAAI,KAAM,GAAI,YAAa,GAAM,OAAQ,gCAAiC,CAC9F,CACA,GAAI,EAAI,WAAA,QACN,MAAO,CAAE,QAAS,GAAI,KAAM,GAAI,YAAa,GAAM,OAAQ,2BAA2B,EAAe,OAAQ,EAE/G,IAAM,EAAU,EAAI,SAAS,MAAM,EACnC,MAAO,CAAE,UAAS,KAAM,EAAO,CAAO,EAAG,YAAa,EAAM,CAC9D,CAEA,SAAgB,EAAc,EAA0B,CAAC,EAAS,CAChE,IAAM,EAAM,IAAIC,EAAAA,KACV,EAAW,EAAQ,UAAY,IAAIC,EAAAA,mBAAmB,CAAE,IAAK,QAAQ,GAAI,CAAC,EAC1E,MACJ,EAAQ,YAAc,IAAA,GAAY,IAAA,GAAY,EAAS,KAAK,EAAQ,SAAS,EA2C/E,OAzCA,EAAI,IAAIC,EAAAA,YAAY,EAAG,KAAO,IAAY,CACxC,IAAM,EAAU,EAAW,EAC3B,GAAI,IAAY,IAAA,GAAW,OAAO,EAAQ,KAAK,CAAE,MAAO,CAAQ,EAAG,GAAG,EACtE,IAAM,EAAuB,CAC3B,KAAM,EAAQ,KACd,MAAO,EAAQ,MACf,UAAW,EAAQ,UACnB,GAAI,EAAQ,SAAW,IAAA,GAAY,CAAC,EAAI,CAAE,OAAQ,EAAQ,MAAO,EACjE,GAAI,MAAM,EAAS,EAAQ,IAAI,CACjC,EACA,OAAO,EAAQ,KAAK,CAAI,CAC1B,CAAC,EAED,EAAI,IAAIC,EAAAA,YAAY,EAAG,KAAO,IAAY,CACxC,IAAI,EACJ,GAAI,CACF,EAAW,MAAM,EAAQ,IAAI,KAAK,CACpC,MAAQ,CACN,OAAO,EAAQ,KAAK,CAAE,MAAO,4BAA6B,EAAG,GAAG,CAClE,CACA,GAAI,OAAO,EAAQ,SAAY,UAAY,OAAO,EAAQ,cAAiB,SACzE,OAAO,EAAQ,KAAK,CAAE,MAAO,kEAAmE,EAAG,GAAG,EAExG,IAAM,EAAU,EAAW,EAC3B,GAAI,IAAY,IAAA,GAAW,OAAO,EAAQ,KAAK,CAAE,MAAO,CAAQ,EAAG,GAAG,EAEtE,IAAM,EAAU,MAAM,EAAS,EAAQ,IAAI,EAC3C,GAAI,EAAQ,YAAa,OAAO,EAAQ,KAAK,CAAE,MAAO,EAAQ,QAAU,CAAQ,EAAG,GAAG,EACtF,GAAI,EAAQ,OAAS,EAAQ,aAC3B,OAAO,EAAQ,KAAK,CAAE,MAAO,wCAAY,KAAM,EAAQ,IAAK,EAAG,GAAG,EAKpE,IAAM,EAAQ,MAAMJ,EAAAA,QAAG,MAAM,EAAQ,IAAI,EAIzC,MAHI,CAAC,EAAM,OAAO,GAAK,EAAM,QAAU,EAAU,EAAQ,KAAK,CAAE,MAAO,mEAAW,EAAG,GAAG,GAExF,MAAMA,EAAAA,QAAG,UAAU,EAAQ,KAAM,EAAQ,QAAS,CAAE,SAAU,OAAQ,KAAM,GAAM,CAAC,EAC5E,EAAQ,KAAK,CAAE,KAAM,EAAO,EAAQ,OAAO,CAAE,CAAwB,EAC9E,CAAC,EAEM,CACT,CAGA,MAAa,EAAe,CAC1B,SAAUK,EAAAA,cACV,MAAM,EAAyC,CAC7C,IAAM,EAAM,EAAc,EAAQ,YAAc,IAAA,GAAY,CAAC,EAAI,CAAE,UAAW,EAAQ,SAAU,CAAC,EACjG,MAAO,CACL,MAAQ,GAAY,EAAI,MAAM,CAAO,EAGrC,UAAa,IAAA,EACf,CACF,CACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{PlanPointerService as e}from"../services/planPointer/index.mjs";import{API_BASE_PATH as t,contentPath as n,currentPath as r}from"../types/planApi.mjs";import{createHash as i}from"node:crypto";import a from"node:fs/promises";import{Hono as o}from"hono";const s=1048576,c=`This session has not written a plan yet.`;function l(e){return i(`sha256`).update(e,`utf8`).digest(`hex`)}async function u(e){let t;try{t=await a.readFile(e)}catch{return{content:``,hash:``,unavailable:!0,reason:`the plan file no longer exists`}}if(t.byteLength>1048576)return{content:``,hash:``,unavailable:!0,reason:`the plan is larger than ${s} bytes`};let n=t.toString(`utf8`);return{content:n,hash:l(n),unavailable:!1}}function d(t={}){let i=new o,s=t.pointers??new e({env:process.env}),d=()=>t.sessionId===void 0?void 0:s.read(t.sessionId);return i.get(r(),async e=>{let t=d();if(t===void 0)return e.json({error:c},404);let n={path:t.path,title:t.title,writtenAt:t.writtenAt,...t.planId===void 0?{}:{planId:t.planId},...await u(t.path)};return e.json(n)}),i.put(n(),async e=>{let t;try{t=await e.req.json()}catch{return e.json({error:`The save body is not JSON.`},400)}if(typeof t.content!=`string`||typeof t.expectedHash!=`string`)return e.json({error:`A save carries the content to write and the hash it was read at.`},400);let n=d();if(n===void 0)return e.json({error:c},404);let r=await u(n.path);if(r.unavailable)return e.json({error:r.reason??c},409);if(r.hash!==t.expectedHash)return e.json({error:`The plan changed since it was opened.`,hash:r.hash},409);let i=await a.lstat(n.path);return!i.isFile()||i.nlink!==1?e.json({error:`The plan file is no longer a regular file, so it was not written.`},409):(await a.writeFile(n.path,t.content,{encoding:`utf8`,mode:384}),e.json({hash:l(t.content)}))}),i}const f={basePath:t,start(e){let t=d(e.sessionId===void 0?{}:{sessionId:e.sessionId});return{fetch:e=>t.fetch(e),close:()=>void 0}}};export{s as MAX_PLAN_BYTES,f as api,d as createPlanApi};
|
|
2
|
+
//# sourceMappingURL=planApi.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planApi.mjs","names":[],"sources":["../../src/controllers/planApi.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs/promises';\n\nimport type { DoomApi, DoomApiContext, DoomApiHandler } from '@agimon-ai/doompi-core/package-api';\nimport { Hono } from 'hono';\n\nimport { PlanPointerService } from '../services/planPointer';\nimport {\n API_BASE_PATH,\n contentPath,\n currentPath,\n type PlanDetailView,\n type PlanSaveRequest,\n type PlanSaveView,\n} from '../types/planApi';\nimport type { PlanPointerPort } from '../types/planPointer';\n\n/**\n * This package's HTTP surface: the session's current plan, and the manual save.\n *\n * Routes are relative to the mount its host gives it, so nothing here repeats\n * where it was mounted. The host is one session's own server, which is what\n * makes the session id available without the page supplying it.\n *\n * Neither route takes a path. A session has exactly one current plan, and the\n * file both routes act on is the one the pointer names, so a page can address\n * the plan and nothing else; there is no traversal question to answer because\n * there is no path to traverse.\n *\n * The save refuses unless the reader proves they were looking at the content\n * that is still on disk. The agent may rewrite the plan while a tab is open,\n * and silently discarding whichever side finished second is the one outcome\n * worth ruling out.\n */\n\n/** Past this, the plan is reported rather than carried. */\nexport const MAX_PLAN_BYTES = 1024 * 1024;\n\nconst NO_PLAN = 'This session has not written a plan yet.';\nconst STALE_SAVE = 'The plan changed since it was opened.';\nconst NOT_A_FILE = 'The plan file is no longer a regular file, so it was not written.';\n\nexport interface PlanApiOptions {\n /** The session these routes answer for; absent when the host is the hub. */\n sessionId?: string;\n pointers?: PlanPointerPort;\n}\n\nfunction hashOf(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/** Reads the plan as the source view will show it, or says why it cannot. */\nasync function readPlan(\n planPath: string,\n): Promise<Pick<PlanDetailView, 'content' | 'hash' | 'unavailable' | 'reason'>> {\n let raw: Buffer;\n try {\n raw = await fs.readFile(planPath);\n } catch {\n return { content: '', hash: '', unavailable: true, reason: 'the plan file no longer exists' };\n }\n if (raw.byteLength > MAX_PLAN_BYTES) {\n return { content: '', hash: '', unavailable: true, reason: `the plan is larger than ${MAX_PLAN_BYTES} bytes` };\n }\n const content = raw.toString('utf8');\n return { content, hash: hashOf(content), unavailable: false };\n}\n\nexport function createPlanApi(options: PlanApiOptions = {}): Hono {\n const app = new Hono();\n const pointers = options.pointers ?? new PlanPointerService({ env: process.env });\n const pointerFor = (): ReturnType<PlanPointerPort['read']> =>\n options.sessionId === undefined ? undefined : pointers.read(options.sessionId);\n\n app.get(currentPath(), async (context) => {\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n const view: PlanDetailView = {\n path: pointer.path,\n title: pointer.title,\n writtenAt: pointer.writtenAt,\n ...(pointer.planId === undefined ? {} : { planId: pointer.planId }),\n ...(await readPlan(pointer.path)),\n };\n return context.json(view);\n });\n\n app.put(contentPath(), async (context) => {\n let request: PlanSaveRequest;\n try {\n request = (await context.req.json()) as PlanSaveRequest;\n } catch {\n return context.json({ error: 'The save body is not JSON.' }, 400);\n }\n if (typeof request.content !== 'string' || typeof request.expectedHash !== 'string') {\n return context.json({ error: 'A save carries the content to write and the hash it was read at.' }, 400);\n }\n const pointer = pointerFor();\n if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n\n const current = await readPlan(pointer.path);\n if (current.unavailable) return context.json({ error: current.reason ?? NO_PLAN }, 409);\n if (current.hash !== request.expectedHash) {\n return context.json({ error: STALE_SAVE, hash: current.hash }, 409);\n }\n // The same guard write_plan applies before it writes: a plan whose\n // destination has become a symlink or gained a second name is not written\n // through, whatever the pointer still says.\n const stats = await fs.lstat(pointer.path);\n if (!stats.isFile() || stats.nlink !== 1) return context.json({ error: NOT_A_FILE }, 409);\n\n await fs.writeFile(pointer.path, request.content, { encoding: 'utf8', mode: 0o600 });\n return context.json({ hash: hashOf(request.content) } satisfies PlanSaveView);\n });\n\n return app;\n}\n\n/** The named export a host imports from this package's built entry. */\nexport const api: DoomApi = {\n basePath: API_BASE_PATH,\n start(context: DoomApiContext): DoomApiHandler {\n const app = createPlanApi(context.sessionId === undefined ? {} : { sessionId: context.sessionId });\n return {\n fetch: (request) => app.fetch(request),\n // Nothing outlives a request here; an API that starts a watch or a timer\n // tears it down in this callback.\n close: () => undefined,\n };\n },\n};\n"],"mappings":"mQAoCA,MAAa,EAAiB,QAExB,EAAU,2CAUhB,SAAS,EAAO,EAAyB,CACvC,OAAO,EAAW,QAAQ,CAAC,CAAC,OAAO,EAAS,MAAM,CAAC,CAAC,OAAO,KAAK,CAClE,CAGA,eAAe,EACb,EAC8E,CAC9E,IAAI,EACJ,GAAI,CACF,EAAM,MAAM,EAAG,SAAS,CAAQ,CAClC,MAAQ,CACN,MAAO,CAAE,QAAS,GAAI,KAAM,GAAI,YAAa,GAAM,OAAQ,gCAAiC,CAC9F,CACA,GAAI,EAAI,WAAA,QACN,MAAO,CAAE,QAAS,GAAI,KAAM,GAAI,YAAa,GAAM,OAAQ,2BAA2B,EAAe,OAAQ,EAE/G,IAAM,EAAU,EAAI,SAAS,MAAM,EACnC,MAAO,CAAE,UAAS,KAAM,EAAO,CAAO,EAAG,YAAa,EAAM,CAC9D,CAEA,SAAgB,EAAc,EAA0B,CAAC,EAAS,CAChE,IAAM,EAAM,IAAI,EACV,EAAW,EAAQ,UAAY,IAAI,EAAmB,CAAE,IAAK,QAAQ,GAAI,CAAC,EAC1E,MACJ,EAAQ,YAAc,IAAA,GAAY,IAAA,GAAY,EAAS,KAAK,EAAQ,SAAS,EA2C/E,OAzCA,EAAI,IAAI,EAAY,EAAG,KAAO,IAAY,CACxC,IAAM,EAAU,EAAW,EAC3B,GAAI,IAAY,IAAA,GAAW,OAAO,EAAQ,KAAK,CAAE,MAAO,CAAQ,EAAG,GAAG,EACtE,IAAM,EAAuB,CAC3B,KAAM,EAAQ,KACd,MAAO,EAAQ,MACf,UAAW,EAAQ,UACnB,GAAI,EAAQ,SAAW,IAAA,GAAY,CAAC,EAAI,CAAE,OAAQ,EAAQ,MAAO,EACjE,GAAI,MAAM,EAAS,EAAQ,IAAI,CACjC,EACA,OAAO,EAAQ,KAAK,CAAI,CAC1B,CAAC,EAED,EAAI,IAAI,EAAY,EAAG,KAAO,IAAY,CACxC,IAAI,EACJ,GAAI,CACF,EAAW,MAAM,EAAQ,IAAI,KAAK,CACpC,MAAQ,CACN,OAAO,EAAQ,KAAK,CAAE,MAAO,4BAA6B,EAAG,GAAG,CAClE,CACA,GAAI,OAAO,EAAQ,SAAY,UAAY,OAAO,EAAQ,cAAiB,SACzE,OAAO,EAAQ,KAAK,CAAE,MAAO,kEAAmE,EAAG,GAAG,EAExG,IAAM,EAAU,EAAW,EAC3B,GAAI,IAAY,IAAA,GAAW,OAAO,EAAQ,KAAK,CAAE,MAAO,CAAQ,EAAG,GAAG,EAEtE,IAAM,EAAU,MAAM,EAAS,EAAQ,IAAI,EAC3C,GAAI,EAAQ,YAAa,OAAO,EAAQ,KAAK,CAAE,MAAO,EAAQ,QAAU,CAAQ,EAAG,GAAG,EACtF,GAAI,EAAQ,OAAS,EAAQ,aAC3B,OAAO,EAAQ,KAAK,CAAE,MAAO,wCAAY,KAAM,EAAQ,IAAK,EAAG,GAAG,EAKpE,IAAM,EAAQ,MAAM,EAAG,MAAM,EAAQ,IAAI,EAIzC,MAHI,CAAC,EAAM,OAAO,GAAK,EAAM,QAAU,EAAU,EAAQ,KAAK,CAAE,MAAO,mEAAW,EAAG,GAAG,GAExF,MAAM,EAAG,UAAU,EAAQ,KAAM,EAAQ,QAAS,CAAE,SAAU,OAAQ,KAAM,GAAM,CAAC,EAC5E,EAAQ,KAAK,CAAE,KAAM,EAAO,EAAQ,OAAO,CAAE,CAAwB,EAC9E,CAAC,EAEM,CACT,CAGA,MAAa,EAAe,CAC1B,SAAU,EACV,MAAM,EAAyC,CAC7C,IAAM,EAAM,EAAc,EAAQ,YAAc,IAAA,GAAY,CAAC,EAAI,CAAE,UAAW,EAAQ,SAAU,CAAC,EACjG,MAAO,CACL,MAAQ,GAAY,EAAI,MAAM,CAAO,EAGrC,UAAa,IAAA,EACf,CACF,CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../schemas/plan/config.cjs"),n=require("../services/fableFlow/index.cjs"),r=require("../schemas/plan/planConfig.cjs"),i=require("../services/logSinkTelemetry/index.cjs"),a=require("../services/optionalTeamServices/index.cjs"),o=require("../services/planPointer/index.cjs"),s=require("../services/prompts/index.cjs"),c=require("../types/planApi.cjs");let l=require("@agimon-ai/doompi-config"),ee=require("node:buffer"),u=require("node:crypto"),d=require("node:fs");d=e.__toESM(d,1);let te=require("node:os");te=e.__toESM(te,1);let ne=require("node:path");ne=e.__toESM(ne,1);let f=require("@agimon-ai/doompi-config/configWriter"),p=require("@agimon-ai/doompi-core/author-tools"),m=require("@agimon-ai/doompi-core/config"),re=require("@agimon-ai/doompi-core/narration"),h=require("@agimon-ai/doompi-core/tool-surface"),g=require("@agimon-ai/doompi-core/ui-hub"),_=require("@agimon-ai/doompi-core/voice-tools"),v=require("@agimon-ai/doompi-minor-mode");const ie=`agent-harness-plan-mode`,ae=`agent-harness-plan-document`,oe=`complete_plan`,se=`write_plan`,y=`bash`,b=`find`,x=`grep`,S=`read`,ce=`subagent`,le=`task`,ue=`record_debug_evidence`,de=`run_fable_plan`,C=`implementation-plan`,w=`@agimon-ai/doompi-plan`,fe=`activate`,pe=`deactivate`,T=`warning`,me=`info`,he=`Refused to write the plan because its destination is not a regular file.`,E=`plan.trigger`,ge=`plan.model`,D=`plan.flavor`,_e=`not_found`,ve=`unauthenticated`,ye=`restore_failed`,be=new Set,xe=5e3,Se=`exit`,Ce=`continue`,we=[c.PLAN_REVIEW_TITLE,` 1. ${c.EXIT_PLAN_MODE_CHOICE}`,` 2. ${c.CONTINUE_PLANNING_CHOICE}`,` Type something.`].join(`
|
|
2
|
+
`),O=`${c.PLAN_REVIEW_TITLE} Options: 1, ${c.EXIT_PLAN_MODE_CHOICE}; 2, ${c.CONTINUE_PLANNING_CHOICE}. Please choose one option. You may also answer in your own words.`,Te=(0,re.createNarrationRequest)(O),k=[`open_authoring_file`,...p.AUTHOR_FACADE_TOOL_NAMES],Ee=new Set([`add_directory`,`ask_user_question`,y,oe,b,x,`intercom`,`ls`,v.MINOR_MODE_TOOL_NAME,...k,..._.VOICE_MODE_TOOL_NAMES,S,`search_external_files`,ce,`subagent_supervisor`,`subagent_wait`,le,se]),De=new Set([`edit`,`write`,`mcp`]),Oe=[S,y,x,b,`ls`,`mcp`],A=`leader`,ke=`voice_tool`,Ae=[`off`,`minimal`,`low`,`medium`,`high`,`xhigh`,`max`],je=[`idle`,`draft`,`review`,`completed`,`failed`,`cancelled`,`interrupted`],Me=`@agimon-ai/doompi-plan`,Ne={type:`string`,enum:[`normal`,`debug`,`fable`]},Pe={type:`object`,properties:{flavor:Ne},required:[`flavor`],additionalProperties:!1},Fe={type:`object`,properties:{},additionalProperties:!1},Ie={type:`object`,properties:{active:{type:`boolean`},flavor:{anyOf:[{...Ne},{type:`null`}]},changed:{type:`boolean`}},required:[`active`,`flavor`,`changed`],additionalProperties:!1};function Le(e){return(e.match(/^#\s+(.+?)\s*$/m)?.[1]??C).normalize(`NFKD`).replace(/[\u0300-\u036f]/g,``).toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).slice(0,64)||C}function Re(e){let t=new Date(e);return Number.isNaN(t.getTime())?e:t.toLocaleTimeString()}function ze(e){return`${encodeURIComponent(e).slice(0,48)||`session`}--${(0,u.createHash)(`sha256`).update(e).digest(`hex`)}`}function Be(e=new Date,t=(0,u.randomUUID)()){return`${e.toISOString().replace(/[-:]/g,``).replace(/\.\d{3}Z$/,`Z`)}--${t}`}function Ve(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===se});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(`
|
|
3
|
+
|
|
4
|
+
`).trim()||void 0}}function He(e){return e.reason instanceof Error?e.reason:Error(`Plan write cancelled.`)}async function j(e,t){if(t.aborted)throw He(t);let n,r=new Promise((e,r)=>{n=()=>r(He(t)),t.addEventListener(`abort`,n,{once:!0})});try{return await Promise.race([e(),r])}finally{n&&t.removeEventListener(`abort`,n)}}function M(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function N(e){return typeof e==`string`}function P(e){if(M(e)&&N(e.provider)&&N(e.id)&&!(!e.provider||!e.id||e.provider.length>128||e.id.length>128))return{provider:e.provider,id:e.id}}function F(e){return N(e)&&Ae.includes(e)?e:void 0}function I(e){return N(e)&&je.includes(e)?e:void 0}function L(e){if(Array.isArray(e)&&!e.some(e=>!N(e)))return e.map(e=>e)}function Ue(e){if(!M(e))return;let t=L(e.tools),n=F(e.thinking);if(!t||n===void 0)return;let r=e.model===void 0?void 0:P(e.model);if(e.model===void 0||r)return{tools:t,...r?{model:r}:{},thinking:n}}function We(e){return e===`normal`||e===`debug`||e===`fable`?e:void 0}function R(e){if(e.version!==2)return;let t=e.activeFlavor===void 0?void 0:We(e.activeFlavor);if(e.activeFlavor!==void 0&&!t)return;let n=e.originalSnapshot===void 0?void 0:Ue(e.originalSnapshot);if(e.originalSnapshot!==void 0&&!n)return;let r=e.planId===void 0?void 0:N(e.planId)?e.planId:void 0;if(e.planId!==void 0&&r===void 0)return;let i=e.interruptedFableStage===void 0?void 0:I(e.interruptedFableStage);if(e.interruptedFableStage===void 0||i)return{version:2,...t?{activeFlavor:t}:{},...n?{originalSnapshot:n}:{},...r?{planId:r}:{},...i?{interruptedFableStage:i}:{}}}function z(e){if(e.enabled!==!0&&e.enabled!==!1)return;let t=e.toolsBeforePlanMode===void 0?void 0:L(e.toolsBeforePlanMode);if(e.toolsBeforePlanMode!==void 0&&!t)return;let n=e.modelBeforePlanMode===void 0?void 0:P(e.modelBeforePlanMode);if(e.modelBeforePlanMode!==void 0&&!n)return;let r=e.thinkingBeforePlanMode===void 0?void 0:F(e.thinkingBeforePlanMode);if(e.thinkingBeforePlanMode!==void 0&&r===void 0)return;let i=e.planId===void 0?void 0:N(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 Ge(e){if(M(e))return R(e)??z(e)}function Ke(e){if(!M(e)||!N(e.content)||!N(e.path)||!N(e.sessionId)||!N(e.title)||!N(e.writtenAt))return;let t=e.planId===void 0?void 0:N(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 B(e,t,n){if(!N(e))throw Error(`${t} must be a string.`);let r=e.trim();if(n&&!r)throw Error(`${t} must not be empty.`);if(ee.Buffer.byteLength(r,`utf8`)>4096)throw Error(`${t} exceeds the bounded debug evidence limit.`);return r}function V(e,t){if(!Array.isArray(e)||e.length>32)throw Error(`${t} must be a bounded string array.`);return e.map((e,n)=>B(e,`${t}[${n}]`,!1))}function H(e,t){return e===void 0?``:B(e,t,!1)}function U(e,t){return e===void 0?[]:V(e,t)}function W(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 qe(e){if(!M(e))throw Error(`Debug evidence must be an object.`);W(e,[`issue`,`expectedBehavior`,`reproductionAttempt`,`actualBehavior`,`logs`,`correlatedTraceEvidence`,`processOutput`,`browserConsoleEvidence`,`correlationIds`,`timestamps`,`verifiedFacts`,`hypotheses`,`unavailableEvidence`],`Debug evidence`);let t={issue:B(e.issue,`issue`,!0),expectedBehavior:H(e.expectedBehavior,`expectedBehavior`),reproductionAttempt:H(e.reproductionAttempt,`reproductionAttempt`),actualBehavior:H(e.actualBehavior,`actualBehavior`),logs:U(e.logs,`logs`),correlatedTraceEvidence:U(e.correlatedTraceEvidence,`correlatedTraceEvidence`),processOutput:U(e.processOutput,`processOutput`),browserConsoleEvidence:U(e.browserConsoleEvidence,`browserConsoleEvidence`),correlationIds:U(e.correlationIds,`correlationIds`),timestamps:U(e.timestamps,`timestamps`),verifiedFacts:U(e.verifiedFacts,`verifiedFacts`),hypotheses:U(e.hypotheses,`hypotheses`),unavailableEvidence:U(e.unavailableEvidence,`unavailableEvidence`)};if(ee.Buffer.byteLength(JSON.stringify(t),`utf8`)>32768)throw Error(`Debug evidence exceeds the bounded packet size.`);return t}function Je(e,t){return n=>n.filter(n=>n===oe||n===se?e!==void 0:n===de?e===`fable`:n===ue?e===`debug`:t.has(n)?e===void 0||e===`debug`:e===void 0||!De.has(n))}function G(e){if(e.output=!1,e.progress=!1,e.worktree=!1,Array.isArray(e.parallel))for(let t of e.parallel)G(t);else e.parallel&&G(e.parallel)}function Ye(e){if(e.action!==void 0){e.action===`run`&&(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??[])G(t);for(let t of e.chain??[])G(t)}function Xe(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 Ze(e,t){if(e.action===`run`)for(let n of e.requests??[])n.model=t}function Qe(e,t){if(e.action===`assign`)for(let n of e.assignments??[])n.model=t}function $e(e){return new Set([`append-step`,`create`,`delete`,`disable`,`eject`,`enable`,`grant-spawn-budget`,`reset`,`schedule`,`schedule-cancel`,`update`,`watchdog.configure`]).has(e??``)}function et(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 tt(e=process.env,n=process.cwd()){return t.loadDoomConfig((0,l.loadHarnessState)(e).state.root??n).modes?.planning}function nt(e){let t={key:`p`,label:`plan`,detail:`read-only planning modes`,order:60};return[e?{id:`plan.exit`,path:[t,{key:`e`,label:`exit`,detail:`restore and exit`,tone:`exit`}],action:{name:`plan.exit`}}:{id:`plan.normal`,path:[t,{key:`e`,label:`enter`,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`}}]}function K(e,t=tt,u=i.createPlanTelemetry(),p={}){let b=!0,x=0,S,C,O,k,De,Ae,je,Ne=()=>{let e=je?.modelRegistry;return e?e.getAvailable().filter(t=>e.hasConfiguredAuth(t)).map(e=>({provider:e.provider,id:e.id})):[]},N=!1,P,F,I,L,Ue,R,z,B,V=!1,H=!1,U=!1,W,G,K=`idle`,q,J,Y,rt,it=Promise.resolve(),at=p.doomIntegrations??!0,ot=p.planPointers??new o.PlanPointerService({env:process.env}),st=new Set(p.debugDiagnosticTools??be),ct,lt=()=>Je(N?P:void 0,st),ut=()=>{ct?.update(lt())},dt=new AbortController,ft=p.fableBroker??{start:(e,t)=>{let n=R;if(!n)throw Error(`The session-bound Fable broker is unavailable.`);return n.start(e,t)},cancel:(e,t)=>{R?.cancel({requester:`@agimon-ai/doompi-plan`,operationId:e,reason:t})}},pt=()=>p.fableBroker!==void 0||R!==void 0;function X(e=x){if(!b||e!==x)throw Error(`Plan runtime is disposed or stale.`)}async function mt(){let e=W;if(!e||!e.modes.list().some(e=>e.descriptor.source===_.DOOM_VOICE_SOURCE&&e.descriptor.id===_.DOOM_VOICE_AUTO_MODE_ID&&e.state.activation===`active`))return!1;try{return await e.narration.request(Te),!0}catch(e){return u.recordWarning(i.PLAN_EVENT.planReviewCompleted,e,{"plan.outcome":`narration_failed`}),!1}}function ht(){return{content:[{type:`text`,text:`${we}\n\nThe choices were spoken through autonomous voice. Stop now and wait for the user's next message; it will arrive as an ordinary user message.`}],details:{answers:[],awaitingResponse:!0,cancelled:!1,delivery:`voice`,voicePrompt:we},terminate:!0}}function gt(){return S??=(async()=>{b=!1,x+=1,dt.abort(Error(`Plan runtime is shutting down.`));let e=J,t=F,n=[];rt?.cancel(`Plan runtime is shutting down.`);let r=[it,...Y?[Y]:[]],i=await Promise.allSettled(r);for(let e of i)e.status===`rejected`&&n.push(e.reason);if(N&&t&&e)try{await Tt(e,t,!0)&&ct?.update(Je(void 0,st))}catch(e){n.push(e)}let a=[()=>xt(e),()=>L?.dispose(),()=>De?.(),()=>k?.dispose(),()=>O?.dispose(),()=>C?.dispose()];for(let e of a)try{e()}catch(e){n.push(e)}L=void 0,W=void 0,De=void 0,k=void 0,O=void 0,C=void 0,Y=void 0,J=void 0,U=!1,N=!1,P=void 0,F=void 0,I=void 0;try{await u.shutdown()}catch(e){n.push(e)}if(n.length>0)throw AggregateError(n,`Plan runtime cleanup failed.`)})(),S}function _t(){b&&O?.update(nt(N))}function vt(){let e=P,t=e===`fable`&&K!==`idle`?` · ${K}`:``;return{activation:N?`active`:`inactive`,condition:K===`failed`?`failed`:K===`interrupted`?`degraded`:`ready`,...N&&e?{detail:`${e}${t} - read only`,color:T,modelContextVariant:e}:{},actions:[{id:fe,enabled:!0},...N?[{id:pe,enabled:!0}]:[{id:pe,enabled:!1,disabledReason:`Plan mode is inactive.`}]]}}function yt(e,t){try{return e.ui.theme.fg(T,t)}catch{return t}}function Z(e){if(!b)return;_t();let t=P,n=N&&t?`plan:${t}`:void 0;e.ui.setStatus(`plan-mode`,n?yt(e,n):void 0),C?.publish(vt())}function bt(e,t){try{ot.write(e.sessionManager.getSessionId(),{path:t.path,title:t.title,writtenAt:t.writtenAt,...t.planId===void 0?{}:{planId:t.planId}})}catch(e){u.recordWarning(i.PLAN_EVENT.planPointerFailed,`The plan pointer was not recorded.`,{"plan.reason":e instanceof Error?e.name:`unknown`})}e.hasUI&&(e.ui.setStatus(c.PLAN_STATUS_KEY,c.formatPlanStatus(t.title,Re(t.writtenAt))),H=!0)}function xt(e){if(e){try{ot.clear(e.sessionManager.getSessionId())}catch{}H&&(H=!1,e.hasUI&&e.ui.setStatus(c.PLAN_STATUS_KEY,void 0))}}function St(){if(!b||!at||!N||!P||!J)return;let e=[...Oe],t={owner:w,allowedTools:e,requiredTools:[y],allowMcpTools:!0,allowedExternalProfiles:P===`fable`?[n.FABLE_PLAN_PROFILE]:[],denyExtensions:!1};L?L.update(t):L=Ue?.register(t)}function Q(){b&&e.appendEntry(ie,{version:2,...N&&P?{activeFlavor:P}:{},...F?{originalSnapshot:{tools:[...F.tools],...F.model?{model:{...F.model}}:{},thinking:F.thinking}}:{},...B?{planId:B}:{},...q?{interruptedFableStage:q}:{}})}function Ct(e,t,n){u.recordWarning(i.PLAN_EVENT.modelResolveFailed,`Planning model ${n}: ${t}`,{[ge]:t,"plan.model.phase":e,"plan.model.reason":n})}async function wt(t){let n=x;X(n);let r=I?.main;if(r){if(r.model){let i=et(r.model,t);if(!i)t.ui.notify(`Planning model not found: ${r.model}`,T),Ct(`apply`,r.model,_e);else{let a=await e.setModel(i);X(n),a||(t.ui.notify(`Planning model is unavailable without authentication: ${r.model}`,T),Ct(`apply`,r.model,ve))}}X(n),r.thinking&&e.setThinkingLevel(r.thinking)}}async function Tt(t,n,r=!1){let a=x;if(r||X(a),!n)return!1;if(n.model){let o=`${n.model.provider}/${n.model.id}`,s=t.modelRegistry.find(n.model.provider,n.model.id);if(!s)return t.ui.notify(`Previous model not found: ${o}`,T),Ct(`restore`,o,_e),!1;try{let n=await e.setModel(s);if(r||X(a),!n)return t.ui.notify(`Previous model is unavailable without authentication: ${o}`,T),Ct(`restore`,o,ve),!1}catch(e){return r||X(a),t.ui.notify(`Previous model could not be restored: ${o}`,T),Ct(`restore`,o,ye),u.recordError(i.PLAN_EVENT.modelResolveFailed,e,{[ge]:o,"plan.model.phase":`restore`,"plan.model.reason":ye}),!1}}return r||X(a),e.setThinkingLevel(n.thinking),!0}function Et(e){N&&P?e.ui.notify(`Already in plan:${P}.`,me):e.ui.notify(`Plan mode is inactive.`,me)}function $(e){let t=x,n=async()=>{X(t);let n=await e();return X(t),n},r=it.then(n,n);return it=r.then(()=>void 0,()=>void 0),r}async function Dt(e){let t=x;if(X(t),!Y&&!K.match(/^(draft|review)$/u))return;(K===`draft`||K===`review`)&&(q=K),rt?.cancel(e);let n=Y;if(n)try{await n,X(t)}catch(e){X(t),u.recordError(i.PLAN_EVENT.modeDisabled,e,{[D]:`fable`,"plan.fable.reason":`cancel_failed`})}X(t),Y=void 0,q&&(K=`interrupted`),J&&Z(J),Q()}async function Ot(n,r,a,o){let s=x;if(X(s),J=n,N){if(P===r){Et(n);return}P===`fable`&&await Dt(`Leaving Fable for plan:${r}.`),X(s),P=r,St(),ut(),Z(n),Q(),u.recordEvent(i.PLAN_EVENT.modeEnabled,{[E]:a,[D]:r,"plan.tool.count":e.getActiveTools().length});return}let c;try{c=t()}catch(e){throw u.recordError(i.PLAN_EVENT.configLoadFailed,e,{[E]:a}),e}o?B??=Be():(z=void 0,V=!1,U=!1,B=Be(),q=void 0,K=`idle`),I=c,F??={tools:[...e.getActiveTools()],...n.model?{model:{provider:n.model.provider,id:n.model.id}}:{},thinking:e.getThinkingLevel()},N=!0,P=r,ut(),St(),await wt(n),X(s),Z(n),Q(),u.recordEvent(i.PLAN_EVENT.modeEnabled,{[E]:a,[D]:r,"plan.tool.count":e.getActiveTools().length,...I?.main?.model?{[ge]:I.main.model}:{},...I?.main?.thinking?{"plan.thinking":I.main.thinking}:{}})}async function kt(e,t){let n=x;if(X(n),!N)return Et(e),!1;await Dt(`Plan mode is exiting.`),X(n);let r=await Tt(e,F);if(X(n),!r)return e.ui.notify(`Previous model was not restored. Plan mode remains read-only.`,T),Z(e),Q(),u.recordWarning(i.PLAN_EVENT.modeDisabled,`Plan mode restoration failed.`,{[E]:t,[D]:P??`unknown`,"plan.restored":!1}),!1;let a=!!z;return ct?.update(Je(void 0,st)),L?.dispose(),L=void 0,N=!1,P=void 0,I=void 0,U=!1,F=void 0,G=void 0,K=`idle`,q=void 0,Z(e),Q(),u.recordEvent(i.PLAN_EVENT.modeDisabled,{[E]:t,[D]:`normal`,"plan.written":a,"plan.restored":!0}),!0}rt=n.createFablePlanFlow({broker:ft,isAuthorized:()=>b&&N&&P===`fable`&&pt(),onStage:e=>{b&&(K=e,(e===`completed`||e===`failed`||e===`cancelled`)&&(q=void 0),J&&Z(J),N&&Q())},onError:e=>{b&&u.recordError(i.PLAN_EVENT.modeEnabled,e,{[D]:`fable`,"plan.fable.reason":`flow_error`})}});async function At(e,t){if(X(),u.recordEvent(i.PLAN_EVENT.planReviewCompleted,{"plan.outcome":e===Se?`exited`:`continued`}),e===Se){let e=await $(()=>kt(t,`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 V=!1,{content:[{type:`text`,text:`The user chose to continue planning. Remain read-only and refine the plan.`}],details:{exited:!1}}}return{services:[e=>{if(e.inject([h.DOOM_TOOL_SURFACE_SERVICE],e=>{let t=(0,h.readDoomToolSurface)(e);if(!t)return;let n=t.register({source:w,restrict:lt()});return ct=n,()=>{ct===n&&(ct=void 0,n.dispose())}}),e.inject([a.DOOM_FABLE_PLAN_SERVICE],e=>{let t=a.readDoomFablePlanService(e);if(t)return R=t,()=>{R===t&&(R=void 0,Y&&rt?.cancel(`The Team Fable service was unloaded.`))}}),e.inject([a.DOOM_SUBAGENT_POLICY_SERVICE],e=>{let t=a.readDoomSubagentPolicyService(e);if(t)return Ue=t,St(),()=>{Ue===t&&(L?.dispose(),L=void 0,Ue=void 0)}}),at&&(e.inject([v.DOOM_MINOR_MODE_CATALOG_SERVICE,re.DOOM_NARRATION_SERVICE],e=>{let t={modes:(0,v.requireMinorModeCatalog)(e),narration:(0,re.requireDoomNarrationService)(e)};return W=t,()=>{W===t&&(W=void 0)}}),e.inject([v.DOOM_MINOR_MODE_CATALOG_SERVICE],e=>{let t=(0,v.registerMinorModeOwner)((0,v.requireMinorModeCatalog)(e),{descriptor:{source:w,id:`plan`,label:`Plan`,description:`Read-only planning with normal, debug, and Fable flavors.`,order:40,actions:[{id:fe,label:`Activate`,description:`Activate plan mode or switch its planning flavor.`,contexts:[`tui`,`headless`],parameters:[{name:`flavor`,label:`Flavor`,kind:`enum`,required:!0,choices:[{value:`normal`,label:`Normal`},{value:`debug`,label:`Debug`},{value:`fable`,label:`Fable`}]}]},{id:pe,label:`Deactivate`,description:`Exit plan mode and restore the previous agent configuration.`,contexts:[`tui`,`headless`],parameters:[]}]},initialState:vt(),async handleAction(e,t,n){if(!b)throw Error(`Plan runtime is disposed.`);if(e===fe){let e=t.flavor;if(e!==`normal`&&e!==`debug`&&e!==`fable`)throw Error(`A valid plan flavor is required.`);return await $(()=>Ot(n.context,e,A,!1)),{message:`Plan mode is active with the ${e} flavor.`}}if(e===pe)return{message:await $(()=>kt(n.context,A))?`Plan mode deactivated.`:`Plan mode remains active.`};throw Error(`Unknown plan mode action: ${e}`)},onError:e=>void u.recordError(i.PLAN_EVENT.configLoadFailed,e)});return C=t,()=>{t.dispose(),C===t&&(C=void 0)}}),e.inject([g.DOOM_UI_HUB_SERVICE],e=>{let n=(0,g.requireDoomUiHub)(e),i=n.registerLeader({source:w,bindings:nt(N)}),a=n.registerConfig({source:w,listSections:()=>{let e=Ne();try{return r.planConfigSections(t(),Ae,e)}catch(t){return r.planConfigSections(void 0,t instanceof Error?t.message:String(t),e)}},handlers:{[m.CONFIG_ACTION.set]:async({fieldId:e,value:t})=>{let n=r.planSettingByFieldId(e);n&&t&&(Ae=void 0,await(0,f.setDoomConfigValue)((0,l.globalDoomConfigPath)(),[...n.keyPath],t))},[m.CONFIG_ACTION.clear]:async({fieldId:e})=>{let t=r.planSettingByFieldId(e);t&&(Ae=void 0,await(0,f.unsetDoomConfigValue)((0,l.globalDoomConfigPath)(),[...t.keyPath]))}},onError:e=>{b&&(Ae=e instanceof Error?e.message:String(e))}});return O=i,k=a,()=>{a.dispose(),i.dispose(),k===a&&(k=void 0),O===i&&(O=void 0)}})),at){let t=e=>{if(X(),e.aborted)throw e.reason instanceof Error?e.reason:Error(`Plan voice transition was cancelled.`)},n={descriptor:{source:Me,id:`plan-activate`,name:`activate_plan`,label:`Activate Plan`,description:`Activate or switch the serialized read-only planning mode flavor.`,order:10,inputSchema:Pe,resultSchema:Ie},execute(e,n){let r=We(M(e)?e.flavor:void 0);if(!r)throw Error(`A valid plan flavor is required.`);return t(n.signal),$(async()=>{t(n.signal);let e=N,i=P;return await Ot(n.context,r,ke,!1),{active:N,flavor:P??r,changed:e!==N||i!==P}})}},r={descriptor:{source:Me,id:`plan-exit`,name:`exit_plan`,label:`Exit Plan`,description:`Exit read-only planning mode and restore the previous agent configuration.`,order:20,inputSchema:Fe,resultSchema:Ie},execute(e,n){return t(n.signal),$(async()=>{t(n.signal);let e=N,r=await kt(n.context,ke);return{active:N,flavor:P??null,changed:e!==N||r}})}};e.inject([_.DOOM_VOICE_TOOLS_SERVICE],e=>{let t=(0,_.requireDoomVoiceToolsService)(e),i=t.register(n),a=t.register(r);return()=>{a.dispose(),i.dispose()}})}at&&e.inject([g.DOOM_UI_HUB_SERVICE],e=>{let t=(0,g.requireDoomUiHub)(e).registerLeaderActions({source:w,handlers:{"plan.normal":()=>{let e=b?J:void 0;return e?$(()=>Ot(e,`normal`,A,!1)):void 0},"plan.exit":()=>{let e=b?J:void 0;return e?$(async()=>{await kt(e,A)}):void 0},"plan.debug":()=>{let e=b?J:void 0;return e?$(()=>Ot(e,`debug`,A,!1)):void 0},"plan.fable":()=>{let e=b?J:void 0;return e?$(()=>Ot(e,`fable`,A,!1)):void 0}},onError:(e,t)=>{b&&(J?.hasUI&&J.ui.notify(`Leader action ${t} failed. Plan mode remains read-only.`,T),u.recordError(i.PLAN_EVENT.modeEnabled,e,{[E]:A,"plan.action":t}))}});return De=t,()=>{t(),De===t&&(De=void 0)}})}],onStop:gt,onDispose:gt,tools:[{name:ue,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(X(),!N||P!==`debug`)return{content:[{type:`text`,text:`Debug planning is not active.`}],details:{recorded:!1}};try{G=qe(t)}catch(e){throw u.recordWarning(i.PLAN_EVENT.modeEnabled,e,{[D]:`debug`,"plan.debug.reason":`invalid_evidence`}),e}return J&&Z(J),{content:[{type:`text`,text:`Debug evidence recorded as optional planning context.`}],details:{recorded:!0}}}},{name:de,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){let r=x;if(X(r),!N||P!==`fable`)return{content:[{type:`text`,text:`Fable planning is not active.`}],details:{started:!1}};if(!pt())return{content:[{type:`text`,text:`The local Fable broker is unavailable. Fable planning remains disabled.`}],details:{started:!1,errorCode:`broker_unavailable`}};let i=rt;if(!i)throw Error(`Fable planning flow is unavailable.`);let a=i.run(t,n);Y=a;try{let e=await a;return X(r),{content:[{type:`text`,text:e.draft?`Fable draft:\n${e.draft}`:`Fable planning ${e.status}: ${e.errorCode??`no output`}.`}],details:{...e,started:!0}}}finally{b&&r===x&&Y===a&&(Y=void 0)}}},{name:se,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,a,o){let s=x;if(X(s),!N)return{content:[{type:`text`,text:`Plan mode is disabled. Use normal file tools instead.`}],details:{written:!1}};let c=Ve(o.sessionManager.getBranch(),t);if(!c){let e=Error(`Present the complete implementation plan as visible Markdown in chat before calling write_plan.`);throw u.recordError(i.PLAN_EVENT.writePlanFailed,e,{"plan.reason":`missing_visible_plan`}),e}let f=Date.now(),p=(0,l.getHarnessState)().root??o.cwd,m=(0,l.resolvePlanningPlansDirectory)(I?.plansDirectory,p,te.default.homedir()),re=ze(o.sessionManager.getSessionId());B??=Be();let h=z?.planId===B&&ne.default.dirname(z.path)===m?z.path:void 0,g=Le(c),_=B,v=h??ne.default.join(m,`${g}--${_}.md`),ie=new AbortController,oe=Error(`Writing ${v} timed out after ${xe}ms.`),se=setTimeout(()=>ie.abort(oe),xe),y=AbortSignal.any([ie.signal,dt.signal,...r?[r]:[]]),S=`checking`,ce=()=>{a?.({content:[{type:`text`,text:`${S===`checking`?`Checking`:`Writing`} ${v}...`}],details:{phase:S,path:v,startedAt:f}})},le=(e,t)=>{u.recordWarning(i.PLAN_EVENT.writePlanUnsafePath,t,{"plan.phase":S,"plan.refusal":e})};try{ce();try{await j(()=>d.default.promises.mkdir(m,{recursive:!0,mode:448}),y)}catch(e){throw y.aborted?He(y):Error(`Could not create the configured plans directory ${m}.`,{cause:e})}let t=await j(()=>d.default.promises.lstat(m),y),n=await j(()=>d.default.promises.realpath(m),y);if(t.isSymbolicLink()||!t.isDirectory())return le(`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:S,durationMs:Date.now()-f}};X(s),S=`writing`,ce();let r;try{for(let e=0;e<3;e+=1)try{let e=h?0:d.default.constants.O_EXCL;r=await j(()=>d.default.promises.open(v,d.default.constants.O_CREAT|d.default.constants.O_WRONLY|d.default.constants.O_NONBLOCK|d.default.constants.O_NOFOLLOW|e,384),y);break}catch(t){if(!(!h&&t instanceof Error&&`code`in t&&String(t.code)===`EEXIST`)||e===2)throw t;_=Be(),B=_,v=ne.default.join(m,`${g}--${_}.md`),Q()}if(!r)throw Error(`Could not allocate a unique plan filename in ${m}.`);let e=await j(()=>d.default.promises.realpath(m),y),t=await j(()=>r.stat(),y);if(e!==n||!t.isFile()||t.nlink!==1)return le(`invalid_destination`,he),{content:[{type:`text`,text:he}],details:{written:!1,path:v,phase:S,durationMs:Date.now()-f}};await j(()=>r.truncate(0),y),await j(()=>r.writeFile(c,{encoding:`utf8`,signal:y}),y)}catch(e){if(e instanceof Error&&`code`in e&&[`EISDIR`,`ELOOP`,`ENXIO`].includes(String(e.code)))return le(`invalid_destination`,he),{content:[{type:`text`,text:he}],details:{written:!1,path:v,phase:S,durationMs:Date.now()-f}};throw e}finally{await r?.close()}return X(s),z={content:c,path:v,sessionId:re,planId:_,title:g,writtenAt:new Date().toISOString()},e.appendEntry(ae,z),bt(o,z),V=!0,U=!1,u.recordEvent(i.PLAN_EVENT.planWritten,{"plan.written":!0,"plan.bytes":ee.Buffer.byteLength(c,`utf8`),"plan.duration_ms":Date.now()-f,"plan.revised":!!h}),{content:[{type:`text`,text:`Wrote implementation plan to ${v}.`}],details:{written:!0,path:v,phase:S,durationMs:Date.now()-f}}}catch(e){if(!b||s!==x)throw He(dt.signal);let t={"plan.phase":S,"plan.duration_ms":Date.now()-f};if(ie.signal.aborted&&!r?.aborted){let n=Error(`write_plan timed out during ${S} for ${v}.`,{cause:e});throw u.recordError(i.PLAN_EVENT.writePlanTimedOut,n,{...t,"plan.timeout_ms":xe}),n}throw u.recordError(i.PLAN_EVENT.writePlanFailed,e,{...t,"plan.cancelled":r?.aborted??!1}),e}finally{clearTimeout(se)}}},{name:oe,label:`Complete Plan`,description:`Present the saved implementation plan for exit-or-continue approval. Interactive sessions use the normal selector; autonomous voice narrates a plain-text handoff and waits for the next user message.`,promptSnippet:`Request explicit exit-or-continue approval after the saved plan has been presented`,promptGuidelines:[`After write_plan succeeds, call complete_plan without a decision so it can present the review question.`,`When autonomous voice returns an awaiting-response result, stop. Interpret the next ordinary user message, then call complete_plan again with decision "exit" or "continue".`,`Never pass decision "${Se}" without the user explicitly choosing "${c.EXIT_PLAN_MODE_CHOICE}".`],parameters:{type:`object`,properties:{decision:{type:`string`,enum:[Se,Ce]}},additionalProperties:!1},async execute(e,t,n,r,a){let o=x;if(X(o),!N)return{content:[{type:`text`,text:`Plan mode is already disabled.`}],details:{exited:!1}};if(!V)return{content:[{type:`text`,text:`Present the complete plan in chat and save it with write_plan before requesting approval.`}],details:{exited:!1}};if(!a.hasUI)return u.recordEvent(i.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 s=M(t)?t.decision:void 0,l=s===Se||s===Ce;if(U){if(!l)throw Error(`The narrated plan review is waiting for an explicit exit or continue decision.`);return U=!1,At(s,a)}if(s!==void 0)throw Error(`Call complete_plan without a decision before submitting a narrated plan-review answer.`);if(await mt())return X(o),U=!0,ht();let ee=await a.ui.select(c.PLAN_REVIEW_TITLE,[...c.PLAN_REVIEW_OPTIONS]);return X(o),At(ee===`Exit plan mode and start implementation`?Se:Ce,a)}}],events:{tool_call:async(e,t)=>{if(!b||!N)return;let n=P===`debug`&&(e.toolName===ue||st.has(e.toolName))||P===`fable`&&e.toolName===de;if(!Ee.has(e.toolName)&&!n)return{block:!0,reason:`Plan mode blocks the ${e.toolName} tool. Use SPC p e to restore access.`};let r=Xe(I?.subagents,t.model);if(e.toolName===le){r&&Qe(e.input,r);return}if(e.toolName!==ce)return;let i=e.input;if($e(i.action))return{block:!0,reason:`Plan mode blocks subagent management action '${i.action}'. Use SPC p e first.`};Ye(i),r&&Ze(i,r)},before_agent_start:async(e,t)=>{if(!b)return;let n=[];if(N){let e=(0,l.getHarnessState)().root??t.cwd,r=(0,l.resolvePlanningPlansDirectory)(I?.plansDirectory,e,te.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 your turn; completion notifications wake the parent session.\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 without a decision. In an interactive text session, complete_plan uses the normal exit-or-continue selector. Under autonomous voice, it displays and narrates the choices without opening a blocking dialog, then ends the turn. Interpret the user's next ordinary message and call complete_plan again with decision "exit" or "continue". Do not exit plan mode without explicit approval.`,s.buildFlavorPlanningPrompt(P,r,G,K))}if(z){let e=z.content;try{e=await d.default.promises.readFile(z.path,`utf8`)}catch{e=z.content}n.push(`[CURRENT PLAN]\nSource: ${z.path}\n\n${e}`)}if(n.length!==0)return{systemPrompt:`${e.systemPrompt}\n\n${n.join(`
|
|
5
|
+
|
|
6
|
+
`)}`}},context:async e=>{if(b)return{messages:e.messages.filter(e=>e.customType!==`agent-harness-plan-mode-context`)}},session_start:async(e,t)=>{if(!b)return;je=t;let n=++x,r=t.sessionManager.getEntries(),i=r.flatMap(e=>e.type===`custom`&&e.customType===ie?[Ge(e.data)]:[]).filter(e=>e!==void 0).at(-1),a=ze(t.sessionManager.getSessionId()),o=r.flatMap(e=>e.type===`custom`&&e.customType===ae?[Ke(e.data)]:[]).filter(e=>e!==void 0).at(-1),s=F;if(L?.dispose(),L=void 0,z=o?.sessionId===a?o:void 0,z?bt(t,z):xt(t),B=i?.planId??z?.planId,V=!1,U=!1,I=void 0,G=void 0,N=!1,P=void 0,_t(),F=i?.originalSnapshot,q=i?.interruptedFableStage,K=q?`interrupted`:`idle`,J=t,i?.activeFlavor)await Ot(t,i.activeFlavor,`session_restore`,!0),X(n);else{let e=i?.originalSnapshot??s;e&&(await Tt(t,e),X(n)),ut(),X(n),F=void 0,Z(t)}}}}}exports.WRITE_PLAN_TIMEOUT_MS=xe,exports.configurePlanningSubagentInput=Ze,exports.configurePlanningTaskInput=Qe,exports.constrainSubagentInput=Ye,exports.createPlanIdentifier=Be,exports.createPlanModeRuntime=K,exports.isBlockedSubagentManagementAction=$e,exports.loadPlanningModeConfig=tt,exports.parseDebugEvidencePacket=qe,exports.parsePersistedPlanState=Ge,exports.planSessionIdentifier=ze,exports.planTitleSlug=Le,exports.planToolRestriction=Je,exports.planningSubagentModel=Xe,exports.visiblePlanForToolCall=Ve;
|
|
7
|
+
//# sourceMappingURL=planMode.cjs.map
|