lsd-pi 1.1.2 → 1.1.3
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 +2 -1
- package/dist/bedrock-auth.d.ts +25 -0
- package/dist/bedrock-auth.js +59 -0
- package/dist/headless.js +8 -3
- package/dist/loader.js +1 -0
- package/dist/onboarding-llm.d.ts +37 -0
- package/dist/onboarding-llm.js +64 -0
- package/dist/onboarding.d.ts +2 -14
- package/dist/onboarding.js +146 -71
- package/dist/pi-migration.js +1 -0
- package/dist/resources/extensions/memory/auto-extract.js +21 -3
- package/dist/resources/extensions/memory/dream.js +703 -0
- package/dist/resources/extensions/memory/extension-manifest.json +2 -2
- package/dist/resources/extensions/memory/index.js +115 -8
- package/dist/resources/extensions/slash-commands/extension-manifest.json +10 -10
- package/dist/resources/extensions/slash-commands/index.js +0 -4
- package/dist/resources/extensions/slash-commands/plan.js +181 -45
- package/dist/resources/extensions/subagent/agents.js +14 -1
- package/dist/resources/extensions/subagent/configured-model.js +3 -2
- package/dist/resources/extensions/subagent/index.js +34 -28
- package/dist/resources/extensions/subagent/launch-helpers.js +24 -0
- package/dist/resources/extensions/subagent/model-resolution.js +41 -3
- package/dist/resources/extensions/usage/extension-manifest.json +11 -0
- package/dist/resources/extensions/usage/index.js +346 -0
- package/{src/resources/skills/create-gsd-extension → dist/resources/skills/create-lsd-extension}/SKILL.md +6 -6
- package/{src/resources/skills/create-gsd-extension → dist/resources/skills/create-lsd-extension}/references/custom-tools.md +1 -1
- package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extension-lifecycle.md +2 -2
- package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extensioncontext-reference.md +1 -1
- package/{src/resources/skills/create-gsd-extension → dist/resources/skills/create-lsd-extension}/references/key-rules-gotchas.md +4 -4
- package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/packaging-distribution.md +6 -6
- package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/create-extension.md +3 -3
- package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/debug-extension.md +5 -5
- package/dist/resources/skills/teams-debug/SKILL.md +5 -6
- package/dist/resources/skills/teams-document/SKILL.md +1 -2
- package/dist/resources/skills/teams-plan/SKILL.md +3 -4
- package/dist/resources/skills/teams-run/SKILL.md +3 -4
- package/dist/resources/skills/teams-verify/SKILL.md +4 -5
- package/dist/startup-model-validation.js +1 -0
- package/dist/welcome-screen.js +13 -11
- package/dist/wizard.js +12 -0
- package/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +688 -409
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +761 -488
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +40 -18
- package/packages/pi-ai/src/models.generated.ts +759 -486
- package/packages/pi-coding-agent/dist/cli/config-selector.js +1 -1
- package/packages/pi-coding-agent/dist/cli/config-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +1 -2
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +6 -30
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +44 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js +9 -5
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +3 -2
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +1 -1
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +15 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +25 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +10 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +31 -22
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +18 -5
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +139 -20
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/cli/config-selector.ts +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +5 -28
- package/packages/pi-coding-agent/src/core/settings-manager.ts +52 -1
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +18 -5
- package/packages/pi-coding-agent/src/core/skills.ts +3 -2
- package/packages/pi-coding-agent/src/index.ts +1 -1
- package/packages/pi-coding-agent/src/main.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +2 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +12 -13
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +39 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +46 -20
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +171 -20
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +4 -0
- package/packages/pi-tui/dist/components/editor.d.ts +1 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +23 -0
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/src/components/editor.ts +23 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts +18 -5
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +139 -20
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +4 -0
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/memory/auto-extract.ts +23 -3
- package/src/resources/extensions/memory/dream.ts +814 -0
- package/src/resources/extensions/memory/extension-manifest.json +2 -2
- package/src/resources/extensions/memory/index.ts +134 -13
- package/src/resources/extensions/memory/tests/auto-extract.test.ts +10 -2
- package/src/resources/extensions/memory/tests/dream.test.ts +142 -0
- package/src/resources/extensions/slash-commands/extension-manifest.json +10 -10
- package/src/resources/extensions/slash-commands/index.ts +3 -7
- package/src/resources/extensions/slash-commands/plan.ts +192 -46
- package/src/resources/extensions/subagent/agents.ts +11 -1
- package/src/resources/extensions/subagent/configured-model.ts +3 -2
- package/src/resources/extensions/subagent/index.ts +38 -30
- package/src/resources/extensions/subagent/launch-helpers.ts +30 -0
- package/src/resources/extensions/subagent/model-resolution.ts +40 -3
- package/src/resources/extensions/usage/extension-manifest.json +11 -0
- package/src/resources/extensions/usage/index.ts +441 -0
- package/{dist/resources/skills/create-gsd-extension → src/resources/skills/create-lsd-extension}/SKILL.md +6 -6
- package/{dist/resources/skills/create-gsd-extension → src/resources/skills/create-lsd-extension}/references/custom-tools.md +1 -1
- package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extension-lifecycle.md +2 -2
- package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extensioncontext-reference.md +1 -1
- package/{dist/resources/skills/create-gsd-extension → src/resources/skills/create-lsd-extension}/references/key-rules-gotchas.md +4 -4
- package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/packaging-distribution.md +6 -6
- package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/create-extension.md +3 -3
- package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/debug-extension.md +5 -5
- package/src/resources/skills/teams-debug/SKILL.md +5 -6
- package/src/resources/skills/teams-document/SKILL.md +1 -2
- package/src/resources/skills/teams-plan/SKILL.md +3 -4
- package/src/resources/skills/teams-run/SKILL.md +3 -4
- package/src/resources/skills/teams-verify/SKILL.md +4 -5
- package/dist/resources/extensions/slash-commands/create-extension.js +0 -264
- package/dist/resources/extensions/slash-commands/create-slash-command.js +0 -208
- package/src/resources/extensions/slash-commands/create-extension.ts +0 -297
- package/src/resources/extensions/slash-commands/create-slash-command.ts +0 -234
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/compaction-session-control.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-commands.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-rendering.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-ui.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/events-reference.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extensionapi-reference.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/mode-behavior.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/model-provider-management.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/remote-execution-overrides.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/state-management.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/references/system-prompt-modification.md +0 -0
- /package/dist/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/add-capability.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/compaction-session-control.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-commands.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-rendering.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/custom-ui.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/events-reference.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/extensionapi-reference.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/mode-behavior.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/model-provider-management.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/remote-execution-overrides.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/state-management.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/references/system-prompt-modification.md +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/templates/extension-skeleton.ts +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/templates/stateful-tool-skeleton.ts +0 -0
- /package/src/resources/skills/{create-gsd-extension → create-lsd-extension}/workflows/add-capability.md +0 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"description": "Persistent file-based memory across sessions",
|
|
6
6
|
"tier": "bundled",
|
|
7
7
|
"provides": {
|
|
8
|
-
"hooks": ["session_start", "before_agent_start", "session_shutdown"],
|
|
9
|
-
"commands": ["memories", "remember", "forget"]
|
|
8
|
+
"hooks": ["session_start", "before_agent_start", "turn_end", "tool_call", "session_shutdown"],
|
|
9
|
+
"commands": ["memories", "remember", "forget", "dream", "auto-dream"]
|
|
10
10
|
}
|
|
11
11
|
}
|
|
@@ -7,15 +7,15 @@
|
|
|
7
7
|
* Memory files live under ~/.lsd/memory/<sanitized-project-path>/ and are
|
|
8
8
|
* indexed by a MEMORY.md entrypoint that is always loaded into context.
|
|
9
9
|
*/
|
|
10
|
+
import { isToolCallEventType, } from '@gsd/pi-coding-agent';
|
|
10
11
|
import { readFileSync, existsSync, writeFileSync } from 'node:fs';
|
|
11
12
|
import { getMemoryDir, getMemoryEntrypoint, ensureMemoryDir } from './memory-paths.js';
|
|
12
13
|
import { MEMORY_FRONTMATTER_EXAMPLE, TYPES_SECTION, WHAT_NOT_TO_SAVE_SECTION, WHEN_TO_ACCESS_SECTION, TRUSTING_RECALL_SECTION, } from './memory-types.js';
|
|
13
14
|
import { scanMemoryFiles } from './memory-scan.js';
|
|
14
15
|
import { memoryAge } from './memory-age.js';
|
|
15
16
|
import { extractMemories } from './auto-extract.js';
|
|
17
|
+
import { formatDreamStatus, isMaintenanceModeToolAllowed, maybeStartAutoDream, readAutoDreamSettings, setProjectAutoDreamEnabled, startDream, } from './dream.js';
|
|
16
18
|
// ── Constants ────────────────────────────────────────────────────────
|
|
17
|
-
/** Name of the entrypoint file that indexes all memories. */
|
|
18
|
-
const ENTRYPOINT_NAME = 'MEMORY.md';
|
|
19
19
|
/** Maximum number of lines loaded from MEMORY.md into context. */
|
|
20
20
|
const MAX_ENTRYPOINT_LINES = 200;
|
|
21
21
|
/** Maximum byte size loaded from MEMORY.md into context. */
|
|
@@ -109,14 +109,17 @@ ${MEMORY_FRONTMATTER_EXAMPLE.join('\n')}
|
|
|
109
109
|
* Memory extension for LSD.
|
|
110
110
|
*
|
|
111
111
|
* Lifecycle:
|
|
112
|
-
* session_start
|
|
112
|
+
* session_start → bootstrap memory directory & MEMORY.md
|
|
113
113
|
* before_agent_start → inject memory system prompt
|
|
114
|
+
* turn_end → check auto-dream gates and start background consolidation
|
|
114
115
|
* session_shutdown → fire-and-forget auto-extract of new memories
|
|
115
116
|
*
|
|
116
117
|
* Commands:
|
|
117
|
-
* /memories
|
|
118
|
-
* /remember
|
|
119
|
-
* /forget
|
|
118
|
+
* /memories — list all saved memories
|
|
119
|
+
* /remember — save a memory immediately
|
|
120
|
+
* /forget — remove a memory by topic
|
|
121
|
+
* /dream — run memory consolidation now or show dream status
|
|
122
|
+
* /auto-dream — enable/disable/show auto-dream status
|
|
120
123
|
*/
|
|
121
124
|
export default function memoryExtension(pi) {
|
|
122
125
|
let memoryCwd = '';
|
|
@@ -153,12 +156,49 @@ export default function memoryExtension(pi) {
|
|
|
153
156
|
systemPrompt: event.systemPrompt + '\n\n' + prompt,
|
|
154
157
|
};
|
|
155
158
|
});
|
|
159
|
+
// ── turn_end: check auto-dream gates ───────────────────────────────
|
|
160
|
+
pi.on('turn_end', async (_event, ctx) => {
|
|
161
|
+
if (!memoryCwd)
|
|
162
|
+
return;
|
|
163
|
+
const result = maybeStartAutoDream(ctx);
|
|
164
|
+
if (result.started) {
|
|
165
|
+
pi.sendMessage({
|
|
166
|
+
customType: 'memory:auto-dream',
|
|
167
|
+
content: result.message,
|
|
168
|
+
display: true,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
// ── tool_call: restrict background maintenance workers ─────────────
|
|
173
|
+
pi.on('tool_call', async (event, ctx) => {
|
|
174
|
+
if (!(process.env.LSD_MEMORY_EXTRACT === '1' || process.env.LSD_MEMORY_DREAM === '1'))
|
|
175
|
+
return;
|
|
176
|
+
if (isMaintenanceModeToolAllowed(event.toolName, event.input, ctx.cwd)) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (isToolCallEventType('write', event) || isToolCallEventType('edit', event)) {
|
|
180
|
+
return {
|
|
181
|
+
block: true,
|
|
182
|
+
reason: `Memory maintenance workers may only write inside the memory directory. Blocked path: ${event.input.path}`,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (isToolCallEventType('bash', event)) {
|
|
186
|
+
return {
|
|
187
|
+
block: true,
|
|
188
|
+
reason: 'Memory maintenance workers may only run read-only bash commands.',
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
block: true,
|
|
193
|
+
reason: `Tool ${event.toolName} is blocked for memory maintenance workers.`,
|
|
194
|
+
};
|
|
195
|
+
});
|
|
156
196
|
// ── session_shutdown: trigger auto-extract ────────────────────────
|
|
157
197
|
pi.on('session_shutdown', async (_event, ctx) => {
|
|
158
198
|
if (!memoryCwd)
|
|
159
199
|
return;
|
|
160
|
-
// Don't extract if this IS the extraction
|
|
161
|
-
if (process.env.LSD_MEMORY_EXTRACT === '1')
|
|
200
|
+
// Don't extract if this IS the extraction or dream worker
|
|
201
|
+
if (process.env.LSD_MEMORY_EXTRACT === '1' || process.env.LSD_MEMORY_DREAM === '1')
|
|
162
202
|
return;
|
|
163
203
|
try {
|
|
164
204
|
extractMemories(ctx, memoryCwd);
|
|
@@ -220,4 +260,71 @@ export default function memoryExtension(pi) {
|
|
|
220
260
|
pi.sendUserMessage(`Please find and remove any memories about: ${topic}`);
|
|
221
261
|
},
|
|
222
262
|
});
|
|
263
|
+
/**
|
|
264
|
+
* /dream — run a consolidation pass now, or show dream status.
|
|
265
|
+
*/
|
|
266
|
+
pi.registerCommand('dream', {
|
|
267
|
+
description: 'Run memory consolidation now or show dream status',
|
|
268
|
+
handler: async (args, ctx) => {
|
|
269
|
+
if (!memoryCwd)
|
|
270
|
+
return;
|
|
271
|
+
const subcommand = args.trim().toLowerCase();
|
|
272
|
+
if (subcommand === 'status') {
|
|
273
|
+
pi.sendMessage({
|
|
274
|
+
customType: 'memory:dream-status',
|
|
275
|
+
content: formatDreamStatus(ctx),
|
|
276
|
+
display: true,
|
|
277
|
+
});
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const result = startDream(ctx, { trigger: 'manual' });
|
|
281
|
+
pi.sendMessage({
|
|
282
|
+
customType: 'memory:dream',
|
|
283
|
+
content: result.message,
|
|
284
|
+
display: true,
|
|
285
|
+
});
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
/**
|
|
289
|
+
* /auto-dream — enable, disable, or inspect project auto-dream.
|
|
290
|
+
*/
|
|
291
|
+
pi.registerCommand('auto-dream', {
|
|
292
|
+
description: 'Enable, disable, or show project auto-dream status',
|
|
293
|
+
handler: async (args, ctx) => {
|
|
294
|
+
if (!memoryCwd)
|
|
295
|
+
return;
|
|
296
|
+
const subcommand = args.trim().toLowerCase();
|
|
297
|
+
if (subcommand === 'on') {
|
|
298
|
+
const settings = setProjectAutoDreamEnabled(memoryCwd, true);
|
|
299
|
+
pi.sendMessage({
|
|
300
|
+
customType: 'memory:auto-dream-settings',
|
|
301
|
+
content: `Auto-dream enabled for this project. Thresholds: ${settings.minHours}h / ${settings.minSessions} sessions.`,
|
|
302
|
+
display: true,
|
|
303
|
+
});
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (subcommand === 'off') {
|
|
307
|
+
const settings = setProjectAutoDreamEnabled(memoryCwd, false);
|
|
308
|
+
pi.sendMessage({
|
|
309
|
+
customType: 'memory:auto-dream-settings',
|
|
310
|
+
content: `Auto-dream disabled for this project. Thresholds remain ${settings.minHours}h / ${settings.minSessions} sessions.`,
|
|
311
|
+
display: true,
|
|
312
|
+
});
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
const settings = readAutoDreamSettings(memoryCwd);
|
|
316
|
+
pi.sendMessage({
|
|
317
|
+
customType: 'memory:auto-dream-status',
|
|
318
|
+
content: [
|
|
319
|
+
'Auto-Dream Settings',
|
|
320
|
+
'',
|
|
321
|
+
`- Enabled: ${settings.enabled ? 'yes' : 'no'}`,
|
|
322
|
+
`- Thresholds: ${settings.minHours}h / ${settings.minSessions} sessions`,
|
|
323
|
+
'',
|
|
324
|
+
formatDreamStatus(ctx),
|
|
325
|
+
].join('\n'),
|
|
326
|
+
display: true,
|
|
327
|
+
});
|
|
328
|
+
},
|
|
329
|
+
});
|
|
223
330
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
"id": "slash-commands",
|
|
3
|
+
"name": "Slash Commands",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Bundled slash commands for audit, clearing state, and plan workflows",
|
|
6
|
+
"tier": "bundled",
|
|
7
|
+
"requires": { "platform": ">=2.29.0" },
|
|
8
|
+
"provides": {
|
|
9
|
+
"commands": ["audit", "clear", "plan", "execute", "cancel-plan"],
|
|
10
|
+
"flags": ["plan"]
|
|
11
|
+
}
|
|
12
12
|
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import createSlashCommand from "./create-slash-command.js";
|
|
2
|
-
import createExtension from "./create-extension.js";
|
|
3
1
|
import auditCommand from "./audit.js";
|
|
4
2
|
import clearCommand from "./clear.js";
|
|
5
3
|
import planCommand from "./plan.js";
|
|
6
4
|
export default function slashCommands(pi) {
|
|
7
|
-
createSlashCommand(pi);
|
|
8
|
-
createExtension(pi);
|
|
9
5
|
auditCommand(pi);
|
|
10
6
|
clearCommand(pi);
|
|
11
7
|
planCommand(pi);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { mkdirSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { getAgentDir, getPermissionMode, isToolCallEventType, setPermissionMode } from "@gsd/pi-coding-agent";
|
|
2
3
|
import { join } from "node:path";
|
|
3
|
-
import { getPermissionMode, isToolCallEventType, setPermissionMode } from "@gsd/pi-coding-agent";
|
|
4
4
|
const PLAN_ENTRY_TYPE = "plan-mode-state";
|
|
5
5
|
const PLAN_APPROVAL_QUESTION_ID = "plan_mode_approval";
|
|
6
6
|
const PLAN_DIR_RE = /(^|[/\\])\.(?:lsd|gsd)[/\\]plan([/\\]|$)/;
|
|
@@ -56,15 +56,64 @@ const BLOCKED_TOOLS = new Set([
|
|
|
56
56
|
"write",
|
|
57
57
|
"edit",
|
|
58
58
|
]);
|
|
59
|
-
|
|
59
|
+
const DEFAULT_APPROVAL_PERMISSION_MODE = "auto";
|
|
60
|
+
const APPROVE_AUTO_LABEL = "Approve & switch to Auto mode";
|
|
61
|
+
const APPROVE_BYPASS_LABEL = "Approve & switch to Bypass mode";
|
|
62
|
+
const REVISE_LABEL = "Revise plan";
|
|
63
|
+
const CANCEL_LABEL = "Cancel";
|
|
64
|
+
const INITIAL_STATE = {
|
|
60
65
|
active: false,
|
|
61
66
|
task: "",
|
|
67
|
+
latestPlanPath: undefined,
|
|
62
68
|
approvalStatus: "cancelled",
|
|
69
|
+
previousMode: undefined,
|
|
70
|
+
preplanModel: undefined,
|
|
71
|
+
targetPermissionMode: undefined,
|
|
63
72
|
};
|
|
73
|
+
let state = { ...INITIAL_STATE };
|
|
64
74
|
let startedFromFlag = false;
|
|
65
75
|
function isPlanModeActive() {
|
|
66
76
|
return getPermissionMode() === "plan";
|
|
67
77
|
}
|
|
78
|
+
function parseQualifiedModelRef(value) {
|
|
79
|
+
if (typeof value !== "string")
|
|
80
|
+
return undefined;
|
|
81
|
+
const trimmed = value.trim();
|
|
82
|
+
if (!trimmed)
|
|
83
|
+
return undefined;
|
|
84
|
+
const parts = trimmed.split("/");
|
|
85
|
+
if (parts.length !== 2)
|
|
86
|
+
return undefined;
|
|
87
|
+
const [provider, id] = parts.map((part) => part.trim());
|
|
88
|
+
if (!provider || !id)
|
|
89
|
+
return undefined;
|
|
90
|
+
return { provider, id };
|
|
91
|
+
}
|
|
92
|
+
export function readPlanModeReasoningModel() {
|
|
93
|
+
try {
|
|
94
|
+
const settingsPath = join(getAgentDir(), "settings.json");
|
|
95
|
+
if (!existsSync(settingsPath))
|
|
96
|
+
return undefined;
|
|
97
|
+
const raw = readFileSync(settingsPath, "utf-8");
|
|
98
|
+
const parsed = JSON.parse(raw);
|
|
99
|
+
const model = parseQualifiedModelRef(parsed.planModeReasoningModel);
|
|
100
|
+
return model ? `${model.provider}/${model.id}` : undefined;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function sameModel(left, right) {
|
|
107
|
+
return !!left && !!right && left.provider === right.provider && left.id === right.id;
|
|
108
|
+
}
|
|
109
|
+
function resolveModelFromContext(ctx, modelRef) {
|
|
110
|
+
const allModels = typeof ctx?.modelRegistry?.getAll === "function" ? ctx.modelRegistry.getAll() : [];
|
|
111
|
+
return allModels.find((model) => model.provider === modelRef.provider && model.id === modelRef.id);
|
|
112
|
+
}
|
|
113
|
+
function setPermissionModeAndEnv(mode) {
|
|
114
|
+
setPermissionMode(mode);
|
|
115
|
+
process.env.LUCENT_CODE_PERMISSION_MODE = mode;
|
|
116
|
+
}
|
|
68
117
|
function saveState(pi) {
|
|
69
118
|
pi.appendEntry(PLAN_ENTRY_TYPE, { ...state });
|
|
70
119
|
}
|
|
@@ -72,15 +121,11 @@ function setState(pi, next) {
|
|
|
72
121
|
state = next;
|
|
73
122
|
saveState(pi);
|
|
74
123
|
}
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
approvalStatus: "cancelled",
|
|
81
|
-
previousMode: undefined,
|
|
82
|
-
};
|
|
83
|
-
saveState(pi);
|
|
124
|
+
function resetState(pi, overrides = {}) {
|
|
125
|
+
setState(pi, {
|
|
126
|
+
...INITIAL_STATE,
|
|
127
|
+
...overrides,
|
|
128
|
+
});
|
|
84
129
|
}
|
|
85
130
|
function ensurePlanDir() {
|
|
86
131
|
const dir = join(process.cwd(), ".lsd", "plan");
|
|
@@ -102,32 +147,63 @@ function restoreStateFromSession(ctx) {
|
|
|
102
147
|
// Best-effort restore only.
|
|
103
148
|
}
|
|
104
149
|
}
|
|
105
|
-
function enablePlanMode(pi, next = {}) {
|
|
150
|
+
function enablePlanMode(pi, currentModel, next = {}) {
|
|
106
151
|
const currentMode = getPermissionMode();
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
152
|
+
const enteringPlanMode = currentMode !== "plan";
|
|
153
|
+
const previousMode = enteringPlanMode
|
|
154
|
+
? currentMode
|
|
155
|
+
: (state.previousMode ?? "accept-on-edit");
|
|
156
|
+
setPermissionModeAndEnv("plan");
|
|
112
157
|
setState(pi, {
|
|
113
158
|
active: true,
|
|
114
159
|
task: next.task ?? state.task,
|
|
115
160
|
latestPlanPath: next.latestPlanPath ?? state.latestPlanPath,
|
|
116
161
|
approvalStatus: next.approvalStatus ?? state.approvalStatus ?? "pending",
|
|
117
162
|
previousMode: next.previousMode ?? previousMode,
|
|
163
|
+
preplanModel: next.preplanModel ?? (enteringPlanMode ? (currentModel ?? state.preplanModel) : state.preplanModel),
|
|
164
|
+
targetPermissionMode: next.targetPermissionMode ?? state.targetPermissionMode,
|
|
118
165
|
});
|
|
119
166
|
}
|
|
120
|
-
function
|
|
121
|
-
|
|
122
|
-
setPermissionMode(restoreMode);
|
|
123
|
-
process.env.LUCENT_CODE_PERMISSION_MODE = restoreMode;
|
|
167
|
+
function leavePlanMode(pi, approvalStatus, nextPermissionMode, clearTask = false) {
|
|
168
|
+
setPermissionModeAndEnv(nextPermissionMode);
|
|
124
169
|
setState(pi, {
|
|
125
170
|
active: false,
|
|
126
171
|
task: clearTask ? "" : state.task,
|
|
127
172
|
latestPlanPath: state.latestPlanPath,
|
|
128
173
|
approvalStatus,
|
|
129
|
-
previousMode:
|
|
174
|
+
previousMode: state.previousMode,
|
|
175
|
+
preplanModel: state.preplanModel,
|
|
176
|
+
targetPermissionMode: state.targetPermissionMode ?? nextPermissionMode,
|
|
130
177
|
});
|
|
178
|
+
return nextPermissionMode;
|
|
179
|
+
}
|
|
180
|
+
async function setModelIfNeeded(pi, ctx, modelRef) {
|
|
181
|
+
if (!modelRef)
|
|
182
|
+
return;
|
|
183
|
+
const currentModel = parseQualifiedModelRef(ctx?.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined);
|
|
184
|
+
if (sameModel(currentModel, modelRef))
|
|
185
|
+
return;
|
|
186
|
+
const model = resolveModelFromContext(ctx, modelRef);
|
|
187
|
+
if (!model)
|
|
188
|
+
return;
|
|
189
|
+
await pi.setModel(model, { persist: false });
|
|
190
|
+
}
|
|
191
|
+
async function approvePlan(pi, ctx, permissionMode) {
|
|
192
|
+
const reasoningModel = parseQualifiedModelRef(readPlanModeReasoningModel());
|
|
193
|
+
if (reasoningModel) {
|
|
194
|
+
await setModelIfNeeded(pi, ctx, reasoningModel);
|
|
195
|
+
}
|
|
196
|
+
state = {
|
|
197
|
+
...state,
|
|
198
|
+
targetPermissionMode: permissionMode,
|
|
199
|
+
};
|
|
200
|
+
leavePlanMode(pi, "approved", permissionMode);
|
|
201
|
+
}
|
|
202
|
+
async function cancelPlan(pi, ctx, clearTask = true) {
|
|
203
|
+
const restoreMode = state.previousMode ?? "accept-on-edit";
|
|
204
|
+
await setModelIfNeeded(pi, ctx, state.preplanModel);
|
|
205
|
+
leavePlanMode(pi, "cancelled", restoreMode, clearTask);
|
|
206
|
+
resetState(pi, { approvalStatus: "cancelled" });
|
|
131
207
|
return restoreMode;
|
|
132
208
|
}
|
|
133
209
|
function buildPlanModeSystemPrompt() {
|
|
@@ -143,6 +219,49 @@ function buildPlanModeSystemPrompt() {
|
|
|
143
219
|
details.push(`Latest plan artifact: ${state.latestPlanPath}`);
|
|
144
220
|
return details.join(" ");
|
|
145
221
|
}
|
|
222
|
+
function buildApprovalSteeringMessage(planPath) {
|
|
223
|
+
return [
|
|
224
|
+
`Plan artifact saved at ${planPath}.`,
|
|
225
|
+
"Present approval options now using ask_user_questions with exactly one single-select question.",
|
|
226
|
+
`Use question id \"${PLAN_APPROVAL_QUESTION_ID}\" and ask the user what to do next.`,
|
|
227
|
+
"Important: ask_user_questions single-select supports only 2-3 explicit options.",
|
|
228
|
+
"Use exactly these 3 options:",
|
|
229
|
+
`1. ${APPROVE_AUTO_LABEL} (Recommended)`,
|
|
230
|
+
`2. ${APPROVE_BYPASS_LABEL}`,
|
|
231
|
+
`3. ${REVISE_LABEL}`,
|
|
232
|
+
`Do not include \"${CANCEL_LABEL}\" as an explicit option. If the user wants to cancel, they should choose \"None of the above\" and type \"${CANCEL_LABEL}\" in the free-text note.`,
|
|
233
|
+
"If the dialog is dismissed or the user gives no answer, continue planning.",
|
|
234
|
+
].join(" ");
|
|
235
|
+
}
|
|
236
|
+
function approvalSelectionToPermissionMode(selected) {
|
|
237
|
+
if (selected.includes(APPROVE_AUTO_LABEL))
|
|
238
|
+
return "auto";
|
|
239
|
+
if (selected.includes(APPROVE_BYPASS_LABEL))
|
|
240
|
+
return "danger-full-access";
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
function selectionRequestsCancel(selected) {
|
|
244
|
+
const values = Array.isArray(selected) ? selected : [selected];
|
|
245
|
+
return values.some((value) => {
|
|
246
|
+
if (typeof value !== "string")
|
|
247
|
+
return false;
|
|
248
|
+
if (value.includes(CANCEL_LABEL))
|
|
249
|
+
return true;
|
|
250
|
+
const normalized = value.replace(/^user_note:\s*/i, "").trim().toLowerCase();
|
|
251
|
+
return normalized === "cancel" || normalized.includes("cancel plan");
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
export const __testing = {
|
|
255
|
+
getState() {
|
|
256
|
+
return { ...state };
|
|
257
|
+
},
|
|
258
|
+
resetState() {
|
|
259
|
+
state = { ...INITIAL_STATE };
|
|
260
|
+
startedFromFlag = false;
|
|
261
|
+
},
|
|
262
|
+
parseQualifiedModelRef,
|
|
263
|
+
approvalSelectionToPermissionMode,
|
|
264
|
+
};
|
|
146
265
|
export default function planCommand(pi) {
|
|
147
266
|
pi.registerFlag("plan", {
|
|
148
267
|
description: "Start the session in plan mode and require a persisted .lsd/plan markdown plan before execution",
|
|
@@ -152,8 +271,7 @@ export default function planCommand(pi) {
|
|
|
152
271
|
restoreStateFromSession(ctx);
|
|
153
272
|
startedFromFlag = false;
|
|
154
273
|
if (state.active) {
|
|
155
|
-
|
|
156
|
-
process.env.LUCENT_CODE_PERMISSION_MODE = "plan";
|
|
274
|
+
setPermissionModeAndEnv("plan");
|
|
157
275
|
}
|
|
158
276
|
});
|
|
159
277
|
pi.on("before_agent_start", async () => {
|
|
@@ -163,16 +281,18 @@ export default function planCommand(pi) {
|
|
|
163
281
|
systemPrompt: buildPlanModeSystemPrompt(),
|
|
164
282
|
};
|
|
165
283
|
});
|
|
166
|
-
pi.on("input", async (event) => {
|
|
284
|
+
pi.on("input", async (event, ctx) => {
|
|
167
285
|
const planFlag = pi.getFlag("plan");
|
|
168
286
|
if (startedFromFlag || planFlag !== true || event.source !== "interactive") {
|
|
169
287
|
return { action: "continue" };
|
|
170
288
|
}
|
|
171
289
|
startedFromFlag = true;
|
|
172
290
|
ensurePlanDir();
|
|
173
|
-
enablePlanMode(pi, {
|
|
291
|
+
enablePlanMode(pi, ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined, {
|
|
174
292
|
task: event.text.trim(),
|
|
175
293
|
approvalStatus: "pending",
|
|
294
|
+
latestPlanPath: undefined,
|
|
295
|
+
targetPermissionMode: undefined,
|
|
176
296
|
});
|
|
177
297
|
return { action: "continue" };
|
|
178
298
|
});
|
|
@@ -204,16 +324,22 @@ export default function planCommand(pi) {
|
|
|
204
324
|
};
|
|
205
325
|
}
|
|
206
326
|
});
|
|
207
|
-
pi.on("tool_result", async (event) => {
|
|
327
|
+
pi.on("tool_result", async (event, ctx) => {
|
|
208
328
|
if (event.toolName === "write" || event.toolName === "edit") {
|
|
209
329
|
const input = event.input;
|
|
210
330
|
const path = input?.path;
|
|
211
|
-
if (path && PLAN_DIR_RE.test(path)) {
|
|
331
|
+
if (path && PLAN_DIR_RE.test(path) && isPlanModeActive()) {
|
|
212
332
|
setState(pi, {
|
|
213
333
|
...state,
|
|
214
334
|
latestPlanPath: path,
|
|
215
|
-
approvalStatus:
|
|
335
|
+
approvalStatus: "pending",
|
|
336
|
+
targetPermissionMode: undefined,
|
|
216
337
|
});
|
|
338
|
+
if (!ctx.hasUI) {
|
|
339
|
+
await approvePlan(pi, ctx, DEFAULT_APPROVAL_PERMISSION_MODE);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
pi.sendUserMessage(buildApprovalSteeringMessage(path), { deliverAs: "steer" });
|
|
217
343
|
}
|
|
218
344
|
return;
|
|
219
345
|
}
|
|
@@ -225,35 +351,43 @@ export default function planCommand(pi) {
|
|
|
225
351
|
const answer = details.response.answers[PLAN_APPROVAL_QUESTION_ID];
|
|
226
352
|
if (!answer)
|
|
227
353
|
return;
|
|
228
|
-
const selected = Array.isArray(answer.selected) ? answer.selected
|
|
229
|
-
if (typeof
|
|
354
|
+
const selected = Array.isArray(answer.selected) ? answer.selected : [answer.selected];
|
|
355
|
+
if (!selected.every((value) => typeof value === "string"))
|
|
230
356
|
return;
|
|
231
|
-
|
|
232
|
-
|
|
357
|
+
const targetPermissionMode = approvalSelectionToPermissionMode(selected[0]);
|
|
358
|
+
if (targetPermissionMode) {
|
|
359
|
+
state = {
|
|
360
|
+
...state,
|
|
361
|
+
targetPermissionMode,
|
|
362
|
+
};
|
|
363
|
+
await approvePlan(pi, ctx, targetPermissionMode);
|
|
233
364
|
return;
|
|
234
365
|
}
|
|
235
|
-
if (selected.includes(
|
|
236
|
-
enablePlanMode(pi, {
|
|
366
|
+
if (selected.some((value) => value.includes(REVISE_LABEL))) {
|
|
367
|
+
enablePlanMode(pi, ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined, {
|
|
368
|
+
approvalStatus: "revising",
|
|
369
|
+
});
|
|
237
370
|
return;
|
|
238
371
|
}
|
|
239
|
-
if (selected
|
|
240
|
-
|
|
241
|
-
clearState(pi);
|
|
372
|
+
if (selectionRequestsCancel(selected)) {
|
|
373
|
+
await cancelPlan(pi, ctx, true);
|
|
242
374
|
}
|
|
243
375
|
});
|
|
244
376
|
pi.registerCommand("plan", {
|
|
245
377
|
description: "Toggle plan mode. While active, only investigative tools and writes under .lsd/plan/ are allowed",
|
|
246
378
|
async handler(args, ctx) {
|
|
247
379
|
if (isPlanModeActive()) {
|
|
248
|
-
|
|
380
|
+
await cancelPlan(pi, ctx, true);
|
|
249
381
|
ctx.ui.notify("Plan mode disabled.", "info");
|
|
250
382
|
return;
|
|
251
383
|
}
|
|
252
384
|
ensurePlanDir();
|
|
253
385
|
const task = args.trim();
|
|
254
|
-
enablePlanMode(pi, {
|
|
386
|
+
enablePlanMode(pi, ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined, {
|
|
255
387
|
task,
|
|
388
|
+
latestPlanPath: undefined,
|
|
256
389
|
approvalStatus: "pending",
|
|
390
|
+
targetPermissionMode: undefined,
|
|
257
391
|
});
|
|
258
392
|
ctx.ui.notify(task
|
|
259
393
|
? `Plan mode enabled. Current task: ${task}`
|
|
@@ -267,17 +401,19 @@ export default function planCommand(pi) {
|
|
|
267
401
|
ctx.ui.notify("Plan mode is not active.", "info");
|
|
268
402
|
return;
|
|
269
403
|
}
|
|
270
|
-
|
|
271
|
-
ctx.ui.notify(`Plan
|
|
404
|
+
await approvePlan(pi, ctx, DEFAULT_APPROVAL_PERMISSION_MODE);
|
|
405
|
+
ctx.ui.notify(`Plan approved. Permission mode switched to ${DEFAULT_APPROVAL_PERMISSION_MODE}.`, "info");
|
|
272
406
|
},
|
|
273
407
|
});
|
|
274
408
|
pi.registerCommand("cancel-plan", {
|
|
275
409
|
description: "Cancel the current plan-mode session without executing",
|
|
276
410
|
async handler(_args, ctx) {
|
|
277
411
|
if (isPlanModeActive()) {
|
|
278
|
-
|
|
412
|
+
await cancelPlan(pi, ctx, true);
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
resetState(pi, { approvalStatus: "cancelled" });
|
|
279
416
|
}
|
|
280
|
-
clearState(pi);
|
|
281
417
|
ctx.ui.notify("Plan mode cancelled.", "info");
|
|
282
418
|
},
|
|
283
419
|
});
|
|
@@ -5,6 +5,19 @@ import * as fs from "node:fs";
|
|
|
5
5
|
import * as path from "node:path";
|
|
6
6
|
import { getAgentDir, parseFrontmatter } from "@gsd/pi-coding-agent";
|
|
7
7
|
const PROJECT_AGENT_DIR_CANDIDATES = [".lsd", ".gsd", ".pi"];
|
|
8
|
+
function normalizeAgentModel(model) {
|
|
9
|
+
const trimmed = model?.trim();
|
|
10
|
+
if (!trimmed)
|
|
11
|
+
return undefined;
|
|
12
|
+
if (trimmed === "$budget_model")
|
|
13
|
+
return trimmed;
|
|
14
|
+
if (trimmed.includes(" "))
|
|
15
|
+
return undefined;
|
|
16
|
+
if (!trimmed.includes("/"))
|
|
17
|
+
return trimmed;
|
|
18
|
+
const parts = trimmed.split("/");
|
|
19
|
+
return parts.length === 2 && parts.every(Boolean) ? trimmed : undefined;
|
|
20
|
+
}
|
|
8
21
|
function loadAgentsFromDir(dir, source) {
|
|
9
22
|
const agents = [];
|
|
10
23
|
if (!fs.existsSync(dir)) {
|
|
@@ -42,7 +55,7 @@ function loadAgentsFromDir(dir, source) {
|
|
|
42
55
|
name: frontmatter.name,
|
|
43
56
|
description: frontmatter.description,
|
|
44
57
|
tools: tools && tools.length > 0 ? tools : undefined,
|
|
45
|
-
model: frontmatter.model,
|
|
58
|
+
model: normalizeAgentModel(frontmatter.model),
|
|
46
59
|
systemPrompt: body,
|
|
47
60
|
source,
|
|
48
61
|
filePath,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { normalizeSubagentModel } from "./model-resolution.js";
|
|
1
2
|
export function resolveConfiguredSubagentModel(agent, preferences, settingsBudgetModel) {
|
|
2
3
|
const configuredModel = agent.model?.trim();
|
|
3
4
|
if (!configuredModel)
|
|
4
5
|
return undefined;
|
|
5
6
|
if (configuredModel === "$budget_model") {
|
|
6
|
-
return settingsBudgetModel
|
|
7
|
+
return normalizeSubagentModel(settingsBudgetModel) ?? normalizeSubagentModel(preferences?.subagent?.budget_model);
|
|
7
8
|
}
|
|
8
|
-
return configuredModel;
|
|
9
|
+
return normalizeSubagentModel(configuredModel);
|
|
9
10
|
}
|