@duckmind/dm-darwin-x64 0.43.4 → 0.48.5
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/dm +0 -0
- package/extensions/.dm-extensions.json +242 -50
- package/extensions/dm-9router-ext/package.json +2 -19
- package/extensions/dm-9router-ext/src/index.js +5 -0
- package/extensions/dm-ask-user/index.js +10 -0
- package/extensions/dm-ask-user/package.json +1 -21
- package/extensions/dm-cli-anything/package.json +0 -6
- package/extensions/dm-context/package.json +2 -12
- package/extensions/dm-context/src/context.js +1 -0
- package/extensions/dm-context/src/index.js +7 -0
- package/extensions/dm-context/src/utils.js +1 -0
- package/extensions/dm-cua/package.json +0 -7
- package/extensions/dm-fff/package.json +1 -28
- package/extensions/dm-fff/src/index.js +15 -0
- package/extensions/dm-fff/src/query.js +1 -0
- package/extensions/dm-goal/package.json +2 -31
- package/extensions/dm-goal/src/goal.js +43 -0
- package/extensions/dm-grill-me/index.js +174 -0
- package/extensions/dm-grill-me/package.json +1 -26
- package/extensions/dm-image2/package.json +0 -7
- package/extensions/dm-subagents/package.json +1 -32
- package/extensions/dm-subagents/src/agents/agent-management.js +37 -0
- package/extensions/dm-subagents/src/agents/agent-memory.js +6 -0
- package/extensions/dm-subagents/src/agents/agent-scope.js +1 -0
- package/extensions/dm-subagents/src/agents/agent-selection.js +1 -0
- package/extensions/dm-subagents/src/agents/agent-serializer.js +7 -0
- package/extensions/dm-subagents/src/agents/agents.js +11 -0
- package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -0
- package/extensions/dm-subagents/src/agents/frontmatter.js +6 -0
- package/extensions/dm-subagents/src/agents/identity.js +1 -0
- package/extensions/dm-subagents/src/agents/proactive-skills.js +1 -0
- package/extensions/dm-subagents/src/agents/skills.js +6 -0
- package/extensions/dm-subagents/src/extension/config.js +2 -0
- package/extensions/dm-subagents/src/extension/control-notices.js +4 -0
- package/extensions/dm-subagents/src/extension/doctor.js +16 -0
- package/extensions/dm-subagents/src/extension/fanout-child.js +231 -0
- package/extensions/dm-subagents/src/extension/index.js +367 -0
- package/extensions/dm-subagents/src/extension/rpc.js +8 -0
- package/extensions/dm-subagents/src/extension/schemas.js +1 -0
- package/extensions/dm-subagents/src/extension/{tool-description.ts → tool-description.js} +6 -126
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +13 -0
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +5 -0
- package/extensions/dm-subagents/src/intercom/result-intercom.js +3 -0
- package/extensions/dm-subagents/src/profiles/profiles.js +3 -0
- package/extensions/dm-subagents/src/runs/background/async-execution.js +46 -0
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +14 -0
- package/extensions/dm-subagents/src/runs/background/async-resume.js +8 -0
- package/extensions/dm-subagents/src/runs/background/async-status.js +12 -0
- package/extensions/dm-subagents/src/runs/background/chain-append.js +2 -0
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +1 -0
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +1 -0
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +1 -0
- package/extensions/dm-subagents/src/runs/background/control-channel.js +1 -0
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +17 -0
- package/extensions/dm-subagents/src/runs/background/notify.js +3 -0
- package/extensions/dm-subagents/src/runs/background/parallel-groups.js +1 -0
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +8 -0
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +4 -0
- package/extensions/dm-subagents/src/runs/background/run-status.js +23 -0
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +4 -0
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +11 -0
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +78 -0
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -0
- package/extensions/dm-subagents/src/runs/background/wait.js +11 -0
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +12 -0
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +102 -0
- package/extensions/dm-subagents/src/runs/foreground/execution.js +51 -0
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +228 -0
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +3 -0
- package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +3 -0
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +8 -0
- package/extensions/dm-subagents/src/runs/shared/nested-path.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +5 -0
- package/extensions/dm-subagents/src/runs/shared/run-history.js +5 -0
- package/extensions/dm-subagents/src/runs/shared/single-output.js +14 -0
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +5 -0
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +22 -0
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +7 -0
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +1 -0
- package/extensions/dm-subagents/src/runs/shared/worktree.js +3 -0
- package/extensions/dm-subagents/src/shared/artifacts.js +2 -0
- package/extensions/dm-subagents/src/shared/atomic-json.js +1 -0
- package/extensions/dm-subagents/src/shared/child-transcript.js +5 -0
- package/extensions/dm-subagents/src/shared/file-coalescer.js +1 -0
- package/extensions/dm-subagents/src/shared/fork-context.js +6 -0
- package/extensions/dm-subagents/src/shared/formatters.js +9 -0
- package/extensions/dm-subagents/src/shared/jsonl-writer.js +2 -0
- package/extensions/dm-subagents/src/shared/model-info.js +1 -0
- package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +1 -0
- package/extensions/dm-subagents/src/shared/session-identity.js +1 -0
- package/extensions/dm-subagents/src/shared/session-tokens.js +2 -0
- package/extensions/dm-subagents/src/shared/settings.js +23 -0
- package/extensions/dm-subagents/src/shared/status-format.js +1 -0
- package/extensions/dm-subagents/src/shared/types.js +8 -0
- package/extensions/dm-subagents/src/shared/utils.js +2 -0
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +1 -0
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +7 -0
- package/extensions/dm-subagents/src/slash/slash-bridge.js +1 -0
- package/extensions/dm-subagents/src/slash/slash-commands.js +38 -0
- package/extensions/dm-subagents/src/slash/slash-live-state.js +6 -0
- package/extensions/dm-subagents/src/tui/render-helpers.js +1 -0
- package/extensions/dm-subagents/src/tui/render.js +4 -0
- package/extensions/dm-tasks/package.json +1 -30
- package/extensions/dm-tasks/src/auto-clear.js +1 -0
- package/extensions/dm-tasks/src/index.js +212 -0
- package/extensions/dm-tasks/src/process-tracker.js +1 -0
- package/extensions/dm-tasks/src/task-store.js +1 -0
- package/extensions/dm-tasks/src/tasks-config.js +1 -0
- package/extensions/dm-tasks/src/types.js +0 -0
- package/extensions/dm-tasks/src/ui/settings-menu.js +1 -0
- package/extensions/dm-tasks/src/ui/task-widget.js +1 -0
- package/extensions/dm-usage/index.js +9 -0
- package/extensions/dm-usage/package.json +1 -18
- package/extensions/greedysearch-dm/bin/search.mjs +51 -51
- package/extensions/greedysearch-dm/index.js +20 -0
- package/extensions/greedysearch-dm/package.json +1 -22
- package/extensions/greedysearch-dm/src/formatters/results.js +8 -0
- package/extensions/greedysearch-dm/src/formatters/sources.js +1 -0
- package/extensions/greedysearch-dm/src/formatters/synthesis.js +1 -0
- package/extensions/greedysearch-dm/src/search/research.mjs +59 -59
- package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +10 -10
- package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +20 -0
- package/extensions/greedysearch-dm/src/tools/shared.js +9 -0
- package/extensions/greedysearch-dm/src/types.js +0 -0
- package/extensions/greedysearch-dm/src/utils/helpers.js +1 -0
- package/package.json +1 -1
- package/extensions/dm-9router-ext/src/index.ts +0 -541
- package/extensions/dm-ask-user/index.ts +0 -857
- package/extensions/dm-context/src/context.ts +0 -158
- package/extensions/dm-context/src/index.ts +0 -439
- package/extensions/dm-context/src/utils.ts +0 -6
- package/extensions/dm-fff/src/index.ts +0 -1023
- package/extensions/dm-fff/src/query.ts +0 -87
- package/extensions/dm-goal/src/goal.ts +0 -1073
- package/extensions/dm-grill-me/index.ts +0 -1085
- package/extensions/dm-subagents/src/agents/agent-management.ts +0 -1052
- package/extensions/dm-subagents/src/agents/agent-memory.ts +0 -254
- package/extensions/dm-subagents/src/agents/agent-scope.ts +0 -6
- package/extensions/dm-subagents/src/agents/agent-selection.ts +0 -25
- package/extensions/dm-subagents/src/agents/agent-serializer.ts +0 -121
- package/extensions/dm-subagents/src/agents/agents.ts +0 -1553
- package/extensions/dm-subagents/src/agents/chain-serializer.ts +0 -277
- package/extensions/dm-subagents/src/agents/frontmatter.ts +0 -93
- package/extensions/dm-subagents/src/agents/identity.ts +0 -30
- package/extensions/dm-subagents/src/agents/proactive-skills.ts +0 -191
- package/extensions/dm-subagents/src/agents/skills.ts +0 -729
- package/extensions/dm-subagents/src/extension/config.ts +0 -39
- package/extensions/dm-subagents/src/extension/control-notices.ts +0 -92
- package/extensions/dm-subagents/src/extension/doctor.ts +0 -214
- package/extensions/dm-subagents/src/extension/fanout-child.ts +0 -172
- package/extensions/dm-subagents/src/extension/index.ts +0 -656
- package/extensions/dm-subagents/src/extension/rpc.ts +0 -369
- package/extensions/dm-subagents/src/extension/schemas.ts +0 -309
- package/extensions/dm-subagents/src/intercom/intercom-bridge.ts +0 -180
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.ts +0 -519
- package/extensions/dm-subagents/src/intercom/result-intercom.ts +0 -377
- package/extensions/dm-subagents/src/profiles/profiles.ts +0 -637
- package/extensions/dm-subagents/src/runs/background/async-execution.ts +0 -1065
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.ts +0 -441
- package/extensions/dm-subagents/src/runs/background/async-resume.ts +0 -391
- package/extensions/dm-subagents/src/runs/background/async-status.ts +0 -395
- package/extensions/dm-subagents/src/runs/background/chain-append.ts +0 -282
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.ts +0 -191
- package/extensions/dm-subagents/src/runs/background/completion-batcher.ts +0 -166
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.ts +0 -63
- package/extensions/dm-subagents/src/runs/background/control-channel.ts +0 -332
- package/extensions/dm-subagents/src/runs/background/fleet-view.ts +0 -515
- package/extensions/dm-subagents/src/runs/background/notify.ts +0 -225
- package/extensions/dm-subagents/src/runs/background/parallel-groups.ts +0 -45
- package/extensions/dm-subagents/src/runs/background/result-watcher.ts +0 -315
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.ts +0 -84
- package/extensions/dm-subagents/src/runs/background/run-status.ts +0 -434
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.ts +0 -514
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.ts +0 -368
- package/extensions/dm-subagents/src/runs/background/subagent-runner.ts +0 -3171
- package/extensions/dm-subagents/src/runs/background/top-level-async.ts +0 -13
- package/extensions/dm-subagents/src/runs/background/wait.ts +0 -353
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.ts +0 -1333
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.ts +0 -1313
- package/extensions/dm-subagents/src/runs/foreground/execution.ts +0 -1239
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.ts +0 -3613
- package/extensions/dm-subagents/src/runs/shared/acceptance.ts +0 -879
- package/extensions/dm-subagents/src/runs/shared/chain-outputs.ts +0 -116
- package/extensions/dm-subagents/src/runs/shared/completion-guard.ts +0 -147
- package/extensions/dm-subagents/src/runs/shared/dm-args.ts +0 -271
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.ts +0 -147
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.ts +0 -295
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.ts +0 -175
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +0 -365
- package/extensions/dm-subagents/src/runs/shared/model-fallback.ts +0 -292
- package/extensions/dm-subagents/src/runs/shared/model-scope.ts +0 -128
- package/extensions/dm-subagents/src/runs/shared/nested-events.ts +0 -908
- package/extensions/dm-subagents/src/runs/shared/nested-path.ts +0 -52
- package/extensions/dm-subagents/src/runs/shared/nested-render.ts +0 -115
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.ts +0 -198
- package/extensions/dm-subagents/src/runs/shared/run-history.ts +0 -60
- package/extensions/dm-subagents/src/runs/shared/single-output.ts +0 -180
- package/extensions/dm-subagents/src/runs/shared/structured-output.ts +0 -77
- package/extensions/dm-subagents/src/runs/shared/subagent-control.ts +0 -223
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.ts +0 -342
- package/extensions/dm-subagents/src/runs/shared/tool-budget.ts +0 -74
- package/extensions/dm-subagents/src/runs/shared/turn-budget.ts +0 -52
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.ts +0 -206
- package/extensions/dm-subagents/src/runs/shared/worktree.ts +0 -600
- package/extensions/dm-subagents/src/shared/artifacts.ts +0 -113
- package/extensions/dm-subagents/src/shared/atomic-json.ts +0 -86
- package/extensions/dm-subagents/src/shared/child-transcript.ts +0 -212
- package/extensions/dm-subagents/src/shared/file-coalescer.ts +0 -40
- package/extensions/dm-subagents/src/shared/fork-context.ts +0 -194
- package/extensions/dm-subagents/src/shared/formatters.ts +0 -133
- package/extensions/dm-subagents/src/shared/jsonl-writer.ts +0 -81
- package/extensions/dm-subagents/src/shared/model-info.ts +0 -78
- package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
- package/extensions/dm-subagents/src/shared/session-identity.ts +0 -10
- package/extensions/dm-subagents/src/shared/session-tokens.ts +0 -44
- package/extensions/dm-subagents/src/shared/settings.ts +0 -450
- package/extensions/dm-subagents/src/shared/status-format.ts +0 -49
- package/extensions/dm-subagents/src/shared/types.ts +0 -1257
- package/extensions/dm-subagents/src/shared/utils.ts +0 -554
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.ts +0 -420
- package/extensions/dm-subagents/src/slash/prompt-workflows.ts +0 -330
- package/extensions/dm-subagents/src/slash/slash-bridge.ts +0 -176
- package/extensions/dm-subagents/src/slash/slash-commands.ts +0 -1296
- package/extensions/dm-subagents/src/slash/slash-live-state.ts +0 -292
- package/extensions/dm-subagents/src/tui/render-helpers.ts +0 -80
- package/extensions/dm-subagents/src/tui/render.ts +0 -1748
- package/extensions/dm-tasks/src/auto-clear.ts +0 -91
- package/extensions/dm-tasks/src/index.ts +0 -1145
- package/extensions/dm-tasks/src/process-tracker.ts +0 -140
- package/extensions/dm-tasks/src/task-store.ts +0 -305
- package/extensions/dm-tasks/src/tasks-config.ts +0 -23
- package/extensions/dm-tasks/src/types.ts +0 -40
- package/extensions/dm-tasks/src/ui/settings-menu.ts +0 -100
- package/extensions/dm-tasks/src/ui/task-widget.ts +0 -265
- package/extensions/dm-usage/index.ts +0 -1718
- package/extensions/greedysearch-dm/index.ts +0 -177
- package/extensions/greedysearch-dm/src/formatters/results.ts +0 -163
- package/extensions/greedysearch-dm/src/formatters/sources.ts +0 -116
- package/extensions/greedysearch-dm/src/formatters/synthesis.ts +0 -87
- package/extensions/greedysearch-dm/src/tools/greedy-search-handler.ts +0 -370
- package/extensions/greedysearch-dm/src/tools/shared.ts +0 -187
- package/extensions/greedysearch-dm/src/types.ts +0 -110
- package/extensions/greedysearch-dm/src/utils/helpers.ts +0 -40
|
@@ -19,10 +19,6 @@
|
|
|
19
19
|
"cloakbrowser",
|
|
20
20
|
"automation"
|
|
21
21
|
],
|
|
22
|
-
"peerDependencies": {
|
|
23
|
-
"@sinclair/typebox": "*",
|
|
24
|
-
"@duckmind/dm-coding-agent": "*"
|
|
25
|
-
},
|
|
26
22
|
"dm": {
|
|
27
23
|
"extensions": [
|
|
28
24
|
"./index.js"
|
|
@@ -30,8 +26,5 @@
|
|
|
30
26
|
"skills": [
|
|
31
27
|
"./skills"
|
|
32
28
|
]
|
|
33
|
-
},
|
|
34
|
-
"devDependencies": {
|
|
35
|
-
"@duckmind/dm-coding-agent": "file:../../dm-mono/packages/coding-agent"
|
|
36
29
|
}
|
|
37
30
|
}
|
|
@@ -13,15 +13,6 @@
|
|
|
13
13
|
"fuzzy-search",
|
|
14
14
|
"ai-agent"
|
|
15
15
|
],
|
|
16
|
-
"repository": {
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/que-nguyen/dm.git",
|
|
19
|
-
"directory": "extensions/dm-fff"
|
|
20
|
-
},
|
|
21
|
-
"bugs": {
|
|
22
|
-
"url": "https://github.com/que-nguyen/dm/issues"
|
|
23
|
-
},
|
|
24
|
-
"homepage": "https://github.com/que-nguyen/dm/tree/main/extensions/dm-fff#readme",
|
|
25
16
|
"files": [
|
|
26
17
|
"src",
|
|
27
18
|
"test",
|
|
@@ -30,25 +21,7 @@
|
|
|
30
21
|
],
|
|
31
22
|
"dm": {
|
|
32
23
|
"extensions": [
|
|
33
|
-
"./src/index.
|
|
24
|
+
"./src/index.js"
|
|
34
25
|
]
|
|
35
|
-
},
|
|
36
|
-
"scripts": {
|
|
37
|
-
"test": "bun test test/",
|
|
38
|
-
"typecheck": "tsc --noEmit"
|
|
39
|
-
},
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"@ff-labs/fff-node": "*"
|
|
42
|
-
},
|
|
43
|
-
"peerDependencies": {
|
|
44
|
-
"@sinclair/typebox": "*",
|
|
45
|
-
"@duckmind/dm-coding-agent": "*",
|
|
46
|
-
"@duckmind/dm-tui": "*"
|
|
47
|
-
},
|
|
48
|
-
"devDependencies": {
|
|
49
|
-
"@types/node": "^22.0.0",
|
|
50
|
-
"typescript": "^5.0.0",
|
|
51
|
-
"@duckmind/dm-coding-agent": "file:../../dm-mono/packages/coding-agent",
|
|
52
|
-
"@duckmind/dm-tui": "file:../../dm-mono/packages/tui"
|
|
53
26
|
}
|
|
54
27
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import{Text as L}from"@duckmind/dm-tui";import{FileFinder as Kj}from"@ff-labs/fff-node";import{Type as W}from"@sinclair/typebox";import w from"node:path";function c(J,$=process.cwd()){let Z=J.trim();if(!Z)return Z;if(w.isAbsolute(Z)){let k=w.relative($,Z).replaceAll(w.sep,"/");if(k==="")return null;if(k.startsWith("../")||k===".."||w.isAbsolute(k))throw Error(`Path constraint must be relative to the workspace: ${J}`);Z=k}if(Z==="."||Z==="./")return null;if(Z.startsWith("./"))Z=Z.slice(2);let G=Z.match(/^(.*)\/\*\*(?:\/\*)?$/);if(G){let k=G[1];if(k&&!/[*?[{]/.test(k))return`${k}/`}if(Z.startsWith("/")||Z.endsWith("/"))return Z;if(/[*?[{]/.test(Z))return Z;let B=Z.split("/").pop()??"";if(/\.[a-zA-Z][a-zA-Z0-9]{0,9}$/.test(B))return Z;return`${Z}/`}function $j(J,$=process.cwd()){if(!J)return[];let Z=Array.isArray(J)?J:[J],G=[];for(let B of Z){let k=B.split(/[,\s]+/).map((V)=>V.trim()).filter(Boolean);for(let V of k){let z=V.startsWith("!")?V.slice(1):V,P=c(z,$);if(P)G.push(`!${P}`)}}return G}function x(J,$,Z,G=process.cwd()){let B=[];if(J){let k=c(J,G);if(k)B.push(k)}return B.push(...$j(Z,G)),B.push($),B.join(" ")}var E=20,f=30,Zj=500,p=20,h=["tools-and-ui","tools-only","override"],Hj={grep:"ffgrep",find:"fffind",multiGrep:"fff-multi-grep"},Qj={grep:"grep",find:"find",multiGrep:"multi_grep"};function Wj(J){return J==="override"?Qj:Hj}var _=new Map,Yj=0;function u(J){let $=`fff_c${++Yj}`;if(_.set($,J),_.size>200){let Z=_.keys().next().value;if(Z)_.delete(Z)}return $}function d(J){return _.get(J)}var M=new Map,Bj=0;function Xj(J){let $=`${++Bj}`;if(M.set($,J),M.size>200){let Z=M.keys().next().value;if(Z)M.delete(Z)}return $}function kj(J){return M.get(J)}function l(J,$=Zj){let Z=J.trim();return Z.length<=$?Z:`${Z.slice(0,$)}...`}var qj=25,Vj=20;function n(J){let $=J.gitStatus;if($&&$!=="clean"&&$!=="unknown"&&$!=="")return` [${$} in git]`;let Z=J.totalFrecencyScore??J.accessFrecencyScore??0;if(Z>=qj)return" [VERY often touched file]";if(Z>=Vj)return" [often touched file]";return""}function o(J){if(J.items.length===0)return"No matches found";let $=[],Z="",G=0;for(let B of J.items){if(B.relativePath!==Z){if($.length>0)$.push("");Z=B.relativePath,$.push(`${Z}${n(B)}`)}B.contextBefore?.forEach((k,V)=>{let z=B.lineNumber-B.contextBefore.length+V;$.push(` ${z}- ${l(k)}`)}),$.push(` ${B.lineNumber}: ${l(B.lineContent)}`),G++,B.contextAfter?.forEach((k,V)=>{let z=B.lineNumber+1+V;$.push(` ${z}- ${l(k)}`)})}return $.join(`
|
|
2
|
+
`)}var Uj=5;function Gj(J){let $=J.length*12;return Math.floor($*50/100)}function bj(J,$,Z){if(J.items.length===0)return{output:"No files found matching pattern",weak:!1,shownCount:0};let G=J.items.map((P)=>({item:P})),k=(J.scores[0]?.total??0)<Gj(Z),V=k?Math.min(Uj,$):$,z=G.slice(0,V);return{output:z.map((P)=>`${P.item.relativePath}${n(P.item)}`).join(`
|
|
3
|
+
`),weak:k,shownCount:z.length}}function Oj(J){return J.match(/(?:^|[ \t])(@(?:"[^"]*|[^\s]*))$/)?.[1]??null}function m(J){return J.includes(" ")?`@"${J}"`:`@${J}`}function zj(J){return{async getSuggestions($,Z,G,B){let k=$[Z]||"",V=Oj(k.slice(0,G));if(!V||B.signal.aborted)return null;let z=V.startsWith('@"')?V.slice(2):V.slice(1),P=await J(z,B.signal);return B.signal.aborted||P.length===0?null:{items:P,prefix:V}},applyCompletion($,Z,G,B,k){let V=$[Z]||"",z=V.slice(0,G-k.length),P=V.slice(G),C=z+B.value+P,y=G-k.length+B.value.length;return{lines:[...$.slice(0,Z),C,...$.slice(Z+1)],cursorLine:Z,cursorCol:y}}}}function Pj(J){let $=null,Z=null,G=null,B=process.cwd(),k=J.getFlag("fff-mode")??process.env.DM_FFF_MODE??"tools-and-ui",V=Wj(k),z=J.getFlag("fff-frecency-db")??process.env.FFF_FRECENCY_DB??void 0,P=J.getFlag("fff-history-db")??process.env.FFF_HISTORY_DB??void 0;function C(Y,j){let K=J.getFlag(Y);if(typeof K==="boolean")return K;if(typeof K==="string")return K==="true"||K==="1";let H=process.env[j];return H==="1"||H==="true"}let y=C("fff-enable-root-scan","FFF_ENABLE_ROOT_SCAN");function T(){return k}function a(Y){k=Y}function i(){return k!=="tools-only"}function F(Y){if($&&!$.isDestroyed&&Z===Y)return Promise.resolve($);if(G)return G;return G=(async()=>{if($&&!$.isDestroyed)$.destroy(),$=null,Z=null;let j=Kj.create({basePath:Y,frecencyDbPath:z,historyDbPath:P,aiMode:!0,enableHomeDirScanning:!0,enableFsRootScanning:y});if(!j.ok)throw Error(`Failed to create FFF file finder: ${j.error}`);return $=j.value,Z=Y,await $.waitForScan(15000),$})().finally(()=>{G=null}),G}function s(){if($&&!$.isDestroyed)$.destroy(),$=null,Z=null}async function r(Y,j){if(j.aborted)return[];let K=await F(B);if(j.aborted)return[];let H=K.mixedSearch(Y,{pageSize:p});if(!H.ok)return[];return H.value.items.slice(0,p).map((Q)=>{if(Q.type==="directory")return{value:m(Q.item.relativePath),label:Q.item.dirName,description:Q.item.relativePath};return{value:m(Q.item.relativePath),label:Q.item.fileName,description:Q.item.relativePath}})}function t(Y){Y.ui.addAutocompleteProvider((j)=>{let K=zj(r);return{async getSuggestions(H,Q,X,U){if(i())try{let q=await K.getSuggestions(H,Q,X,U);if(q)return q}catch{}return j.getSuggestions(H,Q,X,U)},applyCompletion(H,Q,X,U,q){return j.applyCompletion(H,Q,X,U,q)},shouldTriggerFileCompletion(H,Q,X){return j.shouldTriggerFileCompletion?.(H,Q,X)??!0}}})}J.registerFlag("fff-mode",{description:"FFF mode: tools-and-ui | tools-only | override",type:"string"}),J.registerFlag("fff-frecency-db",{description:"Path to the frecency database (overrides FFF_FRECENCY_DB env)",type:"string"}),J.registerFlag("fff-history-db",{description:"Path to the query history database (overrides FFF_HISTORY_DB env)",type:"string"}),J.registerFlag("fff-enable-root-scan",{description:"Allow indexing when launched from the filesystem root (also: FFF_ENABLE_ROOT_SCAN env)",type:"boolean"}),J.on("session_start",async(Y,j)=>{try{B=j.cwd;let K=j.sessionManager?.getEntries();if(K){let H=[...K].reverse().find((Q)=>Q.type==="custom"&&Q.customType==="fff-mode");if(H&&typeof H.data?.mode==="string"&&h.includes(H.data.mode)){let Q=H.data.mode;if(Q!==k)k=Q}}t(j),await F(B)}catch(K){j.ui.notify(`FFF init failed: ${K instanceof Error?K.message:String(K)}`,"error")}}),J.on("session_shutdown",async()=>{s()});let g=(Y,j,K,H,Q=15)=>{let X=H.lastComponent??new L("",0,0),U=Y.content?.find((O)=>O.type==="text")?.text?.trim()??"";if(!U)return X.setText(K.fg("muted","No output")),X;let q=U.split(`
|
|
4
|
+
`),b=q.slice(0,j.expanded?q.length:Q),S=`
|
|
5
|
+
${b.map((O)=>K.fg("toolOutput",O)).join(`
|
|
6
|
+
`)}`;if(q.length>b.length)S+=K.fg("muted",`
|
|
7
|
+
... (${q.length-b.length} more lines)`);return X.setText(S),X},e=W.Object({pattern:W.String({description:"Search pattern (literal text or regex)"}),path:W.Optional(W.String({description:"Repo-relative path constraint. Directory prefix (src/ or src/foo/), bare filename with extension (main.rs), or glob (*.ts, src/**/*.cc, {src,lib}/**). Applied to the full repo-relative path."})),exclude:W.Optional(W.Union([W.String(),W.Array(W.String())],{description:"Exclude paths (comma/space-separated or array). Same syntax as path: directory prefix ('test/'), filename with extension ('config.json'), or glob ('*.min.js', '**/*.{rs,go}'). A leading '!' is optional and ignored — both 'test/' and '!test/' work. Example: 'test/,*.min.js,!vendor/'."})),caseSensitive:W.Optional(W.Boolean({description:"Force case-sensitive matching. Default uses smart-case (case-insensitive when pattern is all lowercase)."})),context:W.Optional(W.Number({description:"Context lines before+after each match"})),limit:W.Optional(W.Number({description:`Max matches (default ${E})`})),cursor:W.Optional(W.String({description:"Pagination cursor from previous result"}))});J.registerTool({name:V.grep,label:V.grep,description:`Grep file contents. Smart-case, auto-detects regex vs literal, git-aware. Results are ranked by frecency (most-accessed files first); matches within a file stay in source order. Default limit ${E}.`,promptSnippet:"Grep contents",promptGuidelines:["Prefer bare identifiers as patterns. Literal queries are most efficient.","Use path for include ('src/', '*.ts') and exclude for noise ('test/,*.min.js').","caseSensitive: true when you need exact case (smart-case otherwise).","After 1-2 greps, read the top match instead of more greps."],parameters:e,async execute(Y,j,K){if(K?.aborted)throw Error("Operation aborted");let H=await F(B),Q=Math.max(1,j.limit??E),X=x(j.path,j.pattern,j.exclude,B),U=j.pattern!==j.pattern.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),q=U?"regex":"plain";if(q==="regex")try{new RegExp(j.pattern)}catch{q="plain"}let b=j.pattern.trim();if(U&&/^(?:[.^$]*(?:[.][*+?]|\*|\+)[.^$]*|[.^$\s]*|\.\*\??|\.\*[+?]?|\.\+\??|\.|\*|\?)$/.test(b))return{content:[{type:"text",text:`Pattern '${j.pattern}' matches everything — grep needs a concrete substring or identifier. Example: \`pattern: 'MyClass'\` or \`pattern: 'export function'\`.`}],details:{totalMatched:0,totalFiles:0}};let O=j.caseSensitive!==!0,A=H.grep(X,{mode:q,smartCase:O,maxMatchesPerFile:Math.min(Q,50),cursor:(j.cursor?d(j.cursor):null)??null,beforeContext:j.context??0,afterContext:j.context??0,classifyDefinitions:!0});if(!A.ok)throw Error(A.error);let D=A.value,v=null;if(D.items.length===0&&!j.cursor&&q!=="regex"){let I=H.grep(j.pattern,{mode:"fuzzy",smartCase:O,maxMatchesPerFile:Math.min(Q,50),cursor:null,beforeContext:0,afterContext:0,classifyDefinitions:!0});if(I.ok&&I.value.items.length>0)v="0 exact matches. Maybe you meant this?",D=I.value}let N=o(D),R=[];if(D.regexFallbackError)R.push(`Invalid regex: ${D.regexFallbackError}, used literal match`);if(D.nextCursor)R.push(`Continue with cursor="${u(D.nextCursor)}"`);if(R.length>0)N+=`
|
|
8
|
+
|
|
9
|
+
[${R.join(". ")}]`;if(v)N=`[${v}]
|
|
10
|
+
${N}`;return{content:[{type:"text",text:N}],details:{totalMatched:D.totalMatched,totalFiles:D.totalFiles}}},renderCall(Y,j,K){let H=K.lastComponent??new L("",0,0),Q=Y?.pattern??"",X=Y?.path??".",U=j.fg("toolTitle",j.bold(V.grep))+" "+j.fg("accent",`/${Q}/`)+j.fg("toolOutput",` in ${X}`);if(Y?.limit!==void 0)U+=j.fg("toolOutput",` limit ${Y.limit}`);if(Y?.cursor)U+=j.fg("muted"," (page)");return H.setText(U),H},renderResult(Y,j,K,H){return g(Y,j,K,H,15)}});let jj=W.Object({pattern:W.String({description:"Fuzzy filename search and glob search. Frecency-ranked, git-aware. Multi-word = narrower (AND) not bound to order, use for multi word related concept search. Prefer this over ls/find/bash as the first exploration step whenever the user names a concept, feature, or symbol — it surfaces the relevant files in one call. Only use ls/read on a directory when you specifically need the alphabetical layout of an unknown repo, or when a concept search returned nothing."}),path:W.Optional(W.String({description:"Repo-relative path constraint. Directory prefix (src/ or src/foo/), bare filename with extension (main.rs), or glob (*.ts, src/**/*.cc, {src,lib}/**). Applied to the full repo-relative path."})),exclude:W.Optional(W.Union([W.String(),W.Array(W.String())],{description:"Exclude paths (comma/space-separated or array). Same syntax as path: directory prefix ('test/'), filename with extension ('config.json'), or glob ('*.min.js', '**/*.{rs,go}'). A leading '!' is optional and ignored — both 'test/' and '!test/' work. Example: 'test/,*.min.js,!vendor/'."})),limit:W.Optional(W.Number({description:`Max results per page (default ${f})`})),cursor:W.Optional(W.String({description:"Pagination cursor from previous result"}))});if(J.registerTool({name:V.find,label:V.find,description:`Fuzzy path search and glob search. Matches against the whole repo-relative path, not just the filename. Frecency-ranked, git-aware. Multi-word = narrower (AND). Default limit ${f}.`,promptSnippet:"Find files by path or glob",promptGuidelines:["Matches the WHOLE path, not just the filename — `profile` hits `chrome/browser/profiles/x.cc` too.","Keep queries to 1-2 terms; extra words narrow.","Use for paths, not content. Use grep for content.","For exact path matches use a glob in `path` — e.g. path: '**/profile.h' for exact filename, or path: 'src/**/profile.h' scoped to a subtree. Bare patterns are fuzzy.","To list everything inside a directory, pass path: 'dir/**' with an empty or wildcard pattern instead of using pattern alone.","Use exclude: 'test/,*.min.js' to cut noise in large repos."],parameters:jj,async execute(Y,j,K){if(K?.aborted)throw Error("Operation aborted");let H=await F(B),Q=j.cursor?kj(j.cursor):void 0,X=Q?Q.pageSize:Math.max(1,j.limit??f),U=Q?Q.query:x(j.path,j.pattern,j.exclude,B),q=Q?Q.pattern:j.pattern,b=Q?.nextPageIndex??0,S=H.fileSearch(U,{pageIndex:b,pageSize:X});if(!S.ok)throw Error(S.error);let O=S.value,A=bj(O,X,q),D=A.output,v=b*X+O.items.length,N=O.items.length>=X&&O.totalMatched>v,R=[];if(A.weak&&A.shownCount>0)R.push(`Query "${q}" produced only weak scattered fuzzy matches. Output capped at ${A.shownCount}/${O.totalMatched}.`);if(!A.weak&&N){let I=O.totalMatched-v,Jj=Xj({query:U,pattern:q,pageSize:X,nextPageIndex:b+1});R.push(`${I} more match${I===1?"":"es"} available. cursor="${Jj}" to continue`)}if(R.length>0)D+=`
|
|
11
|
+
|
|
12
|
+
[${R.join(". ")}]`;return{content:[{type:"text",text:D}],details:{totalMatched:O.totalMatched,totalFiles:O.totalFiles,pageIndex:b,hasMore:N}}},renderCall(Y,j,K){let H=K.lastComponent??new L("",0,0),Q=Y?.pattern??"",X=Y?.path??".",U=j.fg("toolTitle",j.bold(V.find))+" "+j.fg("accent",Q)+j.fg("toolOutput",` in ${X}`);if(Y?.limit!==void 0)U+=j.fg("toolOutput",` (limit ${Y.limit})`);if(Y?.cursor)U+=j.fg("muted"," (page)");return H.setText(U),H},renderResult(Y,j,K,H){return g(Y,j,K,H,20)}}),process.env.DM_FFF_MULTIGREP==="1"){let Y=W.Object({patterns:W.Array(W.String(),{description:"Literal patterns (OR). Include snake_case/camelCase/PascalCase variants."}),constraints:W.Optional(W.String({description:"File filter, e.g. '*.{ts,tsx} !test/'"})),context:W.Optional(W.Number({description:"Context lines before+after"})),limit:W.Optional(W.Number({description:`Max matches (default ${E})`})),cursor:W.Optional(W.String({description:"Pagination cursor"}))});J.registerTool({name:V.multiGrep,label:V.multiGrep,description:"Search file contents for ANY of multiple literal patterns (OR, SIMD Aho-Corasick). Faster than regex alternation.",promptSnippet:"Multi-pattern OR content search",promptGuidelines:["Use when searching for several identifiers at once.","Include all naming-convention variants (snake/camel/Pascal).","Patterns are literal. Use constraints for file filters."],parameters:Y,async execute(j,K,H){if(H?.aborted)throw Error("Operation aborted");if(!K.patterns?.length)throw Error("patterns array must have at least 1 element");let Q=await F(B),X=Math.max(1,K.limit??E),U=Q.multiGrep({patterns:K.patterns,constraints:K.constraints,maxMatchesPerFile:Math.min(X,50),smartCase:!0,cursor:(K.cursor?d(K.cursor):null)??null,beforeContext:K.context??0,afterContext:K.context??0});if(!U.ok)throw Error(U.error);let q=U.value,b=o(q),S=[];if(q.items.length>=X)S.push(`${X}+ matches (refine patterns)`);if(q.nextCursor)S.push(`More available. cursor="${u(q.nextCursor)}" to continue`);if(S.length>0)b+=`
|
|
13
|
+
|
|
14
|
+
[${S.join(". ")}]`;return{content:[{type:"text",text:b}],details:{totalMatched:q.totalMatched,totalFiles:q.totalFiles,patterns:K.patterns}}},renderCall(j,K,H){let Q=H.lastComponent??new L("",0,0),X=j?.patterns??[],U=j?.constraints,q=K.fg("toolTitle",K.bold(V.multiGrep))+" "+K.fg("accent",X.map((b)=>`"${b}"`).join(", "));if(U)q+=K.fg("toolOutput",` (${U})`);if(j?.cursor)q+=K.fg("muted"," (page)");return Q.setText(q),Q},renderResult(j,K,H,Q){return g(j,K,H,Q,15)}})}J.registerCommand("fff-mode",{description:"Show or set FFF mode: /fff-mode [tools-and-ui | tools-only | override]",handler:async(Y,j)=>{let K=(Y||"").trim();if(!K){let U=T(),q=J.getFlag("fff-mode")??"unset";j.ui.notify(`Current mode: '${U}' (flag: ${q})`,"info");return}if(!h.includes(K)){j.ui.notify(`Usage: /fff-mode [${h.join(" | ")}]`,"warning");return}let H=K,Q=T();a(H),J.appendEntry("fff-mode",{mode:H});let X=Q==="override"!==(H==="override")?" (tool name change requires /reload)":"";j.ui.notify(`Mode changed: '${Q}' → '${H}'${X}`,"info")}}),J.registerCommand("fff-health",{description:"Show FFF file finder health and status",handler:async(Y,j)=>{if(!$||$.isDestroyed){j.ui.notify("FFF not initialized","warning");return}let K=$.healthCheck();if(!K.ok){j.ui.notify(`Health check failed: ${K.error}`,"error");return}let H=K.value,Q=[`FFF v${H.version}`,`Mode: ${T()}`,`Git: ${H.git.repositoryFound?`yes (${H.git.workdir??"unknown"})`:"no"}`,`Picker: ${H.filePicker.initialized?`${H.filePicker.indexedFiles??0} files`:"not initialized"}`,`Frecency: ${H.frecency.initialized?"active":"disabled"}`,`Query tracker: ${H.queryTracker.initialized?"active":"disabled"}`],X=$.getScanProgress();if(X.ok)Q.push(`Scanning: ${X.value.isScanning?"yes":"no"} (${X.value.scannedFilesCount} files)`);j.ui.notify(Q.join(`
|
|
15
|
+
`),"info")}}),J.registerCommand("fff-rescan",{description:"Trigger FFF to rescan files",handler:async(Y,j)=>{if(!$||$.isDestroyed){j.ui.notify("FFF not initialized","warning");return}let K=$.scanFiles();if(!K.ok){j.ui.notify(`Rescan failed: ${K.error}`,"error");return}j.ui.notify("FFF rescan triggered","info")}})}export{n as fffFileAnnotation,Pj as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import G from"node:path";function I(q,B=process.cwd()){let j=q.trim();if(!j)return j;if(G.isAbsolute(j)){let k=G.relative(B,j).replaceAll(G.sep,"/");if(k==="")return null;if(k.startsWith("../")||k===".."||G.isAbsolute(k))throw Error(`Path constraint must be relative to the workspace: ${q}`);j=k}if(j==="."||j==="./")return null;if(j.startsWith("./"))j=j.slice(2);let y=j.match(/^(.*)\/\*\*(?:\/\*)?$/);if(y){let k=y[1];if(k&&!/[*?[{]/.test(k))return`${k}/`}if(j.startsWith("/")||j.endsWith("/"))return j;if(/[*?[{]/.test(j))return j;let A=j.split("/").pop()??"";if(/\.[a-zA-Z][a-zA-Z0-9]{0,9}$/.test(A))return j;return`${j}/`}function K(q,B=process.cwd()){if(!q)return[];let j=Array.isArray(q)?q:[q],y=[];for(let A of j){let k=A.split(/[,\s]+/).map((F)=>F.trim()).filter(Boolean);for(let F of k){let J=F.startsWith("!")?F.slice(1):F,H=I(J,B);if(H)y.push(`!${H}`)}}return y}function M(q,B,j,y=process.cwd()){let A=[];if(q){let k=I(q,y);if(k)A.push(k)}return A.push(...K(j,y)),A.push(B),A.join(" ")}export{I as normalizePathConstraint,K as normalizeExcludes,M as buildQuery};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": null,
|
|
7
7
|
"license": "MIT",
|
|
8
|
-
"main": "src/goal.
|
|
8
|
+
"main": "src/goal.js",
|
|
9
9
|
"files": [
|
|
10
10
|
"src",
|
|
11
11
|
"test",
|
|
@@ -21,40 +21,11 @@
|
|
|
21
21
|
"objective",
|
|
22
22
|
"continuation"
|
|
23
23
|
],
|
|
24
|
-
"repository": {
|
|
25
|
-
"type": "git",
|
|
26
|
-
"url": "git+https://github.com/que-nguyen/dm.git",
|
|
27
|
-
"directory": "extensions/dm-goal"
|
|
28
|
-
},
|
|
29
|
-
"bugs": {
|
|
30
|
-
"url": "https://github.com/que-nguyen/dm/issues"
|
|
31
|
-
},
|
|
32
|
-
"homepage": "https://github.com/que-nguyen/dm#readme",
|
|
33
24
|
"dm": {
|
|
34
25
|
"extensions": [
|
|
35
|
-
"./src/goal.
|
|
26
|
+
"./src/goal.js"
|
|
36
27
|
]
|
|
37
28
|
},
|
|
38
|
-
"scripts": {
|
|
39
|
-
"typecheck": "tsc --noEmit",
|
|
40
|
-
"test": "node --import tsx --test test/*.test.ts",
|
|
41
|
-
"verify": "npm run typecheck && npm test"
|
|
42
|
-
},
|
|
43
|
-
"dependencies": {
|
|
44
|
-
"typebox": "^1.3.3"
|
|
45
|
-
},
|
|
46
|
-
"peerDependencies": {
|
|
47
|
-
"@duckmind/dm-ai": "^0.80.0",
|
|
48
|
-
"@duckmind/dm-coding-agent": "^0.80.0"
|
|
49
|
-
},
|
|
50
29
|
"peerDependenciesMeta": {},
|
|
51
|
-
"devDependencies": {
|
|
52
|
-
"@biomejs/biome": "2.5.2",
|
|
53
|
-
"typescript": "6.0.3",
|
|
54
|
-
"@duckmind/dm-coding-agent": "file:../../dm-mono/packages/coding-agent",
|
|
55
|
-
"@duckmind/dm-ai": "file:../../dm-mono/packages/ai",
|
|
56
|
-
"@types/node": "^22.0.0",
|
|
57
|
-
"tsx": "^4.21.0"
|
|
58
|
-
},
|
|
59
30
|
"engines": {}
|
|
60
31
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import{existsSync as i,mkdirSync as VD,readFileSync as WD,writeFileSync as XD}from"node:fs";import{dirname as YD,join as b}from"node:path";import k from"node:process";import{randomUUID as g}from"node:crypto";import{defineTool as ZD}from"@duckmind/dm-coding-agent";import{isContextOverflow as $D}from"@duckmind/dm-ai";import{Type as p}from"typebox";var _="goal",P="goal-state",v=4000,zD=20,l="dm-goal-continuation:",KD=[/(?<!could\s)\bnot\s+(?:yet\s+)?(?:complete|completed|done|finished)\b/i,/\bstill\s+(?:incomplete|failing|failing\s+tests?|fails?)\b/i,/\btests?\s+(?:still\s+)?fail(?:ing)?\b/i],UD=/usage[_\s-]*limit|chatgpt usage limit|multi-auth rotation failed|credentials tried|unauthori[sz]ed|invalid api key/i,_D=/websocket closed|sse response headers timed out|headers timed out|context[_\s-]*length[_\s-]*exceeded|input exceeds the context window|provider returned error/i,m=[{value:"pause",label:"pause",description:"Pause the active goal"},{value:"resume",label:"resume",description:"Resume a paused or budget-limited goal"},{value:"clear",label:"clear",description:"Clear the current goal"},{value:"edit",label:"edit",description:"Edit the current goal objective"},{value:"status",label:"status",description:"Show the current goal"},{value:"--tokens ",label:"--tokens",description:"Set a token budget before the goal"}],MD={value:"edit --tokens ",label:"--tokens",description:"Set a token budget before the updated goal"},E=b(k.env.DM_CODING_AGENT_DIR??b(k.env.HOME??".",".dm","agent"),"dm-goal-state.json"),H,C,f,Z,O,j=!1,S=new Set,qD=ZD({name:"goal_complete",label:"Goal Complete",description:"Mark the active /goal as complete after all required work is done and verified. Do not use for partial progress, blockers, failing, or unverified work.",promptSnippet:"Mark the active /goal as complete after fully finishing and verifying it",promptGuidelines:["When a /goal is active, keep working until the goal is complete; do not stop with only a plan or partial progress.","Before calling goal_complete, audit the active goal requirement by requirement against the current files, command output, tests, or external state.","Call goal_complete only after the requested goal is fully implemented, verified, and no known required work remains; otherwise keep working."],parameters:p.Object({summary:p.String({description:"State what was completed and what evidence verified it. Do not use this tool to report partial progress, blockers, failures, or remaining work."})}),async execute(D,F,J,Q,V){let W=H,$=W?.text??"unknown goal",N=F.summary.trim();if(!W)return V.ui.notify("Goal completion rejected: no active goal.","warning"),{content:[{type:"text",text:"Goal completion rejected: no active goal."}],details:{goal:$,summary:N}};let y=!N?"summary is empty":xD(N)?"summary says the goal is not complete":void 0;if(y){q(W,V),X(W),Y(V,W);let T=`Goal completion rejected: ${y}.`;return V.ui.notify(T,"warning"),{content:[{type:"text",text:T}],details:{goal:$,summary:N}}}if(W)H=w(W,"complete"),q(H,V),X(H);return V.ui.setStatus(_,W?s(H):void 0),QD(V),VF(V),V.ui.notify(`Goal complete: ${$}`,"info"),{content:[{type:"text",text:`Goal complete: ${N}`}],details:{goal:$,summary:N},terminate:!0}}});function ND(D){f=D,D.registerTool(qD),D.registerCommand("goal",{description:"Run a goal to completion: /goal [--tokens 100k] <goal_to_complete>",getArgumentCompletions:hD,handler:async(F,J)=>{let Q=TD(F);if(typeof Q==="string"){J.ui.notify(Q,"warning");return}switch(Q.kind){case"show":AD(J);return;case"pause":OD(J);return;case"resume":await ED(D,J);return;case"clear":CD(J);return;case"edit":await wD(Q.objective??"",Q.tokenBudget,D,J);return;case"start":await SD(Q.objective??"",Q.tokenBudget,D,J);return}}}),D.on("session_start",(F,J)=>{if(B(),r(),K(),z(),H=x(J),H)Y(J,H);else J.ui.setStatus(_,void 0)}),D.on("session_shutdown",(F,J)=>{if(H)X(H);r(),K(),z(),J.ui.setStatus(_,void 0),B()}),D.on("session_before_compact",(F,J)=>{if(!H||H.status!=="active")return;q(H,J),U(),X(H),Y(J,H)}),D.on("session_compact",async(F,J)=>{if(!H||H.status!=="active"){K();return}let Q=x(J);if(Q?.id===H.id)H=Q;q(H,J),X(H),Y(J,H);let V=rD(F,H.id);if(G(H.id),V||I(J))return;await d(D,J,H)}),D.on("input",(F)=>{if(F.source==="extension"){if(cD(F.text))return{action:"handled"};return}K(),z()}),D.on("tool_call",()=>{if(!j)return;if(!H||H.status!=="paused"){z();return}return{block:!0,reason:"Blocked stale /goal tool call after the goal was paused or interrupted."}}),D.on("before_agent_start",(F)=>{if(sD(F.prompt),!H||H.status!=="active")return;return{systemPrompt:`${F.systemPrompt}
|
|
2
|
+
|
|
3
|
+
${uD(H)}`}}),D.on("agent_end",async(F,J)=>{if(!H||H.status!=="active")return;let Q=H.id,V=Z?.goalId===Q,W=DF(F.messages);if(!V)H=BD(H);if(q(H,J),W?.stopReason==="aborted"||W?.stopReason==="error"){if(iD(W)){O={goalId:Q,kind:t(W)?"compaction_retry":"provider_retry"},U(),X(H),Y(J,H);return}G(Q),RD(J,H,W);return}if(G(Q),H.tokenBudget!==void 0&&H.tokensUsed>=H.tokenBudget){U(),H=w(H,"budget_limited"),X(H),Y(J,H),J.ui.notify(`Goal token budget reached: ${M(H)}`,"warning");return}if(X(H),Y(J,H),V){if(I(J))return;if(Z?.goalId===Q)Z=void 0}let $=H;if(!$||$.id!==Q||$.status!=="active")return;if(I(J))return;await d(D,J,$)})}async function SD(D,F,J,Q){let V=c(D);if(V){Q.ui.notify(V,"warning");return}let W=H?.status!=="complete"?H:void 0;if(W){if(!await Q.ui.confirm("Replace goal?",`Current goal: ${W.text}
|
|
4
|
+
|
|
5
|
+
New goal: ${D}`)){Q.ui.notify(`Goal kept: ${W.text}`,"info");return}}U(),K(),z(),H=ID(D,F,HD(Q)),X(H),Y(Q,H),Q.ui.notify(W?`Goal replaced: ${D}`:`Goal started: ${D}`,"info"),await fD(J,Q,H)}function OD(D){if(!H){D.ui.notify("No active goal.","info");return}if(H.status!=="active"){D.ui.notify(`Goal is ${H.status}; only active goals can be paused.`,"warning");return}U(),a(),e(D),H=w(H,"paused"),X(H),Y(D,H),D.ui.notify(`Goal paused: ${H.text}`,"info")}async function ED(D,F){if(!H){F.ui.notify("No active goal.","info");return}if(H.status!=="paused"&&H.status!=="budget_limited"){F.ui.notify(`Goal is ${H.status}; only paused or budget-limited goals can be resumed.`,"warning");return}if(K(),z(),H=w(H,"active"),X(H),Y(F,H),H.status!=="active"){F.ui.notify(`Goal token budget is still reached: ${M(H)}`,"warning");return}F.ui.notify(`Goal resumed: ${H.text}`,"info"),await yD(D,F,H)}function CD(D){if(!H){D.ui.notify("No active goal.","info"),U(),K(),z(),JD(D.cwd),D.ui.setStatus(_,void 0);return}let F=H.text;QD(D),D.ui.notify(`Goal cleared: ${F}`,"warning")}async function wD(D,F,J,Q){let V=c(D);if(V){Q.ui.notify(V,"warning");return}if(!H){Q.ui.notify("No active goal. Use /goal <objective> to start one.","warning");return}if(q(H,Q),U(),K(),H=n({...H,text:D,status:LD(H.status),tokenBudget:F??H.tokenBudget,updatedAt:Date.now()}),X(H),Y(Q,H),Q.ui.notify(`Goal updated: ${D}`,"info"),H.status==="active")z(),await jD(J,Q,H)}function AD(D){if(!H){D.ui.notify(`Usage: /goal <objective>
|
|
6
|
+
No goal is currently set.`,"info"),D.ui.setStatus(_,void 0);return}q(H,D),X(H),Y(D,H),D.ui.notify(bD(H),"info")}function ID(D,F,J){let Q=Date.now();return{id:g(),text:D,status:"active",startedAt:Q,updatedAt:Q,iteration:0,tokenBudget:F,tokensUsed:0,timeUsedSeconds:0,baselineTokens:J}}function w(D,F){return n({...D,status:F,updatedAt:Date.now()})}function LD(D){return D==="paused"?"paused":"active"}function n(D){if(D.status==="active"&&D.tokenBudget!==void 0&&D.tokensUsed>=D.tokenBudget)return{...D,status:"budget_limited"};return D}function BD(D){return{...D,iteration:D.iteration+1,updatedAt:Date.now()}}function RD(D,F,J){U(),a(),e(D),H=w(F,"paused"),X(H),Y(D,H);let Q=J.stopReason==="aborted"?"interruption":"agent error",V=J.errorMessage?` (${FD(J.errorMessage)})`:"";D.ui.notify(`Goal paused after ${Q}${V}. Run /goal resume to continue.`,"warning")}function q(D,F){D.tokensUsed=Math.max(0,HD(F)-D.baselineTokens),D.timeUsedSeconds=Math.max(0,Math.floor((Date.now()-D.startedAt)/1000)),D.updatedAt=Date.now()}function hD(D){let F=D.trimStart();if(F==="")return[...m];let J=/^edit\s+(\S*)$/.exec(F)?.[1];if(J!==void 0)return J===""||"--tokens".startsWith(J)?[MD]:null;if(/\s/.test(F))return null;let Q=m.filter((V)=>V.value.startsWith(F)||V.label.startsWith(F));return Q.length>0?[...Q]:null}function TD(D){let F=GD(D.trim());if(F.length===0)return{kind:"show"};let[J,...Q]=F;if(J==="pause")return Q.length===0?{kind:"pause"}:"Usage: /goal pause";if(J==="resume")return Q.length===0?{kind:"resume"}:"Usage: /goal resume";if(J==="clear"||J==="stop")return Q.length===0?{kind:"clear"}:"Usage: /goal clear";if(J==="status")return Q.length===0?{kind:"show"}:"Usage: /goal status";if(J==="edit")return u("edit",Q);return u("start",F)}function u(D,F){let J,Q=[...F];if(Q[0]==="--tokens"){let V=Q[1];if(!V)return"Usage: /goal --tokens 100k <goal_to_complete>";let W=PD(V);if(W===void 0)return`Invalid token budget: ${V}`;J=W,Q.splice(0,2)}if(Q.length===0)return D==="edit"?"Usage: /goal edit <goal_to_complete>":"Usage: /goal <goal_to_complete>";return{kind:D,objective:Q.join(" "),tokenBudget:J}}function GD(D){let F=[],J="",Q;for(let V of D){if(Q){if(V===Q)Q=void 0;else J+=V;continue}if(V==='"'||V==="'"){Q=V;continue}if(/\s/.test(V)){if(J)F.push(J);J="";continue}J+=V}if(J)F.push(J);return F}function PD(D){let F=/^(\d+(?:\.\d+)?)([km])?$/iu.exec(D.trim());if(!F)return;let J=Number(F[1]);if(!Number.isFinite(J)||J<=0)return;let Q=F[2]?.toLowerCase()==="m"?1e6:F[2]?.toLowerCase()==="k"?1000:1;return Math.floor(J*Q)}function c(D){let F=D.trim();if(!F)return"Usage: /goal <goal_to_complete>";if(F.length>v)return`Goal objective is too long (${F.length}/${v} characters). Put long instructions in a file and reference it from /goal instead.`;return}async function fD(D,F,J){return R(D,F,pD(J))}async function jD(D,F,J){return R(D,F,vD(J))}async function yD(D,F,J){return R(D,F,mD(J))}async function d(D,F,J){if(Z?.goalId===J.id)return!1;if(I(F))return!1;let Q=oD(J),V=dD(J,Q);Z={goalId:J.id,iteration:J.iteration,marker:Q,prompt:V};let W=await R(D,F,V);if(!W&&Z?.marker===Q)Z=void 0;return W}async function R(D,F,J){try{return await(F.isIdle?.()?D.sendUserMessage(J):D.sendUserMessage(J,{deliverAs:"followUp"})),!0}catch(Q){return F.ui.notify(`Goal prompt failed: ${QF(Q)}`,"error"),!1}}function Y(D,F){B(),D.ui.setStatus(_,s(F))}function s(D){if(!D)return;if(D.status==="complete")return"complete";if(D.status==="paused")return"paused";if(D.status==="budget_limited")return`budget ${M(D)}`;if(D.tokenBudget!==void 0)return`active ${M(D)}`;return`active ${o(D.timeUsedSeconds)}`}function M(D){return`${L(D.tokensUsed)}/${L(D.tokenBudget??0)}`}function bD(D){return[`Goal: ${D.text}`,`Status: ${D.status}`,`Iteration: ${D.iteration}`,`Elapsed: ${o(D.timeUsedSeconds)}`,`Tokens: ${D.tokenBudget===void 0?L(D.tokensUsed):M(D)}`,`Commands: ${kD(D.status)}`].join(`
|
|
7
|
+
`)}function kD(D){if(D==="active")return"/goal edit <objective>, /goal pause, /goal clear";if(D==="paused")return"/goal edit <objective>, /goal resume, /goal clear";return"/goal edit <objective>, /goal clear"}function o(D){if(D<60)return`${D}s`;let F=Math.floor(D/60);if(F<60)return`${F}m`;return`${Math.floor(F/60)}h${F%60}m`}function L(D){if(D<1000)return`${D}`;if(D<1e6)return`${Number.isInteger(D/1000)?D/1000:(D/1000).toFixed(1)}k`;return`${Number.isInteger(D/1e6)?D/1e6:(D/1e6).toFixed(1)}m`}function pD(D){let F=D.tokenBudget===void 0?"":`
|
|
8
|
+
Token budget: ${L(D.tokenBudget)}.`;return`Goal mode is active. Complete this goal fully:
|
|
9
|
+
|
|
10
|
+
${A(D)}${F}
|
|
11
|
+
|
|
12
|
+
${h("this goal")}`}function vD(D){let F=D.tokenBudget===void 0?"":`
|
|
13
|
+
Token budget: ${M(D)} used.`;return`The active /goal objective was updated. Continue working toward this goal:
|
|
14
|
+
|
|
15
|
+
${A(D)}${F}
|
|
16
|
+
|
|
17
|
+
${h("the updated goal")}`}function mD(D){let F=D.tokenBudget===void 0?"":`
|
|
18
|
+
Token budget: ${M(D)} used.`;return`The user explicitly resumed the paused /goal. Continue working toward this goal:
|
|
19
|
+
|
|
20
|
+
${A(D)}${F}
|
|
21
|
+
|
|
22
|
+
${h("this goal")}`}function uD(D){let F=D.tokenBudget===void 0?"":`
|
|
23
|
+
- Respect the goal token budget (${M(D)} used).`;return`Active /goal:
|
|
24
|
+
${A(D)}
|
|
25
|
+
|
|
26
|
+
Goal-mode rules:
|
|
27
|
+
- Keep going until the active goal is completely resolved end-to-end.
|
|
28
|
+
- Treat the current worktree, command output, tests, and external state as authoritative.
|
|
29
|
+
- Do not redefine the goal into a smaller task; audit every requirement before completion.
|
|
30
|
+
- Do not stop at analysis, a plan, TODO list, partial fixes, or suggested next steps.
|
|
31
|
+
- Autonomously perform implementation and verification with the available tools when they are needed to complete the goal.
|
|
32
|
+
- Persevere through recoverable tool failures by trying reasonable alternatives instead of yielding early.
|
|
33
|
+
- If the goal is not complete at the end of a turn, expect an automatic continuation and keep working from where you left off.
|
|
34
|
+
- Only call the goal_complete tool after the goal is fully complete and verified.${F}`}function dD(D,F){return`Continue the active /goal until it is complete:
|
|
35
|
+
|
|
36
|
+
${A(D)}
|
|
37
|
+
|
|
38
|
+
This is automatic continuation #${D.iteration}. Current files, command output, tests, and external state are authoritative; re-check them as needed. ${h("this goal")}
|
|
39
|
+
|
|
40
|
+
${eD(F)}`}function A(D){return`<goal_objective>
|
|
41
|
+
${JF(D.text)}
|
|
42
|
+
</goal_objective>`}function h(D){return`Keep going until ${D} is completely resolved end-to-end. Do not redefine ${D} into a smaller task. Do not stop at analysis, a plan, TODO list, partial fixes, or suggested next steps. Autonomously perform implementation and verification with the available tools when they are needed. Treat the current worktree, command output, tests, and external state as authoritative. If a tool call fails, try reasonable alternatives instead of yielding early. Before calling goal_complete, audit ${D} requirement by requirement against the verified current state. Only call the goal_complete tool after ${D} is fully complete and verified.`}function I(D){return D.hasPendingMessages?.()??!1}function e(D){try{D.abort?.()}catch{}}function a(){j=!0}function z(){j=!1}function K(){O=void 0}function G(D){if(O?.goalId===D)O=void 0}function rD(D,F){let J=D;if(J.willRetry===!0)return!0;return O?.goalId===F&&O.kind==="compaction_retry"&&(J.reason===void 0||J.reason==="overflow")}function xD(D){return KD.some((F)=>F.test(D))}function iD(D){if(D.stopReason!=="error")return!1;if(!D.errorMessage)return!1;if(UD.test(D.errorMessage))return!1;return t(D)||_D.test(D.errorMessage)}function t(D){return $D(gD(D))}function gD(D){return{role:"assistant",content:D.content??[],api:D.api??"openai-responses",provider:D.provider??"unknown",model:D.model??"unknown",usage:D.usage??lD(),stopReason:D.stopReason??"error",errorMessage:D.errorMessage,timestamp:D.timestamp??Date.now()}}function lD(){return{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}}}function r(){Z=void 0,S.clear()}function U(){if(Z)nD(Z.marker);Z=void 0}function nD(D){if(S.add(D),S.size<=zD)return;let F=S.values().next().value;if(F)S.delete(F)}function cD(D){let F=DD(D);return F?S.delete(F):!1}function sD(D){let F=DD(D);if(F&&Z?.marker===F)Z=void 0}function oD(D){return`${D.id}:${D.iteration}:${g()}`}function eD(D){return`<!-- ${l}${D} -->`}function aD(D){return D.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var tD=new RegExp(`<!--\\s*${aD(l)}([^\\s>]+)\\s*-->`);function DD(D){return tD.exec(D)?.[1]}function DF(D){for(let F=D.length-1;F>=0;F--){let J=D[F];if(!J||typeof J!=="object")continue;let Q=J;if(Q.role!=="assistant")continue;let V={role:"assistant",stopReason:FF(Q.stopReason)?Q.stopReason:void 0,errorMessage:typeof Q.errorMessage==="string"?Q.errorMessage:void 0};if(Array.isArray(Q.content))V.content=Q.content;if(typeof Q.api==="string")V.api=Q.api;if(typeof Q.provider==="string")V.provider=Q.provider;if(typeof Q.model==="string")V.model=Q.model;if(typeof Q.timestamp==="number")V.timestamp=Q.timestamp;let W=HF(Q.usage);if(W)V.usage=W;return V}return}function FF(D){return["stop","length","toolUse","error","aborted"].includes(String(D))}function HF(D){if(!D||typeof D!=="object")return;let F=D;if(typeof F.input!=="number"||typeof F.output!=="number")return;return{input:F.input,output:F.output,cacheRead:F.cacheRead??0,cacheWrite:F.cacheWrite??0,totalTokens:F.totalTokens??F.input+F.output+(F.cacheRead??0),cost:{input:F.cost?.input??0,output:F.cost?.output??0,cacheRead:F.cost?.cacheRead??0,cacheWrite:F.cost?.cacheWrite??0,total:F.cost?.total??0}}}function JF(D){return D.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function QF(D){return FD(D instanceof Error?D.message:String(D))}function FD(D){return D.length>160?`${D.slice(0,157)}...`:D}function HD(D){let J=D.sessionManager?.getBranch?.()??[],Q=0;for(let V of J){if(V.type!=="message"||V.message?.role!=="assistant")continue;let W=V.message.usage;Q+=W?.input??0,Q+=W?.output??0}return Q}function X(D){f?.appendEntry(P,{goal:D})}function JD(D){f?.appendEntry(P,{goal:null}),XF(D)}function x(D){let F=D.sessionManager,V=(F?.getBranch?.()??F?.getEntries?.()??[]).filter((W)=>W.type==="custom"&&W.customType===P).pop()?.data;return YF(V?.goal)&&V.goal.status!=="complete"?V.goal:void 0}function QD(D){U(),K(),z(),H=void 0,JD(D.cwd),D.ui.setStatus(_,void 0)}function VF(D){B(),D.ui.setStatus(_,"complete"),C=setTimeout(()=>{C=void 0;try{D.ui.setStatus(_,void 0)}catch{}},8000)}function B(){if(!C)return;clearTimeout(C),C=void 0}function WF(){if(!i(E))return{};try{let D=JSON.parse(WD(E,"utf8"));return D&&typeof D==="object"&&!Array.isArray(D)?D:{}}catch{return{}}}function XF(D){if(!i(E))return;let F=WF();delete F[D],VD(YD(E),{recursive:!0}),XD(E,`${JSON.stringify(F,null,2)}
|
|
43
|
+
`)}function YF(D){if(!D||typeof D!=="object")return!1;let F=D;return typeof F.id==="string"&&typeof F.text==="string"&&["active","paused","budget_limited","complete"].includes(String(F.status))&&typeof F.startedAt==="number"&&typeof F.updatedAt==="number"&&typeof F.iteration==="number"&&typeof F.tokensUsed==="number"&&typeof F.timeUsedSeconds==="number"&&typeof F.baselineTokens==="number"}export{c as validateObjective,PD as parseTokenBudget,TD as parseCommand,iD as isRetryableGoalInterruption,xD as isContradictoryCompletionSummary,L as formatTokenCount,s as formatStatus,o as formatDuration,DF as findFinalAssistantMessage,ND as default,hD as completeGoalArguments,uD as buildGoalSystemPrompt};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import{CustomEditor as c,DynamicBorder as r,getMarkdownTheme as s}from"@duckmind/dm-coding-agent";import{Markdown as a,matchesKey as N,Text as k,truncateToWidth as P}from"@duckmind/dm-tui";import{Type as H}from"typebox";var v="grill-me-state",e="design-doc by default; adapt/recommend near readiness",U={active:!1,topic:"",intent:"auto",outputPreference:"",researchMode:"auto",checkpoint:"",phase:"interview",outputPhase:!1,outputSelection:void 0,approvedOutputPlan:void 0,alternatives:[],currentQuestion:void 0,updatedAt:Date.now()},p=["auto","plan","learn","research","content","decide"],l=["off","ask","auto"],g=[{label:"GitHub issues",value:"github-issues",description:"Issue titles/bodies/labels for implementation slices, research tasks, tutorial chapters, or milestones."},{label:"Design doc",value:"design-doc",description:"A structured design proposal with goals, constraints, architecture, tradeoffs, risks, and rollout."},{label:"README.md",value:"readme",description:"A README or README update covering setup, usage, behavior, examples, and caveats."},{label:"ADR",value:"adr",description:"Architecture Decision Record(s) documenting decision context, options, choice, and consequences."},{label:"PRD",value:"prd",description:"Product requirements, user stories, scope, acceptance criteria, and non-goals."},{label:"Implementation plan",value:"implementation-plan",description:"Step-by-step engineering plan, milestones, sequencing, dependencies, and validation."},{label:"Research brief",value:"research-brief",description:"Open questions, investigation plan, evidence to gather, and decision criteria."},{label:"Summary / decision memo",value:"summary",description:"Concise summary of the checkpoint, decisions, assumptions, and next actions."},{label:"Tutorial / content outline",value:"content-outline",description:"Chapters, lesson flow, examples, exercises, or publishing outline."},{label:"Test plan / QA checklist",value:"test-plan",description:"Acceptance tests, manual QA steps, edge cases, and regression coverage."},{label:"Changelog / release notes",value:"release-notes",description:"User-facing change summary, migration notes, and release caveats."}],b="If approved GitHub issue output has no repo/remote, ask to initialize, create, or select one before creating the previewed issues; use drafts only if the user chooses.";function C(J){return{...J}}function E(J){return(typeof J.outputPreference==="string"?J.outputPreference.trim():"")||"(none set; explicitly ask for one or more outputs before production)"}function O(){return g.map((J)=>`- ${J.label} (${J.value}): ${J.description}`).join(`
|
|
2
|
+
`)}function f(){return g.map((J)=>J.label).join(", ")}function A(J){if(J.outputPhase)return"output";return J.phase??"interview"}function d(J){let j=A(J);if(j==="output")return"output production; approved mutations allowed";if(j==="output-selection")return"mandatory output selection; choose final outputs/continue/stop";return"interview; read-only enforcement active"}function t(J,j){return`# Shared Understanding
|
|
3
|
+
|
|
4
|
+
## Topic
|
|
5
|
+
|
|
6
|
+
${J}
|
|
7
|
+
|
|
8
|
+
## Current Understanding
|
|
9
|
+
|
|
10
|
+
We are starting a grill-me session to reach shared understanding before producing outputs or implementation work.
|
|
11
|
+
|
|
12
|
+
## Working Configuration
|
|
13
|
+
|
|
14
|
+
- Intent: ${j.intent}
|
|
15
|
+
- Grilling style: thorough Socratic interview
|
|
16
|
+
- Research mode: ${j.researchMode}
|
|
17
|
+
- Output preference: ${E(j)}
|
|
18
|
+
|
|
19
|
+
## Decisions
|
|
20
|
+
|
|
21
|
+
- Grill mode uses a single thorough default style.
|
|
22
|
+
- Grill mode should adapt to the subject rather than force hardcoded interview phases.
|
|
23
|
+
- A hardcoded output-selection phase is mandatory at the end of the interview before output production or stopping.
|
|
24
|
+
- Grill mode must not assume a default output. The assistant must explicitly ask which output(s) to produce.
|
|
25
|
+
|
|
26
|
+
## Assumptions
|
|
27
|
+
|
|
28
|
+
- The checkpoint should evolve as meaningful understanding changes.
|
|
29
|
+
- The assistant should ask enough follow-up questions to resolve the decision tree instead of rushing to readiness.
|
|
30
|
+
|
|
31
|
+
## Risks / Unknowns
|
|
32
|
+
|
|
33
|
+
- The user's desired outcome mode and output set may still be ambiguous.
|
|
34
|
+
- Some branches may need to be explicitly deferred if they are not worth resolving now.
|
|
35
|
+
|
|
36
|
+
## Coverage Checklist
|
|
37
|
+
|
|
38
|
+
Use this as an adaptive checklist, not a rigid phase order. Mark each branch resolved, intentionally deferred, or still open.
|
|
39
|
+
|
|
40
|
+
- [ ] Desired outcome and success criteria
|
|
41
|
+
- [ ] Scope boundaries and non-goals
|
|
42
|
+
- [ ] User/audience/stakeholder context
|
|
43
|
+
- [ ] Constraints, dependencies, and available resources
|
|
44
|
+
- [ ] Alternatives, tradeoffs, and decision criteria
|
|
45
|
+
- [ ] Risks, failure modes, edge cases, and open unknowns
|
|
46
|
+
- [ ] Validation, testing, or evidence plan
|
|
47
|
+
- [ ] Rollout/next steps and ownership
|
|
48
|
+
- [ ] Output artifact selection (only in the mandatory terminal phase)
|
|
49
|
+
|
|
50
|
+
## Decision Branches
|
|
51
|
+
|
|
52
|
+
- Root: clarify the user's desired outcome and success criteria, then follow dependent branches one at a time.
|
|
53
|
+
|
|
54
|
+
## Open Questions
|
|
55
|
+
|
|
56
|
+
- What outcome is the user ultimately trying to achieve with this topic?
|
|
57
|
+
- What constraints or risks should shape the next branch of questioning?
|
|
58
|
+
- Which output artifact(s) should be produced, if any, once shared understanding is sufficient?
|
|
59
|
+
|
|
60
|
+
## Explicit Output Destination Options
|
|
61
|
+
|
|
62
|
+
${O()}
|
|
63
|
+
`}function jj(J){return`# Grill Status
|
|
64
|
+
|
|
65
|
+
- Active: ${J.active?"yes":"no"}
|
|
66
|
+
- Topic: ${J.topic||"(none)"}
|
|
67
|
+
- Intent: ${J.intent}
|
|
68
|
+
- Style: thorough default
|
|
69
|
+
- Research: ${J.researchMode}
|
|
70
|
+
- Phase: ${d(J)}
|
|
71
|
+
- Output preference: ${E(J)}
|
|
72
|
+
${J.outputSelection?`- Output selection rationale: ${J.outputSelection.readinessRationale}
|
|
73
|
+
- Recommended outputs: ${J.outputSelection.recommendedOutputs}
|
|
74
|
+
- Recommended strategy: ${J.outputSelection.recommendedStrategy}
|
|
75
|
+
`:""}${J.approvedOutputPlan?`- Approved output plan: ${J.approvedOutputPlan}
|
|
76
|
+
`:""}- Current question: ${J.currentQuestion||"(none)"}
|
|
77
|
+
- Tab alternatives: ${J.alternatives.length?J.alternatives.map((j)=>j.label).join(" | "):"(none set)"}
|
|
78
|
+
- Checkpoint last updated: ${J.updatedAt?new Date(J.updatedAt).toLocaleString():"never"}
|
|
79
|
+
${J.lastChangeSummary?`- Last checkpoint change: ${J.lastChangeSummary}
|
|
80
|
+
`:""}`}function T(J){return J.map((j)=>({value:String(j.value??"").trim(),label:String(j.label??j.value??"").trim(),description:j.description?String(j.description).trim():void 0})).filter((j)=>j.value&&j.label).slice(0,5)}function y(J){return J.replace(/\r\n/g,`
|
|
81
|
+
`).trim()}function Jj(J,j,X){if(j.length===0)return-1;let z=y(J);if(!z)return X>0?0:j.length-1;let F=j.findIndex((q)=>y(q.value)===z);if(F>=0)return(F+X+j.length)%j.length;if(/\s/.test(z))return-1;let K=z.toLowerCase();return j.findIndex((q)=>q.label.toLowerCase().includes(K)||q.value.toLowerCase().includes(K))}class m extends c{grillKeybindings;getGrillState;constructor(J,j,X,z,F){super(J,j,X,F);this.grillKeybindings=X;this.getGrillState=z}handleInput(J){if(!this.isShowingAutocomplete()){if(this.grillKeybindings.matches(J,"tui.input.tab")&&this.cycleGrillAlternative(1))return;if(N(J,"shift+tab")&&this.cycleGrillAlternative(-1))return}super.handleInput(J)}cycleGrillAlternative(J){let j=this.getGrillState();if(!j.active||j.alternatives.length===0)return!1;let X=Jj(this.getText(),j.alternatives,J);if(X<0)return!1;return this.setText(j.alternatives[X].value),this.tui.requestRender(),!0}}function Qj(J,j){return{async getSuggestions(X,z,F,K){let q=j();if(!q.active||q.alternatives.length===0)return J.getSuggestions(X,z,F,K);let V=X[z]??"",Q=V.slice(0,F),Y=V.slice(F),Z=Q.match(/([^\s]*)$/)?.[1]??"",W=Q.slice(0,Q.length-Z.length);if(!(X.slice(0,z).join(`
|
|
82
|
+
`).trim()===""&&W.trim()===""&&Y.trim()===""&&X.slice(z+1).join(`
|
|
83
|
+
`).trim()===""))return J.getSuggestions(X,z,F,K);let B=Z.toLowerCase(),w=q.alternatives.filter((G)=>!B||G.label.toLowerCase().includes(B)||G.value.toLowerCase().includes(B)).map((G)=>({value:G.value,label:G.label,description:G.description}));if(w.length===0)return J.getSuggestions(X,z,F,K);return{prefix:Z,items:w}},applyCompletion(X,z,F,K,q){return J.applyCompletion(X,z,F,K,q)},shouldTriggerFileCompletion(X,z,F){return J.shouldTriggerFileCompletion?.(X,z,F)??!0}}}function Vj(J){let j=J?.content;if(typeof j==="string")return j;if(Array.isArray(j))return j.filter((X)=>X?.type==="text"&&typeof X.text==="string").map((X)=>X.text).join(`
|
|
84
|
+
`);return""}function h(J){let j=J.sessionManager.getBranch(),X=[];for(let F=j.length-1;F>=0&&X.join(`
|
|
85
|
+
`).length<1600;F--){let K=j[F];if(K?.type!=="message")continue;let q=K.message?.role;if(q!=="user"&&q!=="assistant")continue;let V=Vj(K.message).trim();if(!V||V.startsWith("/grill"))continue;X.unshift(`${q}: ${V}`)}let z=X.join(`
|
|
86
|
+
|
|
87
|
+
`).trim();return z?`Current conversation context:
|
|
88
|
+
|
|
89
|
+
${z}`:""}function Xj(J){let j=J.match(/(?:[^\s"]+|"[^"]*")+/g)??[],X={},z=[];for(let F=0;F<j.length;F++){let K=j[F].replace(/^"|"$/g,"");if(K.startsWith("--")){let q=K.indexOf("=");if(q>2)X[K.slice(2,q)]=K.slice(q+1);else{let V=K.slice(2),Q=j[F+1]?.replace(/^"|"$/g,"");if(Q&&!Q.startsWith("--"))X[V]=Q,F++;else X[V]=!0}}else z.push(K)}return{flags:X,rest:z.join(" ").trim()}}function x(J){return typeof J==="string"&&p.includes(J)?J:void 0}function u(J){return typeof J==="string"&&l.includes(J)?J:void 0}function Zj(J){return J.trim().split(/\s+/,1)[0]?.toLowerCase()??""}function $j(J){return J.split(/&&|\|\||;|\n/).map((j)=>j.trim()).filter(Boolean)}function zj(J){let j=J[1];return["status","log","diff","show","branch","grep","ls-files","remote","rev-parse","describe"].includes(j)}function Wj(J){let j=J[1],X=J[2];if(["status","auth","repo","pr","issue","label","milestone"].includes(j)===!1)return!1;if(j==="repo")return[void 0,"view","list"].includes(X);if(j==="issue")return[void 0,"list","view","status"].includes(X);if(j==="pr")return[void 0,"list","view","status","diff","checks"].includes(X);if(j==="label"||j==="milestone")return[void 0,"list","view"].includes(X);return!0}function Yj(J){let j=J.trim();if(!j)return!0;if(/(^|[^<])>(>|&)?\s*\S/.test(j)||/\btee\b/.test(j))return!1;if(/\b(rm|mv|cp|mkdir|rmdir|touch|chmod|chown|sudo|kill|pkill|reboot|shutdown|curl\s+.*\|\s*(sh|bash)|wget\s+.*\|\s*(sh|bash))\b/.test(j))return!1;let z=["git add","git commit","git push","git checkout","git switch","git reset","git merge","git rebase","npm install","npm i","npm add","pnpm install","pnpm add","yarn add","yarn install","pip install","cargo install","cargo add","gh issue create","gh issue edit","gh issue close","gh pr create","gh pr edit"],F=j.toLowerCase();if(z.some((K)=>F.includes(K)))return!1;for(let K of $j(j)){let q=K.split(/\s+/),V=q[0];if(!V)continue;if(["cat","head","tail","less","more","grep","rg","find","fd","ls","pwd","tree","wc","sort","uniq","cut","awk","sed","date","whoami","uname","which","where","echo"].includes(V))continue;if(["npm","pnpm","yarn"].includes(V)){if(["list","outdated","view","info","why"].includes(q[1]))continue;return!1}if(V==="git"){if(zj(q))continue;return!1}if(V==="gh"){if(Wj(q))continue;return!1}return!1}return!0}function Hj(J){let j=C(U);function X(){j.updatedAt=Date.now(),J.appendEntry(v,C(j))}function z(V){if(!j.active){V.ui.setStatus("grill-me",void 0),V.ui.setWidget("grill-me",void 0);return}let Q=A(j),Y=Q==="output"?"\uD83D\uDD25 grill: output":Q==="output-selection"?"\uD83D\uDD25 grill: select output":"\uD83D\uDD25 grill";V.ui.setStatus("grill-me",V.ui.theme.fg(Q==="output"?"warning":Q==="output-selection"?"success":"accent",Y));let $=j.topic.length>90?`${j.topic.slice(0,87)}...`:j.topic,Z=[V.ui.theme.fg("accent",`\uD83D\uDD25 Grill Me: ${$||"active"}`),V.ui.theme.fg("muted",`intent=${j.intent} style=thorough research=${j.researchMode}`),V.ui.theme.fg("dim",`Phase: ${d(j)}`)];if(j.alternatives.length>0){Z.push(V.ui.theme.fg("accent","Tab: fill/cycle replies • Shift+Tab previous • Enter sends"));for(let W of j.alternatives){let R=W.description?` — ${W.description}`:"";Z.push(V.ui.theme.fg("muted",` • ${W.label}${R}`))}}V.ui.setWidget("grill-me",Z,{placement:"belowEditor"})}function F(V,Q,Y={},$="Grill Me"){j={...C(U),...Y,active:!0,topic:V,phase:"interview",outputPhase:!1,outputSelection:void 0,approvedOutputPlan:void 0},j.checkpoint=t(V,j),j.lastChangeSummary=`Started ${$} session`,X(),z(Q),J.sendUserMessage(`Start a ${$} session for this topic:
|
|
90
|
+
|
|
91
|
+
${V}
|
|
92
|
+
|
|
93
|
+
Begin by updating the checkpoint if needed, seed or maintain the coverage checklist, clarity ledger, and decision branches, then call grill_set_alternatives with 2-5 concrete answer choices and ask the first focused Socratic question. Route repo/docs facts to read-only inspection when available, ask the user for judgments and tradeoffs, and run a light pressure pass over assumptions/risks before closing. Mention that Tab fills/cycles suggested replies and Enter sends the selected or edited reply. Use the single thorough grilling style. When the interview is ready to end, the mandatory hardcoded output-selection phase must be entered with grill_enter_output_selection_phase before producing outputs or stopping.`)}async function K(V){if(!V.hasUI){J.sendMessage({customType:"grill-me-checkpoint",content:j.checkpoint,display:!0});return}return await V.ui.custom((Q,Y,$,Z)=>{let W=new r((M)=>Y.fg("accent",M)),R=new a(j.checkpoint,1,0,s()),B=0,w=0,G=[],D=16;function L(M){if(w!==M||G.length===0)w=M,G=R.render(M);return G}function S(){return Math.max(0,G.length-D)}function _(M){B=Math.max(0,Math.min(S(),B+M)),Q.requestRender()}return{render(M){let I=L(M);B=Math.min(B,S());let o=I.slice(B,B+D),n=I.length>D?`lines ${B+1}-${Math.min(B+D,I.length)} of ${I.length}`:"full checkpoint";return[...W.render(M),P(Y.fg("accent",Y.bold("\uD83D\uDD25 Grill Me Checkpoint")),M),P(Y.fg("dim",`${n} • ↑↓/PgUp/PgDn scroll • e edit • Enter/Esc close`),M),...o.map((i)=>P(i,M,"")),...W.render(M)]},invalidate(){W.invalidate(),R.invalidate(),w=0,G=[]},handleInput(M){if(N(M,"escape")||N(M,"enter"))Z(void 0);else if(N(M,"e"))Z("edit");else if(N(M,"up"))_(-1);else if(N(M,"down"))_(1);else if(N(M,"pageUp"))_(-D);else if(N(M,"pageDown"))_(D)}}},{overlay:!0,overlayOptions:{anchor:"center",width:"80%",minWidth:50,maxHeight:"80%",margin:2}})}async function q(V,Q){if(!j.checkpoint.trim()){V.ui.notify("No grill checkpoint yet.","warning");return}let Y=Q?.trim().toLowerCase()||"overlay";if(Y.includes("edit")){let Z=await V.ui.editor("Edit Grill Me checkpoint",j.checkpoint);if(Z!==void 0)j.checkpoint=Z.trim()||j.checkpoint,j.lastChangeSummary="Checkpoint edited by user",X(),z(V),V.ui.notify("Grill checkpoint updated.","info");return}if(Y.includes("chat")){J.sendMessage({customType:"grill-me-checkpoint",content:j.checkpoint,display:!0});return}if(await K(V)==="edit")await q(V,"edit")}J.registerCommand("checkpoint",{description:"Show the current Grill Me checkpoint in an overlay",handler:async(V,Q)=>{await q(Q,V.trim())}}),J.registerCommand("grill",{description:"Start or control a Socratic Grill Me planning session",handler:async(V,Q)=>{let Y=V.trim(),$=Zj(Y),Z=Y.slice($.length).trim();if($==="help"){J.sendMessage({customType:"grill-me-help",content:`# Grill Me commands
|
|
94
|
+
|
|
95
|
+
- /grill <topic>
|
|
96
|
+
- /grill stop
|
|
97
|
+
- /checkpoint [edit|chat]
|
|
98
|
+
- /grill checkpoint [edit|chat]
|
|
99
|
+
- /grill status
|
|
100
|
+
- /grill intent auto|plan|learn|research|content|decide
|
|
101
|
+
- /grill output <one or more outputs> (preference only; approval still required)
|
|
102
|
+
- /grill research off|ask|auto
|
|
103
|
+
|
|
104
|
+
Grill Me uses one thorough default Socratic style. The assistant must use the hardcoded output-selection phase before ending the interview, producing outputs, or stopping without outputs.`,display:!0});return}if($==="stop"){j.active=!1,j.phase="interview",j.outputPhase=!1,j.outputSelection=void 0,j.approvedOutputPlan=void 0,j.currentQuestion=void 0,j.alternatives=[],j.lastChangeSummary="Stopped grill session",X(),z(Q),Q.ui.notify("Grill mode stopped.","info");return}if($==="status"){J.sendMessage({customType:"grill-me-status",content:jj(j),display:!0});return}if($==="checkpoint"){await q(Q,Z);return}if($==="intent"){let D=x(Z);if(!D){Q.ui.notify(`Usage: /grill intent ${p.join("|")}`,"warning");return}j.intent=D,j.lastChangeSummary=`Intent set to ${D}`,X(),z(Q),Q.ui.notify(`Grill intent: ${D}`,"info");return}if($==="output"){if(!Z){Q.ui.notify("Usage: /grill output <one or more outputs, e.g. design-doc,issues>","warning");return}j.outputPreference=Z,j.lastChangeSummary=`Output preference set to ${Z}`,X(),z(Q),Q.ui.notify(`Grill output preference: ${Z}. This is not approval; Grill Me will still ask/confirm before producing outputs.`,"info");return}if($==="research"){let D=u(Z);if(!D){Q.ui.notify(`Usage: /grill research ${l.join("|")}`,"warning");return}j.researchMode=D,j.lastChangeSummary=`Research mode set to ${D}`,X(),z(Q),Q.ui.notify(`Grill research mode: ${D}`,"info");return}let W=Xj(Y),R={},B=x(W.flags.intent),w=u(W.flags.research);if(B)R.intent=B;if(w)R.researchMode=w;if(typeof W.flags.output==="string")R.outputPreference=W.flags.output;let G=W.rest;if(!G){let D=h(Q);if(!Q.hasUI)G=D||"Current conversation";else{let L=await Q.ui.editor("What should I grill you about?",D||"");if(!L?.trim()){Q.ui.notify("Cancelled grill start.","info");return}G=L.trim()}}F(G,Q,R)}}),J.registerCommand("deep-interview",{description:"Start a DM Deep Interview session",handler:async(V,Q)=>{let Y=V.trim()||h(Q)||"Current conversation";F(Y,Q,{researchMode:"auto"},"DM Deep Interview")}}),J.registerTool({name:"grill_update_checkpoint",label:"Update Grill Checkpoint",description:"Replace the Grill Me shared-understanding checkpoint. Use before asking the next grill question whenever meaningful understanding changes.",promptSnippet:"Persist the evolving Grill Me shared-understanding Markdown checkpoint",promptGuidelines:["Use grill_update_checkpoint before asking the next question whenever an active Grill Me session reaches a meaningful new decision, clarification, assumption, risk, or open question."],parameters:H.Object({markdown:H.String({description:"The full replacement Markdown checkpoint."}),changeSummary:H.String({description:"Brief visible summary of what changed."})}),async execute(V,Q){if(!j.active)return{content:[{type:"text",text:"No active Grill Me session. Start one with /grill <topic>."}],details:{checkpoint:j.checkpoint,changeSummary:"No active session",updatedAt:j.updatedAt}};return j.checkpoint=Q.markdown,j.lastChangeSummary=Q.changeSummary,X(),{content:[{type:"text",text:`Recorded checkpoint update: ${Q.changeSummary}`}],details:{checkpoint:j.checkpoint,changeSummary:Q.changeSummary,updatedAt:j.updatedAt}}},renderCall(V,Q){return new k(Q.fg("toolTitle",Q.bold("grill_update_checkpoint "))+Q.fg("muted",V.changeSummary??""),0,0)},renderResult(V,Q,Y){let $=V.details?.changeSummary,Z=$?`✓ ${$}`:V.content[0]?.type==="text"?V.content[0].text:"Checkpoint updated";return new k(Y.fg("success",Z),0,0)}}),J.registerTool({name:"grill_set_alternatives",label:"Set Grill Alternatives",description:"Set the visible Grill Me answer alternatives offered to the user via Tab autocomplete for the next question or readiness choice.",promptSnippet:"Present answer alternatives through the Grill Me Tab autocomplete UX",promptGuidelines:["Before asking each grill question, call grill_set_alternatives with 2-5 concise, concrete alternatives the user can accept or edit with Tab autocomplete.","Include one recommended alternative and make it clear in the label or description.","Use alternatives that are useful defaults, not exhaustive menus; the user can still type a custom answer."],parameters:H.Object({question:H.String({description:"The question these alternatives answer."}),alternatives:H.Array(H.Object({value:H.String({description:"The exact reply inserted into the user's editor when selected."}),label:H.String({description:"Short visible label for the alternative."}),description:H.Optional(H.String({description:"Brief explanation or recommendation note."}))}),{description:"2-5 suggested replies. Include a recommended/default option."})}),async execute(V,Q,Y,$,Z){if(!j.active)return{content:[{type:"text",text:"No active Grill Me session. Start one with /grill <topic>."}],details:{alternatives:[]}};if(j.currentQuestion=Q.question,j.alternatives=T(Q.alternatives),j.lastChangeSummary=`Set ${j.alternatives.length} Tab alternatives`,X(),Z)z(Z);return{content:[{type:"text",text:`Tab alternatives updated: ${j.alternatives.map((W)=>W.label).join(", ")}`}],details:{question:j.currentQuestion,alternatives:j.alternatives}}},renderCall(V,Q){return new k(Q.fg("toolTitle",Q.bold("grill_set_alternatives "))+Q.fg("muted",V.question??""),0,0)},renderResult(V,Q,Y){let $=V.details?.alternatives??[],Z=$.length?`✓ Tab alternatives: ${$.map((W)=>W.label).join(" | ")}`:"No alternatives set";return new k(Y.fg($.length?"success":"warning",Z),0,0)}}),J.registerTool({name:"grill_enter_output_selection_phase",label:"Enter Grill Output Selection",description:`Enter the mandatory hardcoded output-selection phase at the end of the Grill Me interview before stopping or producing outputs. The phase must explicitly mention available output destinations: ${f()}.`,promptSnippet:"Start the mandatory Grill Me output-selection phase",promptGuidelines:["Use grill_enter_output_selection_phase after the final checkpoint update when the Grill Me interview is ready to end.","Do not stop a Grill Me interview, claim the work is complete, or enter output production until grill_enter_output_selection_phase has been called and the user has selected what happens next.",`In the output-selection chat response, explicitly list these output destination options before asking for a choice: ${f()}.`],parameters:H.Object({readinessRationale:H.String({description:"Why shared understanding is sufficient to leave interview mode."}),recommendedOutputs:H.String({description:`One or more recommended output destinations/formats from the explicit catalog (${f()}), or 'none' if no artifact is recommended.`}),recommendedStrategy:H.String({description:"Recommended output strategy, distinct from destination/format."}),question:H.String({description:"The explicit output-selection question to ask the user. It should name concrete output options rather than saying only 'outputs'."}),alternatives:H.Array(H.Object({value:H.String({description:"The exact reply inserted into the user's editor when selected."}),label:H.String({description:"Short visible label for the alternative."}),description:H.Optional(H.String({description:"Brief explanation or recommendation note."}))}),{description:"2-5 choices covering produce output(s), continue grilling, review checkpoint, or stop with no output as appropriate."})}),async execute(V,Q,Y,$,Z){if(!j.active)return{content:[{type:"text",text:"No active Grill Me session. Start one with /grill <topic>."}],details:{phase:A(j)}};if(j.phase="output-selection",j.outputPhase=!1,j.outputSelection={readinessRationale:Q.readinessRationale,recommendedOutputs:Q.recommendedOutputs,recommendedStrategy:Q.recommendedStrategy,question:Q.question},j.approvedOutputPlan=void 0,j.currentQuestion=Q.question,j.alternatives=T(Q.alternatives),j.lastChangeSummary="Entered mandatory output-selection phase",X(),Z)z(Z);return{content:[{type:"text",text:`Output-selection phase is active. In the chat response, explicitly show these output destination options:
|
|
105
|
+
${O()}
|
|
106
|
+
|
|
107
|
+
Then ask the user to choose one or more, customize the set, continue grilling, review the checkpoint, or stop without output. Alternatives: ${j.alternatives.map((W)=>W.label).join(", ")}`}],details:{phase:A(j),outputSelection:j.outputSelection,outputDestinationOptions:g,alternatives:j.alternatives}}},renderCall(V,Q){return new k(Q.fg("toolTitle",Q.bold("grill_enter_output_selection_phase "))+Q.fg("muted",V.question??""),0,0)},renderResult(V,Q,Y){let $=V.details?.outputSelection,Z=$?`✓ Output selection: ${$.recommendedOutputs}`:V.content[0]?.type==="text"?V.content[0].text:"Output selection phase updated";return new k(Y.fg($?"success":"warning",Z),0,0)}}),J.registerTool({name:"grill_finish_output_selection_phase",label:"Finish Grill Output Selection",description:"Resolve the mandatory output-selection phase without entering output production, either by continuing the interview or stopping with no outputs.",promptSnippet:"Resolve Grill Me output selection without output production",promptGuidelines:["Use grill_finish_output_selection_phase when the user responds to the mandatory output-selection phase by choosing to continue grilling or stop without producing outputs.","If the user approves concrete output production, use grill_enter_output_phase instead."],parameters:H.Object({outcome:H.String({description:"Either 'continue-grilling' or 'stop-without-output'."}),summary:H.Optional(H.String({description:"Brief summary of the user's output-selection decision."}))}),async execute(V,Q,Y,$,Z){if(!j.active)return{content:[{type:"text",text:"No active Grill Me session."}],details:{phase:A(j),active:j.active}};if(A(j)!=="output-selection")return{content:[{type:"text",text:"No active output-selection phase. Call grill_enter_output_selection_phase before resolving output selection."}],details:{phase:A(j),active:j.active}};let W=String(Q.outcome??"").trim().toLowerCase();if(W==="continue-grilling"||W==="continue"||W==="grill"){if(j.phase="interview",j.outputPhase=!1,j.outputSelection=void 0,j.currentQuestion=void 0,j.alternatives=[],j.lastChangeSummary=Q.summary?`Output selection resolved: ${Q.summary}`:"Output selection resolved: continue grilling",X(),Z)z(Z);return{content:[{type:"text",text:"Returned to Grill Me interview mode. Ask the next Socratic question with grill_set_alternatives."}],details:{phase:A(j),active:j.active,outcome:W}}}if(W==="stop-without-output"||W==="stop"||W==="no-output"||W==="none"){if(j.active=!1,j.phase="interview",j.outputPhase=!1,j.outputSelection=void 0,j.approvedOutputPlan=void 0,j.currentQuestion=void 0,j.alternatives=[],j.lastChangeSummary=Q.summary?`Stopped after output selection: ${Q.summary}`:"Stopped after output selection without outputs",X(),Z)z(Z);return{content:[{type:"text",text:j.lastChangeSummary}],details:{phase:A(j),active:j.active,outcome:W}}}return{content:[{type:"text",text:"Unsupported outcome. Use 'continue-grilling' or 'stop-without-output'. If outputs were approved, call grill_enter_output_phase instead."}],details:{phase:A(j),active:j.active,outcome:W}}}}),J.registerTool({name:"grill_enter_output_phase",label:"Enter Grill Output Phase",description:"Mark that the user approved output production after mandatory output selection, allowing the assistant to use tools required to create the approved artifacts.",promptSnippet:"Enter approved Grill Me output-production phase",promptGuidelines:["Use grill_enter_output_phase only after grill_enter_output_selection_phase has run and the user explicitly approves a concrete output plan or preview during an active Grill Me session.","During output phase, do not refuse approved mutating output work merely because it mutates state, such as creating GitHub issues. If a tool, CLI, platform, or DM permission/authentication gate blocks the mutation, stop and ask the user for the needed permission, confirmation, credentials, or plan change; do not bypass it or broaden scope.",b],parameters:H.Object({outputPlan:H.String({description:"The approved output plan, including one or more outputs/artifacts/files/issues and intended tool use."})}),async execute(V,Q,Y,$,Z){if(!j.active)return{content:[{type:"text",text:"No active Grill Me session."}],details:{phase:A(j),outputPhase:!1,outputPlan:Q.outputPlan}};if(A(j)!=="output-selection"&&!j.outputPhase)return{content:[{type:"text",text:"Output production requires the mandatory output-selection phase first. Call grill_enter_output_selection_phase, ask the user to choose/approve outputs, then call grill_enter_output_phase."}],details:{phase:A(j),outputPhase:!1,outputPlan:Q.outputPlan}};if(j.phase="output",j.outputPhase=!0,j.approvedOutputPlan=Q.outputPlan,j.lastChangeSummary="Entered approved output phase",X(),Z)z(Z);return{content:[{type:"text",text:`Output phase enabled for approved plan:
|
|
108
|
+
${Q.outputPlan}
|
|
109
|
+
|
|
110
|
+
${b}`}],details:{phase:A(j),outputPhase:!0,outputPlan:Q.outputPlan}}}}),J.registerTool({name:"grill_finish_output_phase",label:"Finish Grill Output Phase",description:"Return an active Grill Me session to read-only interview/planning enforcement after output production.",promptSnippet:"Return Grill Me to read-only interview mode after output production",parameters:H.Object({summary:H.Optional(H.String({description:"Brief summary of outputs created."}))}),async execute(V,Q,Y,$,Z){if(j.phase="interview",j.outputPhase=!1,j.outputSelection=void 0,j.approvedOutputPlan=void 0,j.lastChangeSummary=Q.summary?`Finished output phase: ${Q.summary}`:"Finished output phase",X(),Z)z(Z);return{content:[{type:"text",text:j.lastChangeSummary}],details:{phase:A(j),outputPhase:!1,summary:Q.summary}}}}),J.on("tool_call",async(V)=>{if(!j.active||j.outputPhase)return;if(V.toolName==="edit"||V.toolName==="write")return{block:!0,reason:"Grill Me is read-only until the mandatory output-selection phase runs and the user approves a concrete output plan. Call grill_enter_output_selection_phase first, then grill_enter_output_phase before writing artifacts."};if(V.toolName==="bash"){let Q=String(V.input?.command??"");if(!Yj(Q))return{block:!0,reason:`Grill Me read-only mode blocked a potentially mutating command. Run the mandatory output-selection phase with grill_enter_output_selection_phase, get output approval, then call grill_enter_output_phase first.
|
|
111
|
+
Command: ${Q}`}}}),J.on("before_agent_start",async(V)=>{if(!j.active)return;let Q=["Use one thorough default style throughout the interview.","Be relentlessly curious but collaborative: challenge vague answers, surface contradictions, and test assumptions without changing persona.","Ask enough follow-up questions to resolve the decision tree. Prefer one more high-value question over premature readiness.","Maintain a coverage checklist and decision-branch ledger in the checkpoint; mark branches resolved, deferred, or still open as understanding evolves.","Maintain a clarity ledger for intent, outcome, scope, constraints, evidence, success criteria, decisions, and risks; use it to choose the next high-leverage question.","Route missing repo/docs facts to read-only inspection when available, and ask the user for judgments, priorities, tradeoffs, risk tolerance, taste, and decision boundaries.","Before closing the interview, run a light pressure pass over assumptions, counterexamples, failure modes, and unresolved branches.","Walk dependent branches one at a time. If an answer changes upstream assumptions, revisit affected downstream decisions before moving on.","Do not enter output selection until major objective, scope, constraints, dependencies, risks, validation, and output branches are resolved or explicitly deferred."].join(`
|
|
112
|
+
- `),Y={off:"Do not proactively inspect files or research. Ask the user instead unless they explicitly provide context.",ask:"If a question could be answered by inspecting files/code/research, ask permission before doing so.",auto:"For coding/project contexts, if a question can be answered by inspecting available files/code, inspect instead of asking. Use read-only tools during interview mode."},$=A(j),Z=$==="output"?`Approved output phase: produce only the approved outputs. If a required mutation is blocked by permissions, auth, or repo setup, ask the user instead of bypassing or faking success. ${b} When done, call grill_finish_output_phase.`:$==="output-selection"?"You are in the mandatory output-selection phase. Do not ask new interview questions unless the user chooses to continue grilling. Ask the user to choose outputs/continue/review/stop from the active output-selection alternatives. If they approve concrete output production, call grill_enter_output_phase. If they choose to continue or stop without output, call grill_finish_output_selection_phase.":"You are in read-only interview mode. Do not implement, write files, create issues, install packages, run mutating commands, or stop the Grill Me work. When ready to end the interview, first update the checkpoint if needed, then call grill_enter_output_selection_phase to enter the mandatory hardcoded output-selection phase before output production or stopping.",W=j.outputSelection?`
|
|
113
|
+
|
|
114
|
+
Active output selection:
|
|
115
|
+
- Rationale: ${j.outputSelection.readinessRationale}
|
|
116
|
+
- Recommended outputs: ${j.outputSelection.recommendedOutputs}
|
|
117
|
+
- Recommended strategy: ${j.outputSelection.recommendedStrategy}
|
|
118
|
+
- Question: ${j.outputSelection.question}`:"",R=`
|
|
119
|
+
|
|
120
|
+
[GRILL ME EXTENSION ACTIVE]
|
|
121
|
+
Topic:
|
|
122
|
+
${j.topic}
|
|
123
|
+
|
|
124
|
+
Configuration:
|
|
125
|
+
- Intent preset: ${j.intent}
|
|
126
|
+
- Grilling style: thorough default
|
|
127
|
+
- Research mode: ${j.researchMode}
|
|
128
|
+
- Output preference: ${E(j)}
|
|
129
|
+
- Phase: ${$}
|
|
130
|
+
- Output phase: ${j.outputPhase?"yes":"no"}${W}
|
|
131
|
+
|
|
132
|
+
Current checkpoint:
|
|
133
|
+
${j.checkpoint||"(No checkpoint yet.)"}
|
|
134
|
+
|
|
135
|
+
Current Tab alternatives:
|
|
136
|
+
${j.alternatives.length?j.alternatives.map((B)=>`- ${B.label}: ${B.value}${B.description?` (${B.description})`:""}`).join(`
|
|
137
|
+
`):"(None set.)"}
|
|
138
|
+
|
|
139
|
+
Behavior:
|
|
140
|
+
- Apply the Socratic method to reach shared understanding of the topic.
|
|
141
|
+
- Avoid hardcoded interview phases. Adapt the dimensions you explore to the subject and to the user's expertise.
|
|
142
|
+
- The output-selection phase is the one hardcoded terminal phase: it is mandatory before stopping the Grill Me work, stopping without outputs, or producing outputs.
|
|
143
|
+
- Treat desired outcome mode as important: learning, building, researching, content/tutorial creation, decision review, etc.
|
|
144
|
+
- Do not set or assume a default output mode for the session. A missing output preference means no output has been chosen yet, not design-doc or any other default.
|
|
145
|
+
- Treat /grill output as a preference only, not production approval. Always explicitly ask/confirm which output(s) to produce before output production.
|
|
146
|
+
- Support 1..n outputs in one approved output plan; for example, a design doc AND uploaded GitHub issues.
|
|
147
|
+
- The output-selection phase must explicitly mention concrete output destinations by name. Use this catalog and allow custom combinations:
|
|
148
|
+
${O()}
|
|
149
|
+
- Ask mostly one focused question at a time. Small grouped questions are allowed only when inseparable.
|
|
150
|
+
- Ask more than the minimum needed for a shallow summary: keep drilling until the meaningful dependency branches are resolved, contradicted, or intentionally deferred.
|
|
151
|
+
- Every grill question must present 2-5 concrete answer alternatives. Before asking the question, call grill_set_alternatives so the user can fill/cycle those alternatives with Tab and send the selected or edited reply with Enter. Also show the same alternatives briefly in chat.
|
|
152
|
+
- Include your recommended answer by default with each grill question and mark it as recommended.
|
|
153
|
+
- ${Q}
|
|
154
|
+
- ${Y[j.researchMode]}
|
|
155
|
+
- ${Z}
|
|
156
|
+
|
|
157
|
+
Checkpoint rule:
|
|
158
|
+
- The checkpoint is the source of durable shared understanding.
|
|
159
|
+
- Whenever the user's answer meaningfully changes shared understanding, call grill_update_checkpoint with a full replacement Markdown checkpoint and a concise changeSummary BEFORE asking the next grill question.
|
|
160
|
+
- The checkpoint should be adaptive Markdown. Add/remove sections as appropriate for the topic.
|
|
161
|
+
- Keep a coverage checklist and decision-branch ledger in the checkpoint when useful; update branch status as resolved, open, contradicted, or intentionally deferred.
|
|
162
|
+
- If there is no meaningful change, you may ask the next question without updating.
|
|
163
|
+
|
|
164
|
+
Readiness/output rule:
|
|
165
|
+
- When you think shared understanding is good enough, do not merely present a prompt-only readiness gate. First verify that the major coverage branches are resolved or explicitly deferred, then call grill_enter_output_selection_phase with the rationale, recommended output destination(s), recommended strategy, explicit output-selection question, and 2-5 alternatives.
|
|
166
|
+
- The mandatory output-selection phase must explicitly ask the user which output(s) to produce, even if you have a recommendation or /grill output preference. In the chat response, name the concrete options from the catalog above, including GitHub issues, design doc, README.md, ADR, PRD, implementation plan, research brief, summary/decision memo, tutorial/content outline, test plan/QA checklist, and changelog/release notes.
|
|
167
|
+
- Offer useful single-output and multi-output alternatives where appropriate, and make clear the user can choose 1..n outputs or customize the list.
|
|
168
|
+
- Output-selection alternatives should include continue grilling and/or review checkpoint when useful, and stop-without-output when producing no artifact is a reasonable choice.
|
|
169
|
+
- Output destination and strategy are separate. For example, GitHub issues can be implementation slices, tutorial chapters, research investigations, content installments, or prototype experiments.
|
|
170
|
+
- For file outputs, draft before writing. For GitHub issues, preview titles/bodies/labels before creating. For multiple outputs, preview the full set and dependencies/order before creation.
|
|
171
|
+
- Mutating output actions require explicit user approval of the concrete output set/plan, an active output-selection phase, and grill_enter_output_phase first.
|
|
172
|
+
- During approved output phase, perform only approved mutations, and do not refuse approved mutating output actions merely because they mutate state. If a permission/authentication/tool/repo setup gate blocks an approved mutation (for example gh issue create), ask the user for permission, confirmation, credentials, or a revised plan instead of bypassing or faking success. ${b}
|
|
173
|
+
- If the user chooses to continue grilling or stop without output during output selection, call grill_finish_output_selection_phase with that outcome.
|
|
174
|
+
[/GRILL ME EXTENSION ACTIVE]`;return{systemPrompt:V.systemPrompt+R}}),J.on("session_start",async(V,Q)=>{Q.ui.setEditorComponent(($,Z,W)=>new m($,Z,W,()=>j)),Q.ui.addAutocompleteProvider(($)=>Qj($,()=>j)),j=C(U);let Y=Q.sessionManager.getBranch();for(let $ of Y)if($?.type==="custom"&&$.customType===v&&$.data){if(j={...C(U),...$.data},j.outputPreference===e)j.outputPreference="";if(!j.phase)j.phase=j.outputPhase?"output":"interview";if(j.phase!=="output")j.outputPhase=!1}z(Q)})}export{Hj as default};
|
|
@@ -15,15 +15,6 @@
|
|
|
15
15
|
"planning",
|
|
16
16
|
"socratic"
|
|
17
17
|
],
|
|
18
|
-
"repository": {
|
|
19
|
-
"type": "git",
|
|
20
|
-
"url": "git+https://github.com/que-nguyen/dm.git",
|
|
21
|
-
"directory": "extensions/dm-grill-me"
|
|
22
|
-
},
|
|
23
|
-
"bugs": {
|
|
24
|
-
"url": "https://github.com/que-nguyen/dm/issues"
|
|
25
|
-
},
|
|
26
|
-
"homepage": "https://github.com/que-nguyen/dm/tree/main/extensions/dm-grill-me#readme",
|
|
27
18
|
"files": [
|
|
28
19
|
"index.ts",
|
|
29
20
|
"README.md",
|
|
@@ -31,25 +22,9 @@
|
|
|
31
22
|
"LICENSE",
|
|
32
23
|
"tsconfig.json"
|
|
33
24
|
],
|
|
34
|
-
"scripts": {
|
|
35
|
-
"typecheck": "tsc -p tsconfig.json"
|
|
36
|
-
},
|
|
37
25
|
"dm": {
|
|
38
26
|
"extensions": [
|
|
39
|
-
"./index.
|
|
27
|
+
"./index.js"
|
|
40
28
|
]
|
|
41
|
-
},
|
|
42
|
-
"dependencies": {
|
|
43
|
-
"typebox": "*"
|
|
44
|
-
},
|
|
45
|
-
"peerDependencies": {
|
|
46
|
-
"@duckmind/dm-coding-agent": "*",
|
|
47
|
-
"@duckmind/dm-tui": "*"
|
|
48
|
-
},
|
|
49
|
-
"devDependencies": {
|
|
50
|
-
"typescript": "^5.8.3",
|
|
51
|
-
"@types/node": "^22.15.3",
|
|
52
|
-
"@duckmind/dm-coding-agent": "file:../../dm-mono/packages/coding-agent",
|
|
53
|
-
"@duckmind/dm-tui": "file:../../dm-mono/packages/tui"
|
|
54
29
|
}
|
|
55
30
|
}
|
|
@@ -20,10 +20,6 @@
|
|
|
20
20
|
"ultra",
|
|
21
21
|
"codex"
|
|
22
22
|
],
|
|
23
|
-
"peerDependencies": {
|
|
24
|
-
"@sinclair/typebox": "*",
|
|
25
|
-
"@duckmind/dm-coding-agent": "*"
|
|
26
|
-
},
|
|
27
23
|
"dm": {
|
|
28
24
|
"extensions": [
|
|
29
25
|
"./index.js"
|
|
@@ -31,8 +27,5 @@
|
|
|
31
27
|
"skills": [
|
|
32
28
|
"./skills"
|
|
33
29
|
]
|
|
34
|
-
},
|
|
35
|
-
"devDependencies": {
|
|
36
|
-
"@duckmind/dm-coding-agent": "file:../../dm-mono/packages/coding-agent"
|
|
37
30
|
}
|
|
38
31
|
}
|
|
@@ -5,15 +5,6 @@
|
|
|
5
5
|
"author": "Nico Bailon",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/que-nguyen/dm.git",
|
|
11
|
-
"directory": "extensions/dm-subagents"
|
|
12
|
-
},
|
|
13
|
-
"homepage": "https://github.com/que-nguyen/dm#readme",
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://github.com/que-nguyen/dm/issues"
|
|
16
|
-
},
|
|
17
8
|
"keywords": [
|
|
18
9
|
"duckmind",
|
|
19
10
|
"dm",
|
|
@@ -33,34 +24,12 @@
|
|
|
33
24
|
"banner.png",
|
|
34
25
|
"install.mjs"
|
|
35
26
|
],
|
|
36
|
-
"scripts": {
|
|
37
|
-
"test": "npm run test:unit",
|
|
38
|
-
"test:unit": "node --experimental-strip-types --test test/unit/*.test.ts",
|
|
39
|
-
"test:integration": "node --experimental-transform-types --import ./test/support/register-loader.mjs --test test/integration/*.test.ts",
|
|
40
|
-
"test:e2e": "node --experimental-transform-types --import ./test/support/register-loader.mjs --test test/e2e/*.test.ts",
|
|
41
|
-
"test:all": "npm run test:unit && npm run test:integration && npm run test:e2e"
|
|
42
|
-
},
|
|
43
27
|
"dm": {
|
|
44
28
|
"extensions": [
|
|
45
|
-
"./src/extension/index.
|
|
29
|
+
"./src/extension/index.js"
|
|
46
30
|
],
|
|
47
31
|
"skills": [
|
|
48
32
|
"./skills"
|
|
49
33
|
]
|
|
50
|
-
},
|
|
51
|
-
"dependencies": {
|
|
52
|
-
"jiti": "2.7.0",
|
|
53
|
-
"typebox": "1.1.24"
|
|
54
|
-
},
|
|
55
|
-
"peerDependencies": {
|
|
56
|
-
"@duckmind/dm-coding-agent": "*",
|
|
57
|
-
"@duckmind/dm-agent-core": "*",
|
|
58
|
-
"@duckmind/dm-ai": "*"
|
|
59
|
-
},
|
|
60
|
-
"devDependencies": {
|
|
61
|
-
"@duckmind/dm-coding-agent": "file:../../dm-mono/packages/coding-agent",
|
|
62
|
-
"@duckmind/dm-agent-core": "file:../../dm-mono/packages/agent",
|
|
63
|
-
"@duckmind/dm-ai": "file:../../dm-mono/packages/ai",
|
|
64
|
-
"@duckmind/dm-tui": "file:../../dm-mono/packages/tui"
|
|
65
34
|
}
|
|
66
35
|
}
|