@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.
- package/CHANGELOG.md +63 -0
- package/dist/types/append-only-mode.d.ts +31 -0
- package/dist/types/capability/rule.d.ts +8 -0
- package/dist/types/cli/completion-cli.d.ts +41 -0
- package/dist/types/cli/config-cli.d.ts +1 -0
- package/dist/types/cli/fixture-report.d.ts +20 -0
- package/dist/types/cli/fixture-report.test.d.ts +1 -0
- package/dist/types/cli/nofile-limit.d.ts +11 -0
- package/dist/types/cli/notify-cli.d.ts +7 -0
- package/dist/types/cli/update-cli.d.ts +22 -0
- package/dist/types/cli.d.ts +124 -1
- package/dist/types/commands/completion.d.ts +29 -0
- package/dist/types/commands/config.d.ts +3 -0
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/file-lock.d.ts +7 -6
- package/dist/types/config/keybindings.d.ts +2 -2
- package/dist/types/config/model-profile-activation.d.ts +6 -0
- package/dist/types/config/settings-schema.d.ts +105 -1
- package/dist/types/config/settings.d.ts +8 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/export/ttsr.d.ts +14 -3
- package/dist/types/extensibility/extensions/runner.d.ts +2 -1
- package/dist/types/extensibility/extensions/types.d.ts +8 -0
- package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +39 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +17 -2
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +7 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +3 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +28 -1
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +42 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +120 -13
- package/dist/types/goals/runtime.d.ts +1 -0
- package/dist/types/hooks/native-skill-hook.d.ts +12 -0
- package/dist/types/main.d.ts +4 -1
- package/dist/types/modes/components/assistant-message.d.ts +5 -1
- package/dist/types/modes/components/model-selector.d.ts +4 -0
- package/dist/types/modes/components/queued-message-selector.d.ts +12 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/status-line.d.ts +9 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +5 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -3
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/print-mode.d.ts +13 -1
- package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -1
- package/dist/types/modes/rpc/rpc-types.d.ts +14 -0
- package/dist/types/modes/shared/agent-wire/event-contract.d.ts +19 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +23 -1
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
- package/dist/types/notifications/config.d.ts +14 -1
- package/dist/types/notifications/daemon-paths.d.ts +1 -0
- package/dist/types/notifications/index.d.ts +6 -3
- package/dist/types/notifications/lifecycle-commands.d.ts +11 -3
- package/dist/types/notifications/telegram-daemon.d.ts +23 -3
- package/dist/types/notifications/telegram-reference.d.ts +0 -5
- package/dist/types/notifications/threaded-render.d.ts +6 -0
- package/dist/types/runtime-api-key.d.ts +7 -0
- package/dist/types/sdk.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +53 -1
- package/dist/types/session/agent-storage.d.ts +1 -0
- package/dist/types/session/file-mention-pruning.d.ts +8 -0
- package/dist/types/session/messages.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +17 -1
- package/dist/types/skill-state/active-state.d.ts +18 -1
- package/dist/types/system-prompt.d.ts +18 -2
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/task/fork-context-budget.d.ts +7 -0
- package/dist/types/task/token-log.d.ts +30 -0
- package/dist/types/task/token-log.test.d.ts +1 -0
- package/dist/types/tools/bisect.d.ts +81 -0
- package/dist/types/tools/computer.d.ts +2 -2
- package/dist/types/tools/index.d.ts +1 -0
- package/dist/types/tools/search.d.ts +2 -2
- package/dist/types/utils/file-mentions.d.ts +14 -0
- package/dist/types/utils/git.d.ts +32 -0
- package/dist/types/web/scrapers/youtube.d.ts +8 -0
- package/dist/types/workflow/workflow-intent-diff.d.ts +8 -2
- package/dist/types/workflow/workflow-intent-report-consumer.d.ts +50 -0
- package/dist/types/workflow/workflow-intent-report-schema.d.ts +2 -0
- package/dist/types/workflow/workflow-intent-report.d.ts +48 -0
- package/package.json +7 -7
- package/src/append-only-mode.ts +58 -0
- package/src/autoresearch/prompt.md +1 -1
- package/src/autoresearch/tools/log-experiment.ts +1 -1
- package/src/capability/rule.ts +9 -0
- package/src/cli/completion-cli.ts +234 -0
- package/src/cli/config-cli.ts +61 -9
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/fixture-report.test.ts +230 -0
- package/src/cli/fixture-report.ts +171 -0
- package/src/cli/nofile-limit.ts +48 -0
- package/src/cli/notify-cli.ts +91 -7
- package/src/cli/update-cli.ts +85 -9
- package/src/cli.ts +29 -1
- package/src/commands/completion.ts +84 -0
- package/src/commands/config.ts +2 -0
- package/src/commands/contribution-prep.ts +1 -1
- package/src/commands/deep-interview.ts +2 -1
- package/src/config/file-lock.ts +73 -34
- package/src/config/keybindings.ts +2 -2
- package/src/config/model-profile-activation.ts +65 -0
- package/src/config/model-registry.ts +14 -2
- package/src/config/settings-schema.ts +68 -1
- package/src/config/settings.ts +22 -0
- package/src/coordinator-mcp/server.ts +34 -8
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +50 -18
- package/src/defaults/gjc/skills/ralplan/SKILL.md +40 -99
- package/src/defaults/gjc/skills/team/SKILL.md +17 -14
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +59 -4
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +30 -0
- package/src/defaults/gjc-defaults.ts +9 -0
- package/src/discovery/helpers.ts +10 -0
- package/src/discovery/index.ts +1 -0
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +60 -2
- package/src/export/ttsr.ts +96 -18
- package/src/extensibility/extensions/runner.ts +183 -219
- package/src/extensibility/extensions/types.ts +9 -0
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +156 -44
- package/src/gjc-runtime/deep-interview-ambiguity.ts +206 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +62 -8
- package/src/gjc-runtime/deep-interview-runtime.ts +210 -2
- package/src/gjc-runtime/deep-interview-state.ts +44 -2
- package/src/gjc-runtime/session-state-sidecar.ts +263 -20
- package/src/gjc-runtime/state-runtime.ts +12 -2
- package/src/gjc-runtime/state-writer.ts +15 -0
- package/src/gjc-runtime/team-runtime.ts +187 -15
- package/src/gjc-runtime/ultragoal-guard.ts +55 -66
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +315 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +1663 -159
- package/src/gjc-runtime/workflow-manifest.generated.json +113 -2
- package/src/gjc-runtime/workflow-manifest.ts +74 -1
- package/src/goals/runtime.ts +10 -2
- package/src/hindsight/backend.ts +1 -3
- package/src/hooks/native-skill-hook.ts +124 -4
- package/src/internal-urls/docs-index.generated.ts +16 -7
- package/src/main.ts +95 -43
- package/src/memories/index.ts +12 -1
- package/src/modes/components/assistant-message.ts +241 -82
- package/src/modes/components/custom-editor.ts +1 -0
- package/src/modes/components/model-selector.ts +54 -11
- package/src/modes/components/queued-message-selector.ts +92 -0
- package/src/modes/components/settings-selector.ts +4 -0
- package/src/modes/components/status-line.ts +167 -54
- package/src/modes/components/tool-execution.ts +44 -19
- package/src/modes/components/welcome.ts +160 -44
- package/src/modes/controllers/command-controller.ts +40 -4
- package/src/modes/controllers/event-controller.ts +66 -47
- package/src/modes/controllers/extension-ui-controller.ts +4 -10
- package/src/modes/controllers/input-controller.ts +180 -18
- package/src/modes/controllers/selector-controller.ts +122 -27
- package/src/modes/interactive-mode.ts +51 -16
- package/src/modes/print-mode.ts +43 -4
- package/src/modes/prompt-action-autocomplete.ts +21 -20
- package/src/modes/rpc/rpc-mode.ts +29 -3
- package/src/modes/rpc/rpc-types.ts +9 -0
- package/src/modes/shared/agent-wire/command-validation.ts +4 -0
- package/src/modes/shared/agent-wire/event-contract.ts +22 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +82 -0
- package/src/modes/shared/agent-wire/scopes.ts +1 -0
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +19 -6
- package/src/notifications/config.ts +25 -5
- package/src/notifications/daemon-paths.ts +2 -0
- package/src/notifications/index.ts +117 -14
- package/src/notifications/lifecycle-commands.ts +37 -7
- package/src/notifications/lifecycle-orchestrator.ts +19 -6
- package/src/notifications/telegram-daemon-cli.ts +2 -2
- package/src/notifications/telegram-daemon-control.ts +5 -3
- package/src/notifications/telegram-daemon.ts +302 -51
- package/src/notifications/telegram-reference.ts +0 -16
- package/src/notifications/threaded-render.ts +17 -1
- package/src/prompts/agents/architect.md +19 -10
- package/src/prompts/agents/critic.md +16 -18
- package/src/prompts/agents/executor.md +14 -11
- package/src/prompts/agents/planner.md +18 -13
- package/src/prompts/ci-green-request.md +3 -8
- package/src/prompts/goals/goal-continuation.md +0 -5
- package/src/prompts/goals/goal-mode-active.md +0 -5
- package/src/prompts/system/agent-creation-architect.md +2 -2
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/system/plan-mode-subagent.md +3 -3
- package/src/prompts/system/project-prompt.md +0 -13
- package/src/prompts/system/subagent-system-prompt.md +3 -2
- package/src/prompts/system/system-prompt.md +29 -19
- package/src/prompts/system/volatile-project-context.md +10 -0
- package/src/prompts/system/web-search.md +4 -7
- package/src/prompts/tools/apply-patch.md +6 -0
- package/src/prompts/tools/ast-edit.md +1 -0
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/bisect.md +22 -0
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/computer.md +2 -2
- package/src/prompts/tools/cron.md +0 -2
- package/src/prompts/tools/eval.md +2 -2
- package/src/prompts/tools/find.md +1 -1
- package/src/prompts/tools/github.md +6 -6
- package/src/prompts/tools/goal.md +1 -3
- package/src/prompts/tools/image-gen.md +12 -5
- package/src/prompts/tools/irc.md +5 -4
- package/src/prompts/tools/job.md +2 -2
- package/src/prompts/tools/lsp.md +1 -1
- package/src/prompts/tools/monitor.md +2 -2
- package/src/prompts/tools/patch.md +2 -2
- package/src/prompts/tools/replace.md +2 -21
- package/src/prompts/tools/rewind.md +1 -1
- package/src/prompts/tools/search-tool-bm25.md +1 -11
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/skill.md +3 -2
- package/src/prompts/tools/ssh.md +2 -1
- package/src/prompts/tools/subagent.md +2 -2
- package/src/prompts/tools/task.md +4 -5
- package/src/prompts/tools/todo-write.md +1 -1
- package/src/prompts/tools/vim.md +1 -0
- package/src/prompts/tools/web-search.md +2 -0
- package/src/prompts/tools/write.md +8 -2
- package/src/runtime-api-key.ts +16 -0
- package/src/sdk.ts +52 -28
- package/src/session/agent-session.ts +951 -132
- package/src/session/agent-storage.ts +4 -0
- package/src/session/file-mention-pruning.ts +64 -0
- package/src/session/messages.ts +4 -0
- package/src/session/session-manager.ts +103 -4
- package/src/skill-state/active-state.ts +141 -5
- package/src/skill-state/deep-interview-mutation-guard.ts +67 -3
- package/src/slash-commands/builtin-registry.ts +218 -71
- package/src/system-prompt.ts +57 -16
- package/src/task/executor.ts +132 -24
- package/src/task/fork-context-advisory.ts +2 -7
- package/src/task/fork-context-budget.ts +9 -0
- package/src/task/index.ts +13 -6
- package/src/task/output-manager.ts +20 -8
- package/src/task/receipt.ts +26 -7
- package/src/task/token-log.test.ts +188 -0
- package/src/task/token-log.ts +179 -0
- package/src/tools/bisect.ts +367 -0
- package/src/tools/computer.ts +246 -43
- package/src/tools/index.ts +3 -0
- package/src/tools/output-meta.ts +116 -4
- package/src/tools/search.ts +8 -2
- package/src/tools/skill.ts +15 -0
- package/src/tools/telegram-send.ts +6 -0
- package/src/utils/file-mentions.ts +39 -7
- package/src/utils/git.ts +73 -0
- package/src/web/scrapers/youtube.ts +24 -12
- package/src/workflow/workflow-intent-diff.ts +29 -6
- package/src/workflow/workflow-intent-report-consumer.ts +221 -0
- package/src/workflow/workflow-intent-report-schema.ts +129 -0
- 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 =
|
|
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.
|
|
159
|
-
* unknown envelope
|
|
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 = [];
|