@gajae-code/coding-agent 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/dist/types/append-only-mode.d.ts +31 -0
  3. package/dist/types/capability/rule.d.ts +8 -0
  4. package/dist/types/cli/completion-cli.d.ts +41 -0
  5. package/dist/types/cli/config-cli.d.ts +1 -0
  6. package/dist/types/cli/fixture-report.d.ts +20 -0
  7. package/dist/types/cli/fixture-report.test.d.ts +1 -0
  8. package/dist/types/cli/nofile-limit.d.ts +11 -0
  9. package/dist/types/cli/notify-cli.d.ts +7 -0
  10. package/dist/types/cli/update-cli.d.ts +22 -0
  11. package/dist/types/cli.d.ts +124 -1
  12. package/dist/types/commands/completion.d.ts +29 -0
  13. package/dist/types/commands/config.d.ts +3 -0
  14. package/dist/types/commands/deep-interview.d.ts +3 -0
  15. package/dist/types/config/file-lock.d.ts +7 -6
  16. package/dist/types/config/keybindings.d.ts +2 -2
  17. package/dist/types/config/model-profile-activation.d.ts +6 -0
  18. package/dist/types/config/settings-schema.d.ts +105 -1
  19. package/dist/types/config/settings.d.ts +8 -0
  20. package/dist/types/discovery/index.d.ts +1 -0
  21. package/dist/types/export/html/template.generated.d.ts +1 -1
  22. package/dist/types/export/ttsr.d.ts +14 -3
  23. package/dist/types/extensibility/extensions/runner.d.ts +2 -1
  24. package/dist/types/extensibility/extensions/types.d.ts +8 -0
  25. package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +39 -0
  26. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
  27. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -1
  28. package/dist/types/gjc-runtime/deep-interview-state.d.ts +17 -2
  29. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +7 -0
  30. package/dist/types/gjc-runtime/state-writer.d.ts +3 -0
  31. package/dist/types/gjc-runtime/team-runtime.d.ts +28 -1
  32. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +42 -0
  33. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +120 -13
  34. package/dist/types/goals/runtime.d.ts +1 -0
  35. package/dist/types/hooks/native-skill-hook.d.ts +12 -0
  36. package/dist/types/main.d.ts +4 -1
  37. package/dist/types/modes/components/assistant-message.d.ts +5 -1
  38. package/dist/types/modes/components/model-selector.d.ts +4 -0
  39. package/dist/types/modes/components/queued-message-selector.d.ts +12 -0
  40. package/dist/types/modes/components/settings-selector.d.ts +2 -0
  41. package/dist/types/modes/components/status-line.d.ts +9 -0
  42. package/dist/types/modes/controllers/command-controller.d.ts +1 -0
  43. package/dist/types/modes/controllers/event-controller.d.ts +5 -0
  44. package/dist/types/modes/controllers/input-controller.d.ts +1 -3
  45. package/dist/types/modes/interactive-mode.d.ts +2 -0
  46. package/dist/types/modes/print-mode.d.ts +13 -1
  47. package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -1
  48. package/dist/types/modes/rpc/rpc-types.d.ts +14 -0
  49. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +19 -0
  50. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +23 -1
  51. package/dist/types/modes/types.d.ts +1 -0
  52. package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
  53. package/dist/types/notifications/config.d.ts +14 -1
  54. package/dist/types/notifications/daemon-paths.d.ts +1 -0
  55. package/dist/types/notifications/index.d.ts +6 -3
  56. package/dist/types/notifications/lifecycle-commands.d.ts +11 -3
  57. package/dist/types/notifications/telegram-daemon.d.ts +23 -3
  58. package/dist/types/notifications/telegram-reference.d.ts +0 -5
  59. package/dist/types/notifications/threaded-render.d.ts +6 -0
  60. package/dist/types/runtime-api-key.d.ts +7 -0
  61. package/dist/types/sdk.d.ts +3 -0
  62. package/dist/types/session/agent-session.d.ts +53 -1
  63. package/dist/types/session/agent-storage.d.ts +1 -0
  64. package/dist/types/session/file-mention-pruning.d.ts +8 -0
  65. package/dist/types/session/messages.d.ts +4 -0
  66. package/dist/types/session/session-manager.d.ts +17 -1
  67. package/dist/types/skill-state/active-state.d.ts +18 -1
  68. package/dist/types/system-prompt.d.ts +18 -2
  69. package/dist/types/task/executor.d.ts +3 -0
  70. package/dist/types/task/fork-context-budget.d.ts +7 -0
  71. package/dist/types/task/token-log.d.ts +30 -0
  72. package/dist/types/task/token-log.test.d.ts +1 -0
  73. package/dist/types/tools/bisect.d.ts +81 -0
  74. package/dist/types/tools/computer.d.ts +2 -2
  75. package/dist/types/tools/index.d.ts +1 -0
  76. package/dist/types/tools/search.d.ts +2 -2
  77. package/dist/types/utils/file-mentions.d.ts +14 -0
  78. package/dist/types/utils/git.d.ts +32 -0
  79. package/dist/types/web/scrapers/youtube.d.ts +8 -0
  80. package/dist/types/workflow/workflow-intent-diff.d.ts +8 -2
  81. package/dist/types/workflow/workflow-intent-report-consumer.d.ts +50 -0
  82. package/dist/types/workflow/workflow-intent-report-schema.d.ts +2 -0
  83. package/dist/types/workflow/workflow-intent-report.d.ts +48 -0
  84. package/package.json +7 -7
  85. package/src/append-only-mode.ts +58 -0
  86. package/src/autoresearch/prompt.md +1 -1
  87. package/src/autoresearch/tools/log-experiment.ts +1 -1
  88. package/src/capability/rule.ts +9 -0
  89. package/src/cli/completion-cli.ts +234 -0
  90. package/src/cli/config-cli.ts +61 -9
  91. package/src/cli/fast-help.ts +1 -0
  92. package/src/cli/fixture-report.test.ts +230 -0
  93. package/src/cli/fixture-report.ts +171 -0
  94. package/src/cli/nofile-limit.ts +48 -0
  95. package/src/cli/notify-cli.ts +91 -7
  96. package/src/cli/update-cli.ts +85 -9
  97. package/src/cli.ts +29 -1
  98. package/src/commands/completion.ts +84 -0
  99. package/src/commands/config.ts +2 -0
  100. package/src/commands/contribution-prep.ts +1 -1
  101. package/src/commands/deep-interview.ts +2 -1
  102. package/src/config/file-lock.ts +73 -34
  103. package/src/config/keybindings.ts +2 -2
  104. package/src/config/model-profile-activation.ts +65 -0
  105. package/src/config/model-registry.ts +14 -2
  106. package/src/config/settings-schema.ts +68 -1
  107. package/src/config/settings.ts +22 -0
  108. package/src/coordinator-mcp/server.ts +34 -8
  109. package/src/defaults/gjc/skills/deep-interview/SKILL.md +50 -18
  110. package/src/defaults/gjc/skills/ralplan/SKILL.md +40 -99
  111. package/src/defaults/gjc/skills/team/SKILL.md +17 -14
  112. package/src/defaults/gjc/skills/ultragoal/SKILL.md +59 -4
  113. package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +30 -0
  114. package/src/defaults/gjc-defaults.ts +9 -0
  115. package/src/discovery/helpers.ts +10 -0
  116. package/src/discovery/index.ts +1 -0
  117. package/src/export/html/template.generated.ts +1 -1
  118. package/src/export/html/template.js +60 -2
  119. package/src/export/ttsr.ts +96 -18
  120. package/src/extensibility/extensions/runner.ts +183 -219
  121. package/src/extensibility/extensions/types.ts +9 -0
  122. package/src/extensibility/gjc-plugins/runtime-adapters.ts +156 -44
  123. package/src/gjc-runtime/deep-interview-ambiguity.ts +206 -0
  124. package/src/gjc-runtime/deep-interview-recorder.ts +62 -8
  125. package/src/gjc-runtime/deep-interview-runtime.ts +210 -2
  126. package/src/gjc-runtime/deep-interview-state.ts +44 -2
  127. package/src/gjc-runtime/session-state-sidecar.ts +263 -20
  128. package/src/gjc-runtime/state-runtime.ts +12 -2
  129. package/src/gjc-runtime/state-writer.ts +15 -0
  130. package/src/gjc-runtime/team-runtime.ts +187 -15
  131. package/src/gjc-runtime/ultragoal-guard.ts +55 -66
  132. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +315 -0
  133. package/src/gjc-runtime/ultragoal-runtime.ts +1663 -159
  134. package/src/gjc-runtime/workflow-manifest.generated.json +113 -2
  135. package/src/gjc-runtime/workflow-manifest.ts +74 -1
  136. package/src/goals/runtime.ts +10 -2
  137. package/src/hindsight/backend.ts +1 -3
  138. package/src/hooks/native-skill-hook.ts +124 -4
  139. package/src/internal-urls/docs-index.generated.ts +16 -7
  140. package/src/main.ts +95 -43
  141. package/src/memories/index.ts +12 -1
  142. package/src/modes/components/assistant-message.ts +241 -82
  143. package/src/modes/components/custom-editor.ts +1 -0
  144. package/src/modes/components/model-selector.ts +54 -11
  145. package/src/modes/components/queued-message-selector.ts +92 -0
  146. package/src/modes/components/settings-selector.ts +4 -0
  147. package/src/modes/components/status-line.ts +167 -54
  148. package/src/modes/components/tool-execution.ts +44 -19
  149. package/src/modes/components/welcome.ts +160 -44
  150. package/src/modes/controllers/command-controller.ts +40 -4
  151. package/src/modes/controllers/event-controller.ts +66 -47
  152. package/src/modes/controllers/extension-ui-controller.ts +4 -10
  153. package/src/modes/controllers/input-controller.ts +180 -18
  154. package/src/modes/controllers/selector-controller.ts +122 -27
  155. package/src/modes/interactive-mode.ts +51 -16
  156. package/src/modes/print-mode.ts +43 -4
  157. package/src/modes/prompt-action-autocomplete.ts +21 -20
  158. package/src/modes/rpc/rpc-mode.ts +29 -3
  159. package/src/modes/rpc/rpc-types.ts +9 -0
  160. package/src/modes/shared/agent-wire/command-validation.ts +4 -0
  161. package/src/modes/shared/agent-wire/event-contract.ts +22 -0
  162. package/src/modes/shared/agent-wire/event-envelope.ts +82 -0
  163. package/src/modes/shared/agent-wire/scopes.ts +1 -0
  164. package/src/modes/types.ts +1 -0
  165. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  166. package/src/modes/utils/ui-helpers.ts +19 -6
  167. package/src/notifications/config.ts +25 -5
  168. package/src/notifications/daemon-paths.ts +2 -0
  169. package/src/notifications/index.ts +117 -14
  170. package/src/notifications/lifecycle-commands.ts +37 -7
  171. package/src/notifications/lifecycle-orchestrator.ts +19 -6
  172. package/src/notifications/telegram-daemon-cli.ts +2 -2
  173. package/src/notifications/telegram-daemon-control.ts +5 -3
  174. package/src/notifications/telegram-daemon.ts +302 -51
  175. package/src/notifications/telegram-reference.ts +0 -16
  176. package/src/notifications/threaded-render.ts +17 -1
  177. package/src/prompts/agents/architect.md +19 -10
  178. package/src/prompts/agents/critic.md +16 -18
  179. package/src/prompts/agents/executor.md +14 -11
  180. package/src/prompts/agents/planner.md +18 -13
  181. package/src/prompts/ci-green-request.md +3 -8
  182. package/src/prompts/goals/goal-continuation.md +0 -5
  183. package/src/prompts/goals/goal-mode-active.md +0 -5
  184. package/src/prompts/system/agent-creation-architect.md +2 -2
  185. package/src/prompts/system/plan-mode-active.md +1 -1
  186. package/src/prompts/system/plan-mode-subagent.md +3 -3
  187. package/src/prompts/system/project-prompt.md +0 -13
  188. package/src/prompts/system/subagent-system-prompt.md +3 -2
  189. package/src/prompts/system/system-prompt.md +29 -19
  190. package/src/prompts/system/volatile-project-context.md +10 -0
  191. package/src/prompts/system/web-search.md +4 -7
  192. package/src/prompts/tools/apply-patch.md +6 -0
  193. package/src/prompts/tools/ast-edit.md +1 -0
  194. package/src/prompts/tools/bash.md +1 -1
  195. package/src/prompts/tools/bisect.md +22 -0
  196. package/src/prompts/tools/browser.md +1 -1
  197. package/src/prompts/tools/computer.md +2 -2
  198. package/src/prompts/tools/cron.md +0 -2
  199. package/src/prompts/tools/eval.md +2 -2
  200. package/src/prompts/tools/find.md +1 -1
  201. package/src/prompts/tools/github.md +6 -6
  202. package/src/prompts/tools/goal.md +1 -3
  203. package/src/prompts/tools/image-gen.md +12 -5
  204. package/src/prompts/tools/irc.md +5 -4
  205. package/src/prompts/tools/job.md +2 -2
  206. package/src/prompts/tools/lsp.md +1 -1
  207. package/src/prompts/tools/monitor.md +2 -2
  208. package/src/prompts/tools/patch.md +2 -2
  209. package/src/prompts/tools/replace.md +2 -21
  210. package/src/prompts/tools/rewind.md +1 -1
  211. package/src/prompts/tools/search-tool-bm25.md +1 -11
  212. package/src/prompts/tools/search.md +1 -1
  213. package/src/prompts/tools/skill.md +3 -2
  214. package/src/prompts/tools/ssh.md +2 -1
  215. package/src/prompts/tools/subagent.md +2 -2
  216. package/src/prompts/tools/task.md +4 -5
  217. package/src/prompts/tools/todo-write.md +1 -1
  218. package/src/prompts/tools/vim.md +1 -0
  219. package/src/prompts/tools/web-search.md +2 -0
  220. package/src/prompts/tools/write.md +8 -2
  221. package/src/runtime-api-key.ts +16 -0
  222. package/src/sdk.ts +52 -28
  223. package/src/session/agent-session.ts +951 -132
  224. package/src/session/agent-storage.ts +4 -0
  225. package/src/session/file-mention-pruning.ts +64 -0
  226. package/src/session/messages.ts +4 -0
  227. package/src/session/session-manager.ts +103 -4
  228. package/src/skill-state/active-state.ts +141 -5
  229. package/src/skill-state/deep-interview-mutation-guard.ts +67 -3
  230. package/src/slash-commands/builtin-registry.ts +218 -71
  231. package/src/system-prompt.ts +57 -16
  232. package/src/task/executor.ts +132 -24
  233. package/src/task/fork-context-advisory.ts +2 -7
  234. package/src/task/fork-context-budget.ts +9 -0
  235. package/src/task/index.ts +13 -6
  236. package/src/task/output-manager.ts +20 -8
  237. package/src/task/receipt.ts +26 -7
  238. package/src/task/token-log.test.ts +188 -0
  239. package/src/task/token-log.ts +179 -0
  240. package/src/tools/bisect.ts +367 -0
  241. package/src/tools/computer.ts +246 -43
  242. package/src/tools/index.ts +3 -0
  243. package/src/tools/output-meta.ts +116 -4
  244. package/src/tools/search.ts +8 -2
  245. package/src/tools/skill.ts +15 -0
  246. package/src/tools/telegram-send.ts +6 -0
  247. package/src/utils/file-mentions.ts +39 -7
  248. package/src/utils/git.ts +73 -0
  249. package/src/web/scrapers/youtube.ts +24 -12
  250. package/src/workflow/workflow-intent-diff.ts +29 -6
  251. package/src/workflow/workflow-intent-report-consumer.ts +221 -0
  252. package/src/workflow/workflow-intent-report-schema.ts +129 -0
  253. package/src/workflow/workflow-intent-report.ts +135 -0
@@ -2,6 +2,7 @@ import { createHash, randomBytes } from "node:crypto";
2
2
  import * as fs from "node:fs/promises";
3
3
  import * as os from "node:os";
4
4
  import * as path from "node:path";
5
+ import { YAML } from "bun";
5
6
  import { syncSkillActiveState } from "../skill-state/active-state";
6
7
  import { deriveDeepInterviewHud } from "../skill-state/workflow-hud";
7
8
  import { WORKFLOW_STATE_VERSION } from "../skill-state/workflow-state-contract";
@@ -19,7 +20,7 @@ export * from "./deep-interview-recorder";
19
20
  *
20
21
  * The CLI itself does not run the Socratic interview; that lives inside the `/skill:deep-interview`
21
22
  * skill executed by the agent. This handler validates the documented argument-hint surface
22
- * (`[--quick|--standard|--deep] <idea>`), seeds `.gjc/state/deep-interview-state.json`, and
23
+ * (`[--trace] [--quick|--standard|--deep] <idea>`), seeds `.gjc/state/deep-interview-state.json`, and
23
24
  * updates the shared HUD rail via `syncSkillActiveState` so the active interview is visible to
24
25
  * the TUI.
25
26
  */
@@ -40,6 +41,68 @@ const RESOLUTION_THRESHOLDS = {
40
41
  deep: 0.35,
41
42
  } as const;
42
43
 
44
+ const TRACE_MAX_RELEVANT_PATHS = 12;
45
+ const TRACE_MAX_PACKAGE_HINTS = 8;
46
+ const TRACE_MAX_DIRECTORY_VISITS = 1200;
47
+ const TRACE_MAX_ENTRY_VISITS = 5000;
48
+ const TRACE_MAX_PENDING_DIRECTORIES = 1200;
49
+ const TRACE_SKIP_DIRS = new Set([
50
+ ".git",
51
+ ".gjc",
52
+ "node_modules",
53
+ "dist",
54
+ "build",
55
+ "coverage",
56
+ ".next",
57
+ ".turbo",
58
+ ".cache",
59
+ "vendor",
60
+ "target",
61
+ ".venv",
62
+ "venv",
63
+ "__pycache__",
64
+ ".pytest_cache",
65
+ "tmp",
66
+ "temp",
67
+ "logs",
68
+ "out",
69
+ ]);
70
+ const TRACE_SOURCE_EXTENSIONS = new Set([
71
+ ".ts",
72
+ ".tsx",
73
+ ".js",
74
+ ".jsx",
75
+ ".mts",
76
+ ".cts",
77
+ ".py",
78
+ ".rs",
79
+ ".go",
80
+ ".java",
81
+ ".kt",
82
+ ".swift",
83
+ ".md",
84
+ ".json",
85
+ ".yml",
86
+ ".yaml",
87
+ ]);
88
+
89
+ interface DeepInterviewTraceSummary {
90
+ enabled: true;
91
+ generated_at: string;
92
+ bounded: true;
93
+ limits: {
94
+ max_relevant_paths: number;
95
+ max_package_hints: number;
96
+ max_directory_visits: number;
97
+ max_entry_visits: number;
98
+ max_pending_directories: number;
99
+ };
100
+ idea_terms: string[];
101
+ project_hints: string[];
102
+ relevant_paths: Array<{ path: string; reason: string }>;
103
+ findings: string[];
104
+ }
105
+
43
106
  type DeepInterviewResolution = keyof typeof RESOLUTION_THRESHOLDS;
44
107
 
45
108
  class DeepInterviewCommandError extends Error {
@@ -107,6 +170,134 @@ async function resolveSpecContent(rawSpec: string, cwd: string): Promise<string>
107
170
  return rawSpec;
108
171
  }
109
172
 
173
+ function traceTerms(idea: string): string[] {
174
+ const terms = new Set<string>();
175
+ for (const match of idea.toLowerCase().matchAll(/[a-z0-9][a-z0-9_-]{2,}/g)) {
176
+ const value = match[0];
177
+ if (["the", "and", "for", "with", "that", "this", "from", "into", "should", "would"].includes(value)) continue;
178
+ terms.add(value);
179
+ if (terms.size >= 12) break;
180
+ }
181
+ return [...terms];
182
+ }
183
+
184
+ function relativePathReason(relativePath: string, terms: readonly string[]): string | undefined {
185
+ const normalized = relativePath.toLowerCase();
186
+ const matched = terms.find(term => normalized.includes(term));
187
+ if (matched) return `path matches idea term "${matched}"`;
188
+ if (/deep[-_]?interview/i.test(relativePath)) return "path matches deep-interview workflow surface";
189
+ if (/skill|workflow|runtime|state/i.test(relativePath)) return "path matches workflow/runtime surface";
190
+ return undefined;
191
+ }
192
+
193
+ async function readPackageHints(cwd: string): Promise<string[]> {
194
+ const packagePath = path.join(cwd, "package.json");
195
+ let parsed: unknown;
196
+ try {
197
+ parsed = JSON.parse(await fs.readFile(packagePath, "utf-8"));
198
+ } catch {
199
+ return [];
200
+ }
201
+ const manifest = parsed as {
202
+ name?: unknown;
203
+ workspaces?: unknown;
204
+ scripts?: Record<string, unknown>;
205
+ dependencies?: Record<string, unknown>;
206
+ devDependencies?: Record<string, unknown>;
207
+ };
208
+ const hints: string[] = [];
209
+ if (typeof manifest.name === "string") hints.push(`package: ${manifest.name}`);
210
+ if (manifest.workspaces) hints.push("workspace: package.json declares workspaces");
211
+ const scripts = Object.keys(manifest.scripts ?? {}).slice(0, TRACE_MAX_PACKAGE_HINTS);
212
+ if (scripts.length > 0) hints.push(`scripts: ${scripts.join(", ")}`);
213
+ const deps = [...Object.keys(manifest.dependencies ?? {}), ...Object.keys(manifest.devDependencies ?? {})]
214
+ .filter(name => /typescript|bun|react|vite|zod|winston|commander|oclif/i.test(name))
215
+ .slice(0, TRACE_MAX_PACKAGE_HINTS);
216
+ if (deps.length > 0) hints.push(`notable dependencies: ${deps.join(", ")}`);
217
+ return hints.slice(0, TRACE_MAX_PACKAGE_HINTS);
218
+ }
219
+
220
+ async function collectRelevantTracePaths(
221
+ cwd: string,
222
+ terms: readonly string[],
223
+ ): Promise<Array<{ path: string; reason: string }>> {
224
+ const results: Array<{ path: string; reason: string; score: number }> = [];
225
+ const pending: Array<{ absolutePath: string; depth: number }> = [{ absolutePath: cwd, depth: 0 }];
226
+ let visitedDirectories = 0;
227
+ let visitedEntries = 0;
228
+ while (
229
+ pending.length > 0 &&
230
+ visitedDirectories < TRACE_MAX_DIRECTORY_VISITS &&
231
+ visitedEntries < TRACE_MAX_ENTRY_VISITS
232
+ ) {
233
+ const current = pending.shift();
234
+ if (!current) break;
235
+ visitedDirectories += 1;
236
+ try {
237
+ const directory = await fs.opendir(current.absolutePath);
238
+ for await (const entry of directory) {
239
+ visitedEntries += 1;
240
+ if (visitedEntries > TRACE_MAX_ENTRY_VISITS) break;
241
+ if (TRACE_SKIP_DIRS.has(entry.name)) continue;
242
+ const absolutePath = path.join(current.absolutePath, entry.name);
243
+ const relativePath = path.relative(cwd, absolutePath).split(path.sep).join("/");
244
+ if (entry.isDirectory()) {
245
+ if (current.depth < 6 && pending.length < TRACE_MAX_PENDING_DIRECTORIES) {
246
+ pending.push({ absolutePath, depth: current.depth + 1 });
247
+ }
248
+ continue;
249
+ }
250
+ if (!entry.isFile() || !TRACE_SOURCE_EXTENSIONS.has(path.extname(entry.name))) continue;
251
+ const reason = relativePathReason(relativePath, terms);
252
+ if (!reason) continue;
253
+ const termScore = terms.reduce(
254
+ (score, term) => score + (relativePath.toLowerCase().includes(term) ? 2 : 0),
255
+ 0,
256
+ );
257
+ const surfaceScore = /deep[-_]?interview|skill|workflow|runtime|state/i.test(relativePath) ? 1 : 0;
258
+ results.push({ path: relativePath, reason, score: termScore + surfaceScore });
259
+ }
260
+ } catch {}
261
+ }
262
+ return results
263
+ .sort((a, b) => b.score - a.score || a.path.localeCompare(b.path))
264
+ .slice(0, TRACE_MAX_RELEVANT_PATHS)
265
+ .map(({ path: relativePath, reason }) => ({ path: relativePath, reason }));
266
+ }
267
+
268
+ async function buildDeepInterviewTraceSummary(cwd: string, idea: string): Promise<DeepInterviewTraceSummary> {
269
+ const terms = traceTerms(idea);
270
+ const [projectHints, relevantPaths] = await Promise.all([
271
+ readPackageHints(cwd),
272
+ collectRelevantTracePaths(cwd, terms),
273
+ ]);
274
+ const findings = [
275
+ projectHints.length > 0
276
+ ? "Project manifest was summarized into bounded package/script/dependency hints."
277
+ : "No readable package.json manifest was found at the project root.",
278
+ relevantPaths.length > 0
279
+ ? `Relevant path scan captured ${relevantPaths.length} bounded path hint(s) before interview questions.`
280
+ : "Relevant path scan found no matching source/documentation paths before interview questions.",
281
+ "Trace summary intentionally stores path-level evidence only; raw files and logs are excluded.",
282
+ ];
283
+ return {
284
+ enabled: true,
285
+ generated_at: new Date().toISOString(),
286
+ bounded: true,
287
+ limits: {
288
+ max_relevant_paths: TRACE_MAX_RELEVANT_PATHS,
289
+ max_package_hints: TRACE_MAX_PACKAGE_HINTS,
290
+ max_directory_visits: TRACE_MAX_DIRECTORY_VISITS,
291
+ max_entry_visits: TRACE_MAX_ENTRY_VISITS,
292
+ max_pending_directories: TRACE_MAX_PENDING_DIRECTORIES,
293
+ },
294
+ idea_terms: terms,
295
+ project_hints: projectHints,
296
+ relevant_paths: relevantPaths,
297
+ findings,
298
+ };
299
+ }
300
+
110
301
  interface ResolvedDeepInterviewArgs {
111
302
  resolution: DeepInterviewResolution;
112
303
  threshold: number;
@@ -114,6 +305,7 @@ interface ResolvedDeepInterviewArgs {
114
305
  sessionId: string;
115
306
  idea: string;
116
307
  language?: DeepInterviewLanguagePreference;
308
+ trace?: DeepInterviewTraceSummary;
117
309
  json: boolean;
118
310
  }
119
311
 
@@ -199,7 +391,7 @@ async function readModernSettingsAmbiguityThreshold(): Promise<{ threshold: numb
199
391
  const modernConfigPath = modernSettingsPath();
200
392
  let parsed: unknown;
201
393
  try {
202
- parsed = (await import("bun")).YAML.parse(await fs.readFile(modernConfigPath, "utf-8"));
394
+ parsed = YAML.parse(await fs.readFile(modernConfigPath, "utf-8"));
203
395
  } catch {
204
396
  return undefined;
205
397
  }
@@ -371,6 +563,7 @@ async function resolveDeepInterviewArgs(args: readonly string[], cwd: string): P
371
563
  skipNext = true;
372
564
  continue;
373
565
  }
566
+ if (arg === "--trace") continue;
374
567
  if (arg === "--quick" || arg === "--standard" || arg === "--deep" || arg === "--json") continue;
375
568
  if (arg.startsWith("-")) {
376
569
  throw new DeepInterviewCommandError(2, `unknown flag for gjc deep-interview: ${arg}`);
@@ -379,6 +572,7 @@ async function resolveDeepInterviewArgs(args: readonly string[], cwd: string): P
379
572
  }
380
573
  const idea = ideaParts.join(" ").trim();
381
574
  const effectiveResolution: DeepInterviewResolution = resolution ?? "standard";
575
+ const trace = hasFlag(args, "--trace") && idea ? await buildDeepInterviewTraceSummary(cwd, idea) : undefined;
382
576
  return {
383
577
  resolution: effectiveResolution,
384
578
  threshold,
@@ -386,6 +580,7 @@ async function resolveDeepInterviewArgs(args: readonly string[], cwd: string): P
386
580
  sessionId,
387
581
  idea,
388
582
  language: resolveDeepInterviewLanguagePreference(idea),
583
+ trace,
389
584
  json: hasFlag(args, "--json"),
390
585
  };
391
586
  }
@@ -507,6 +702,17 @@ async function seedDeepInterviewState(cwd: string, resolved: ResolvedDeepIntervi
507
702
  },
508
703
  updated_at: now,
509
704
  };
705
+ if (resolved.trace) {
706
+ payload.trace = resolved.trace;
707
+ (payload.state as Record<string, unknown>).trace = resolved.trace;
708
+ (payload.state as Record<string, unknown>).trace_summary = resolved.trace;
709
+ (payload.state as Record<string, unknown>).codebase_context = {
710
+ source: "trace",
711
+ summary: resolved.trace.findings,
712
+ relevant_paths: resolved.trace.relevant_paths,
713
+ project_hints: resolved.trace.project_hints,
714
+ };
715
+ }
510
716
  if (resolved.language) {
511
717
  payload.language = resolved.language;
512
718
  (payload.state as Record<string, unknown>).language = resolved.language;
@@ -646,6 +852,7 @@ export async function runNativeDeepInterviewCommand(
646
852
  threshold_source: resolved.thresholdSource,
647
853
  idea: resolved.idea,
648
854
  language: resolved.language,
855
+ trace: resolved.trace,
649
856
  state_path: statePath,
650
857
  handoff: "/skill:deep-interview",
651
858
  };
@@ -654,6 +861,7 @@ export async function runNativeDeepInterviewCommand(
654
861
  : [
655
862
  `deep-interview seed state_path=${statePath}`,
656
863
  `resolution=${resolved.resolution} threshold=${resolved.threshold} threshold_source=${resolved.thresholdSource}`,
864
+ resolved.trace ? `trace=enabled bounded_paths=${resolved.trace.relevant_paths.length}` : undefined,
657
865
  "handoff=/skill:deep-interview",
658
866
  "",
659
867
  ].join("\n");
@@ -31,6 +31,13 @@ export interface DeepInterviewEstablishedFact {
31
31
  dimension?: string;
32
32
  evidence?: string;
33
33
  disputed: boolean;
34
+ /**
35
+ * Resolution pointer for a disputed fact: the id of the fact that replaced it
36
+ * after the user confirmed a pivot. A disputed fact without `superseded_by`
37
+ * keeps the deterministic ambiguity floor elevated; setting it releases the
38
+ * pressure while preserving the contradicted fact for audit.
39
+ */
40
+ superseded_by?: string;
34
41
  }
35
42
 
36
43
  export interface DeepInterviewTriggerMetadata {
@@ -66,7 +73,12 @@ export interface DeepInterviewRoundRecord {
66
73
  answered_at: string;
67
74
  scored_at?: string;
68
75
  scores?: Record<string, number>;
76
+ /** Effective ambiguity after the deterministic floor clamp (`max(reported, floor)`). */
69
77
  ambiguity?: number;
78
+ /** Original LLM-reported ambiguity, preserved for audit when the floor clamped it. */
79
+ reported_ambiguity?: number;
80
+ /** Deterministic floor in effect when this round was scored, when it clamped. */
81
+ ambiguity_floor?: number;
70
82
  triggers?: DeepInterviewTriggerMetadata[];
71
83
  }
72
84
 
@@ -125,6 +137,7 @@ const TRANSCRIPT_STATE_FIELDS = [
125
137
  "rounds",
126
138
  "established_facts",
127
139
  "current_ambiguity",
140
+ "ambiguity_floor",
128
141
  "topology",
129
142
  "ontology_snapshots",
130
143
  "auto_researched_rounds",
@@ -150,13 +163,39 @@ const HOISTED_STATE_FIELDS = [
150
163
  "threshold_source",
151
164
  ] as const;
152
165
 
166
+ /**
167
+ * Envelope-reserved keys that are never legitimate interview `state` fields.
168
+ *
169
+ * A malformed write that wraps a whole envelope under `state`
170
+ * (`gjc state deep-interview write --input '{"state": <envelope>}'`) leaks these
171
+ * into the nested state. Because normalization otherwise preserves unknown
172
+ * nested fields, they would accrete a recursive `state.state` chain (plus stale
173
+ * `receipt`/`skill`/`version`/... duplicates) that no later merge or write ever
174
+ * removes, permanently corrupting the shape. They are stripped from `state` on
175
+ * normalize so the canonical envelope self-heals on the next write.
176
+ */
177
+ const ENVELOPE_RESERVED_STATE_KEYS = [
178
+ "state",
179
+ "receipt",
180
+ "skill",
181
+ "version",
182
+ "updated_at",
183
+ "active",
184
+ "current_phase",
185
+ "state_revision",
186
+ "session_id",
187
+ ] as const;
188
+
153
189
  /**
154
190
  * Canonicalize a deep-interview envelope: interview data nested under `state`,
155
191
  * legacy flattened fields hoisted in losslessly, transcript duplicates removed
156
192
  * from the top level, and `rounds`/`established_facts` guaranteed to be arrays.
157
193
  *
158
- * Idempotent: a canonical envelope is returned unchanged in shape. Never deletes
159
- * unknown envelope or nested fields, and never mutates the input.
194
+ * Idempotent: a canonical envelope is returned unchanged in shape. Preserves all
195
+ * unknown envelope and nested fields except the envelope-reserved keys that leak
196
+ * into `state` (see `ENVELOPE_RESERVED_STATE_KEYS`), which are stripped so a
197
+ * malformed envelope-in-state write cannot permanently nest state. Never mutates
198
+ * the input.
160
199
  */
161
200
  export function normalizeDeepInterviewEnvelope(value: unknown): DeepInterviewStateEnvelope {
162
201
  const envelope: DeepInterviewStateEnvelope = isPlainObject(value) ? { ...value } : {};
@@ -169,6 +208,9 @@ export function normalizeDeepInterviewEnvelope(value: unknown): DeepInterviewSta
169
208
  for (const field of HOISTED_STATE_FIELDS) {
170
209
  if (inner[field] === undefined && envelope[field] !== undefined) inner[field] = envelope[field];
171
210
  }
211
+ for (const field of ENVELOPE_RESERVED_STATE_KEYS) {
212
+ if (field in inner) delete inner[field];
213
+ }
172
214
 
173
215
  if (!Array.isArray(inner.rounds)) inner.rounds = [];
174
216
  if (!Array.isArray(inner.established_facts)) inner.established_facts = [];