@gajae-code/coding-agent 0.2.3 → 0.2.4
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 +17 -8600
- package/dist/types/cli/update-cli.d.ts +3 -0
- package/dist/types/config/settings-schema.d.ts +20 -0
- package/dist/types/defaults/gjc-defaults.d.ts +19 -6
- package/dist/types/modes/components/settings-selector.d.ts +4 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/theme/defaults/index.d.ts +126 -0
- package/dist/types/modes/theme/theme.d.ts +5 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/package.json +7 -7
- package/src/cli/update-cli.ts +67 -16
- package/src/config/settings-schema.ts +22 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +39 -4
- package/src/defaults/gjc/skills/deep-interview/auto-answer-uncertain.md +37 -0
- package/src/defaults/gjc/skills/deep-interview/auto-research-greenfield.md +42 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +9 -6
- package/src/defaults/gjc-defaults.ts +68 -16
- package/src/gjc-runtime/deep-interview-runtime.ts +44 -0
- package/src/gjc-runtime/state-runtime.ts +3 -2
- package/src/goals/tools/goal-tool.ts +5 -1
- package/src/internal-urls/docs-index.generated.ts +4 -2
- package/src/memories/index.ts +5 -4
- package/src/modes/components/settings-selector.ts +25 -14
- package/src/modes/controllers/command-controller.ts +1 -1
- package/src/modes/controllers/selector-controller.ts +67 -0
- package/src/modes/interactive-mode.ts +14 -1
- package/src/modes/theme/defaults/blue-crab.json +126 -0
- package/src/modes/theme/defaults/index.ts +2 -0
- package/src/modes/theme/theme.ts +40 -1
- package/src/modes/types.ts +1 -0
- package/src/prompts/memories/unavailable.md +9 -0
- package/src/sdk.ts +4 -0
- package/src/slash-commands/builtin-registry.ts +11 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Deep Interview Auto Answer: Uncertain User Opt-Out
|
|
2
|
+
|
|
3
|
+
You are a read-only architect helping the deep-interview workflow resolve one question after the user opted out, answered with uncertainty, or explicitly asked the agent to decide.
|
|
4
|
+
|
|
5
|
+
Inherited context is read-only background. Do not edit code, write files, mutate `.gjc/` state, run formatters, invoke workflow handoffs, or implement anything. Use only inherited context, the opted-out question, prior interview decisions, topology/ontology notes, confirmed constraints, and read-only repo/context inspection if available.
|
|
6
|
+
|
|
7
|
+
Keep the response compact enough to fit into ambiguity scoring.
|
|
8
|
+
|
|
9
|
+
## Task
|
|
10
|
+
|
|
11
|
+
Provide one decisive answer the parent workflow can tentatively carry forward. Choose the most conservative answer that preserves user intent, avoids irreversible assumptions, and keeps the interview moving.
|
|
12
|
+
|
|
13
|
+
## Response Shape
|
|
14
|
+
|
|
15
|
+
Respond with only this JSON object:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"status": "answered",
|
|
20
|
+
"answer": "One concise decisive answer phrased as the assumption Deep Interview should carry.",
|
|
21
|
+
"rationale": [
|
|
22
|
+
"Context or repo fact supporting the answer."
|
|
23
|
+
],
|
|
24
|
+
"confidence": "high|medium|low",
|
|
25
|
+
"uncertainty": "Explicit remaining uncertainty, or null if negligible."
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Rules:
|
|
30
|
+
- `answer` must be non-empty and must not contradict confirmed user constraints.
|
|
31
|
+
- `rationale` must contain 2-4 bullets citing inherited context, confirmed constraints, or repo facts available in the prompt.
|
|
32
|
+
- `confidence` must be `high`, `medium`, or `low`.
|
|
33
|
+
- Use `uncertainty` whenever context is thin, ambiguous, or depends on a product choice the transcript has not settled.
|
|
34
|
+
|
|
35
|
+
## Fallback
|
|
36
|
+
|
|
37
|
+
If inherited context is insufficient for a defensible decisive answer, do not guess. Return the safest reversible default if one exists, mark confidence `low`, set `uncertainty` to `Insufficient context for a reliable answer: <missing decision or evidence>`, and clearly identify what the user must confirm before execution approval.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Deep Interview Auto Research: Greenfield
|
|
2
|
+
|
|
3
|
+
You are a read-only architect helping the deep-interview workflow evaluate one greenfield question tagged `research: true`.
|
|
4
|
+
|
|
5
|
+
Inherited context is read-only background. Do not edit code, write files, mutate `.gjc/` state, run formatters, invoke workflow handoffs, or implement anything. Use only inherited context, the tagged question, prior interview decisions, topology/ontology notes, confirmed constraints, and read-only repo/context inspection if available.
|
|
6
|
+
|
|
7
|
+
Keep the response compact enough to fit back into the parent interview prompt.
|
|
8
|
+
|
|
9
|
+
## Task
|
|
10
|
+
|
|
11
|
+
Return 2-3 ranked candidate answers for the tagged greenfield question. Candidates must be concrete, mutually distinct, consistent with confirmed constraints, and useful as answer options or context for the next single Socratic question.
|
|
12
|
+
|
|
13
|
+
## Response Shape
|
|
14
|
+
|
|
15
|
+
Respond with only this JSON object:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"status": "answered",
|
|
20
|
+
"candidates": [
|
|
21
|
+
{
|
|
22
|
+
"rank": 1,
|
|
23
|
+
"answer": "Concise candidate answer.",
|
|
24
|
+
"rationale": "Why this candidate fits the inherited context and confirmed constraints.",
|
|
25
|
+
"risks_or_tradeoffs": "Main risk, tradeoff, or caveat for this candidate.",
|
|
26
|
+
"confidence": "high|medium|low"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"recommendation": "One sentence naming the strongest candidate and why it should be offered first.",
|
|
30
|
+
"follow_up_gap": "One sentence naming the remaining uncertainty the user should still confirm."
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Rules:
|
|
35
|
+
- `candidates` must contain 2 or 3 entries when context supports that many.
|
|
36
|
+
- `rank` starts at 1 and increases by 1.
|
|
37
|
+
- `confidence` must be `high`, `medium`, or `low`.
|
|
38
|
+
- Every rationale must cite inherited context, confirmed constraints, or repo facts available in the prompt.
|
|
39
|
+
|
|
40
|
+
## Fallback
|
|
41
|
+
|
|
42
|
+
If inherited context is insufficient to produce at least two meaningful candidates, say so explicitly in `follow_up_gap`, return the best single defensible candidate only if one exists, mark confidence `low`, and name the missing context. Do not fabricate certainty.
|
|
@@ -11,7 +11,7 @@ Use when the user asks for `ultragoal`, `create-goals`, `complete-goals`, durabl
|
|
|
11
11
|
|
|
12
12
|
## Purpose
|
|
13
13
|
|
|
14
|
-
`ultragoal` turns a brief into repo-native artifacts and then drives a GJC goal safely through the unified `goal` tool. New plans default to a stable pointer-style aggregate GJC goal for the whole durable plan in `.gjc/ultragoal/goals.json`, including later accepted/appended stories under the original brief constraints, while GJC tracks G001/G002 story progress in the ledger. Ultragoal does not
|
|
14
|
+
`ultragoal` turns a brief into repo-native artifacts and then drives a GJC goal safely through the unified `goal` tool. New plans default to a stable pointer-style aggregate GJC goal for the whole durable plan in `.gjc/ultragoal/goals.json`, including later accepted/appended stories under the original brief constraints, while GJC tracks G001/G002 story progress in the ledger. Ultragoal does not require any `/goal` slash-command between runs. For back-to-back ultragoal runs in one session/thread, call `goal({"op":"drop"})` only when `goal({"op":"get"})` still reports an active aggregate; then call `goal({"op":"create"})`. The goal tool stays armed across drop so the next create works in-session, and no slash-command cleanup exists or is required.
|
|
15
15
|
|
|
16
16
|
- `.gjc/ultragoal/brief.md`
|
|
17
17
|
- `.gjc/ultragoal/goals.json`
|
|
@@ -41,9 +41,12 @@ Use these exact goal-tool calls for the inline goal state:
|
|
|
41
41
|
goal({"op":"get"})
|
|
42
42
|
goal({"op":"create","objective":"<printed aggregate or per-story objective>"})
|
|
43
43
|
goal({"op":"complete"})
|
|
44
|
+
goal({"op":"drop"})
|
|
45
|
+
goal({"op":"resume"})
|
|
44
46
|
```
|
|
47
|
+
`drop` clears the active goal without exiting goal mode; `resume` reactivates a paused goal.
|
|
45
48
|
|
|
46
|
-
|
|
49
|
+
Use `goal({"op":"get"})` snapshots inside Ultragoal for ledger reconciliation. The unified `goal` tool is the only agent-facing surface for goal state; no `/goal` subcommand is required.
|
|
47
50
|
|
|
48
51
|
## Create goals
|
|
49
52
|
|
|
@@ -61,7 +64,7 @@ Loop until `gjc ultragoal status` reports all goals complete:
|
|
|
61
64
|
1. Run `gjc ultragoal complete-goals`.
|
|
62
65
|
2. Read the printed handoff.
|
|
63
66
|
3. Call `goal({"op":"get"})`.
|
|
64
|
-
4. If no active GJC goal exists, call `goal({"op":"create","objective":"<printed payload objective>"})` with the printed payload. In aggregate mode, if the same aggregate objective is already active, continue the current GJC story without creating a new GJC goal.
|
|
67
|
+
4. If no active GJC goal exists, call `goal({"op":"create","objective":"<printed payload objective>"})` with the printed payload. In aggregate mode, if the same aggregate objective is already active, continue the current GJC story without creating a new GJC goal. If `goal({"op":"get"})` shows a stale dropped goal (status `"dropped"`) and a new aggregate must start, no extra cleanup is needed — `goal({"op":"create"})` succeeds directly. If a previous aggregate is still active and you genuinely need a fresh start in the same session, call `goal({"op":"drop"})` first, then `goal({"op":"create"})`.
|
|
65
68
|
5. Complete the current GJC story only.
|
|
66
69
|
6. Run a completion audit against the story objective and real artifacts/tests.
|
|
67
70
|
7. Before any `--status complete` checkpoint, run the mandatory final cleanup/review gate below. In aggregate mode, do **not** call `goal({"op":"complete"})` for intermediate stories; checkpoint each story with a fresh `goal({"op":"get"})` snapshot whose aggregate objective is still `active`. On the final story, use the same fresh active snapshot to create the final aggregate receipt first; only after that receipt exists may `goal({"op":"complete"})` run.
|
|
@@ -204,9 +207,9 @@ The skill tool then dispatches `/skill:ralplan` or `/skill:deep-interview` same-
|
|
|
204
207
|
|
|
205
208
|
## Constraints
|
|
206
209
|
|
|
207
|
-
- The shell command
|
|
208
|
-
-
|
|
209
|
-
-
|
|
210
|
+
- The shell command emits a model-facing handoff for the active GJC agent; it does not invoke any `/goal` slash-command and the agent loop must not depend on any `/goal` subcommand.
|
|
211
|
+
- Use only the unified goal-tool surface from the agent loop: `goal({"op":"get"})`, `goal({"op":"create"})`, `goal({"op":"complete"})`, `goal({"op":"drop"})`, `goal({"op":"resume"})`. `drop` clears the active goal without exiting goal mode so the next `goal({"op":"create"})` works in-session. No slash-command cleanup exists or is required; Ultragoal never calls any `/goal` subcommand.
|
|
212
|
+
- For back-to-back ultragoal runs in the same session/thread, when `goal({"op":"get"})` still reports an active aggregate, call `goal({"op":"drop"})` before `goal({"op":"create"})`; when no active goal exists or the prior aggregate is already complete or dropped, call `goal({"op":"create"})` directly. The goal tool remains callable across drop; no slash-command cleanup exists or is required.
|
|
210
213
|
- Never call `goal({"op":"create"})` when `goal({"op":"get"})` reports a different active goal.
|
|
211
214
|
- Never call `goal({"op":"complete"})` unless the aggregate run or legacy per-story goal is actually complete.
|
|
212
215
|
- In aggregate mode, intermediate and final story checkpoints require a matching `active` GJC goal snapshot; the final story checkpoint creates the final aggregate receipt before `goal({"op":"complete"})` may reconcile the inline goal state.
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { getAgentDir, isEnoent, parseFrontmatter } from "@gajae-code/utils";
|
|
3
|
+
import autoAnswerUncertainFragment from "./gjc/skills/deep-interview/auto-answer-uncertain.md" with { type: "text" };
|
|
4
|
+
import autoResearchGreenfieldFragment from "./gjc/skills/deep-interview/auto-research-greenfield.md" with {
|
|
5
|
+
type: "text",
|
|
6
|
+
};
|
|
3
7
|
import deepInterviewSkill from "./gjc/skills/deep-interview/SKILL.md" with { type: "text" };
|
|
4
8
|
import ralplanSkill from "./gjc/skills/ralplan/SKILL.md" with { type: "text" };
|
|
5
9
|
import teamSkill from "./gjc/skills/team/SKILL.md" with { type: "text" };
|
|
@@ -7,7 +11,7 @@ import ultragoalSkill from "./gjc/skills/ultragoal/SKILL.md" with { type: "text"
|
|
|
7
11
|
|
|
8
12
|
export const DEFAULT_GJC_DEFINITION_NAMES = ["deep-interview", "ralplan", "team", "ultragoal"] as const;
|
|
9
13
|
export type DefaultGjcDefinitionName = (typeof DEFAULT_GJC_DEFINITION_NAMES)[number];
|
|
10
|
-
export type DefaultGjcDefinitionKind = "skill";
|
|
14
|
+
export type DefaultGjcDefinitionKind = "skill" | "skill-fragment";
|
|
11
15
|
export type EmbeddedDefaultGjcSkill = {
|
|
12
16
|
name: DefaultGjcDefinitionName;
|
|
13
17
|
description: string;
|
|
@@ -19,25 +23,41 @@ export type EmbeddedDefaultGjcSkill = {
|
|
|
19
23
|
};
|
|
20
24
|
export type DefaultGjcInstallStatus = "different" | "matching" | "missing" | "skipped" | "written";
|
|
21
25
|
|
|
22
|
-
export interface
|
|
23
|
-
kind:
|
|
26
|
+
export interface DefaultGjcSkillDefinition {
|
|
27
|
+
kind: "skill";
|
|
24
28
|
name: DefaultGjcDefinitionName;
|
|
25
29
|
relativePath: string;
|
|
26
30
|
content: string;
|
|
27
31
|
}
|
|
28
32
|
|
|
33
|
+
export interface DefaultGjcSkillFragmentDefinition {
|
|
34
|
+
kind: "skill-fragment";
|
|
35
|
+
parentSkillName: DefaultGjcDefinitionName;
|
|
36
|
+
relativePath: string;
|
|
37
|
+
content: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type DefaultGjcDefinition = DefaultGjcSkillDefinition | DefaultGjcSkillFragmentDefinition;
|
|
41
|
+
|
|
29
42
|
export interface InstallDefaultGjcDefinitionsOptions {
|
|
30
43
|
check?: boolean;
|
|
31
44
|
force?: boolean;
|
|
32
45
|
targetRoot?: string;
|
|
33
46
|
}
|
|
34
47
|
|
|
35
|
-
export
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
48
|
+
export type DefaultGjcDefinitionInstallFile =
|
|
49
|
+
| {
|
|
50
|
+
kind: "skill";
|
|
51
|
+
name: DefaultGjcDefinitionName;
|
|
52
|
+
path: string;
|
|
53
|
+
status: DefaultGjcInstallStatus;
|
|
54
|
+
}
|
|
55
|
+
| {
|
|
56
|
+
kind: "skill-fragment";
|
|
57
|
+
parentSkillName: DefaultGjcDefinitionName;
|
|
58
|
+
path: string;
|
|
59
|
+
status: DefaultGjcInstallStatus;
|
|
60
|
+
};
|
|
41
61
|
|
|
42
62
|
export interface DefaultGjcDefinitionInstallResult {
|
|
43
63
|
targetRoot: string;
|
|
@@ -60,6 +80,18 @@ const DEFAULT_GJC_DEFINITIONS: readonly DefaultGjcDefinition[] = [
|
|
|
60
80
|
{ kind: "skill", name: "ralplan", relativePath: "skills/ralplan/SKILL.md", content: ralplanSkill },
|
|
61
81
|
{ kind: "skill", name: "team", relativePath: "skills/team/SKILL.md", content: teamSkill },
|
|
62
82
|
{ kind: "skill", name: "ultragoal", relativePath: "skills/ultragoal/SKILL.md", content: ultragoalSkill },
|
|
83
|
+
{
|
|
84
|
+
kind: "skill-fragment",
|
|
85
|
+
parentSkillName: "deep-interview",
|
|
86
|
+
relativePath: "skill-fragments/deep-interview/auto-research-greenfield.md",
|
|
87
|
+
content: autoResearchGreenfieldFragment,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
kind: "skill-fragment",
|
|
91
|
+
parentSkillName: "deep-interview",
|
|
92
|
+
relativePath: "skill-fragments/deep-interview/auto-answer-uncertain.md",
|
|
93
|
+
content: autoAnswerUncertainFragment,
|
|
94
|
+
},
|
|
63
95
|
];
|
|
64
96
|
|
|
65
97
|
export function getDefaultGjcDefinitions(): readonly DefaultGjcDefinition[] {
|
|
@@ -70,8 +102,19 @@ export function getDefaultGjcAgentDefinitions(): readonly DefaultGjcDefinition[]
|
|
|
70
102
|
return [];
|
|
71
103
|
}
|
|
72
104
|
|
|
105
|
+
export function getEmbeddedDefaultGjcSkillFragments(
|
|
106
|
+
parentSkillName: DefaultGjcDefinitionName,
|
|
107
|
+
): DefaultGjcSkillFragmentDefinition[] {
|
|
108
|
+
return DEFAULT_GJC_DEFINITIONS.filter(
|
|
109
|
+
(definition): definition is DefaultGjcSkillFragmentDefinition =>
|
|
110
|
+
definition.kind === "skill-fragment" && definition.parentSkillName === parentSkillName,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
73
114
|
export function getEmbeddedDefaultGjcSkills(): EmbeddedDefaultGjcSkill[] {
|
|
74
|
-
return DEFAULT_GJC_DEFINITIONS.filter(
|
|
115
|
+
return DEFAULT_GJC_DEFINITIONS.filter(
|
|
116
|
+
(definition): definition is DefaultGjcSkillDefinition => definition.kind === "skill",
|
|
117
|
+
).map(definition => {
|
|
75
118
|
const { frontmatter } = parseFrontmatter(definition.content, {
|
|
76
119
|
source: `embedded:gjc/${definition.relativePath}`,
|
|
77
120
|
level: "warn",
|
|
@@ -110,12 +153,21 @@ export async function installDefaultGjcDefinitions(
|
|
|
110
153
|
status = "written";
|
|
111
154
|
}
|
|
112
155
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
156
|
+
if (definition.kind === "skill") {
|
|
157
|
+
files.push({
|
|
158
|
+
kind: definition.kind,
|
|
159
|
+
name: definition.name,
|
|
160
|
+
path: destination,
|
|
161
|
+
status,
|
|
162
|
+
});
|
|
163
|
+
} else {
|
|
164
|
+
files.push({
|
|
165
|
+
kind: definition.kind,
|
|
166
|
+
parentSkillName: definition.parentSkillName,
|
|
167
|
+
path: destination,
|
|
168
|
+
status,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
119
171
|
}
|
|
120
172
|
|
|
121
173
|
return summarizeInstallResult(targetRoot, files);
|
|
@@ -131,9 +131,17 @@ interface ResolvedDeepInterviewArgs {
|
|
|
131
131
|
thresholdSource: string;
|
|
132
132
|
sessionId?: string;
|
|
133
133
|
idea: string;
|
|
134
|
+
language?: DeepInterviewLanguagePreference;
|
|
134
135
|
json: boolean;
|
|
135
136
|
}
|
|
136
137
|
|
|
138
|
+
interface DeepInterviewLanguagePreference {
|
|
139
|
+
code: "en" | "ko";
|
|
140
|
+
label: "English" | "Korean";
|
|
141
|
+
source: "explicit-user-request" | "initial-idea";
|
|
142
|
+
instruction: string;
|
|
143
|
+
}
|
|
144
|
+
|
|
137
145
|
export interface ResolvedDeepInterviewSpecWriteArgs {
|
|
138
146
|
stage: "final";
|
|
139
147
|
slug: string;
|
|
@@ -205,6 +213,35 @@ async function resolveConfiguredAmbiguityThreshold(
|
|
|
205
213
|
return await readSettingsAmbiguityThreshold(userSettings);
|
|
206
214
|
}
|
|
207
215
|
|
|
216
|
+
function englishLanguagePreference(): DeepInterviewLanguagePreference {
|
|
217
|
+
return {
|
|
218
|
+
code: "en",
|
|
219
|
+
label: "English",
|
|
220
|
+
source: "explicit-user-request",
|
|
221
|
+
instruction:
|
|
222
|
+
"Ask every user-facing deep-interview question in English because the user explicitly requested English.",
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function resolveDeepInterviewLanguagePreference(idea: string): DeepInterviewLanguagePreference | undefined {
|
|
227
|
+
if (/\b(?:answer|ask|respond|reply|write|use|speak)\s+(?:only\s+)?in\s+English\b/i.test(idea)) {
|
|
228
|
+
return englishLanguagePreference();
|
|
229
|
+
}
|
|
230
|
+
if (/(?:영어로|영문으로|영어\s*(?:질문|답변|응답)|English\s+only)/i.test(idea)) {
|
|
231
|
+
return englishLanguagePreference();
|
|
232
|
+
}
|
|
233
|
+
if (/\p{Script=Hangul}/u.test(idea)) {
|
|
234
|
+
return {
|
|
235
|
+
code: "ko",
|
|
236
|
+
label: "Korean",
|
|
237
|
+
source: "initial-idea",
|
|
238
|
+
instruction:
|
|
239
|
+
"Ask every user-facing deep-interview question in Korean unless the user explicitly requests another language.",
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
|
|
208
245
|
function isDeepInterviewSpecWriteInvocation(args: readonly string[]): boolean {
|
|
209
246
|
return hasFlag(args, "--write");
|
|
210
247
|
}
|
|
@@ -327,6 +364,7 @@ async function resolveDeepInterviewArgs(args: readonly string[], cwd: string): P
|
|
|
327
364
|
thresholdSource,
|
|
328
365
|
sessionId,
|
|
329
366
|
idea,
|
|
367
|
+
language: resolveDeepInterviewLanguagePreference(idea),
|
|
330
368
|
json: hasFlag(args, "--json"),
|
|
331
369
|
};
|
|
332
370
|
}
|
|
@@ -405,6 +443,10 @@ async function seedDeepInterviewState(cwd: string, resolved: ResolvedDeepIntervi
|
|
|
405
443
|
},
|
|
406
444
|
updated_at: now,
|
|
407
445
|
};
|
|
446
|
+
if (resolved.language) {
|
|
447
|
+
payload.language = resolved.language;
|
|
448
|
+
(payload.state as Record<string, unknown>).language = resolved.language;
|
|
449
|
+
}
|
|
408
450
|
if (resolved.sessionId) payload.session_id = resolved.sessionId;
|
|
409
451
|
await fs.writeFile(statePath, `${JSON.stringify(payload, null, 2)}\n`);
|
|
410
452
|
return statePath;
|
|
@@ -469,6 +511,7 @@ async function handleSpecWrite(args: readonly string[], cwd: string): Promise<De
|
|
|
469
511
|
|
|
470
512
|
const handoffArgs = ["handoff", "--mode", "deep-interview", "--to", "ralplan", "--json"];
|
|
471
513
|
if (resolved.sessionId) handoffArgs.push("--session-id", resolved.sessionId);
|
|
514
|
+
else handoffArgs.push("--session-id", "");
|
|
472
515
|
const handoffResult = await runNativeStateCommand(handoffArgs, cwd);
|
|
473
516
|
if (handoffResult.status !== 0) {
|
|
474
517
|
throw new DeepInterviewCommandError(
|
|
@@ -527,6 +570,7 @@ export async function runNativeDeepInterviewCommand(
|
|
|
527
570
|
threshold: resolved.threshold,
|
|
528
571
|
threshold_source: resolved.thresholdSource,
|
|
529
572
|
idea: resolved.idea,
|
|
573
|
+
language: resolved.language,
|
|
530
574
|
state_path: statePath,
|
|
531
575
|
handoff: "Run `/skill:deep-interview` inside the GJC agent to drive the Socratic interview loop.",
|
|
532
576
|
};
|
|
@@ -171,16 +171,17 @@ async function resolveSelectors(
|
|
|
171
171
|
}
|
|
172
172
|
if (mode) assertKnownMode(mode);
|
|
173
173
|
|
|
174
|
+
const explicitSessionId = flagValue(args, "--session-id");
|
|
174
175
|
// Session-id resolution order: explicit --session-id flag, then payload
|
|
175
176
|
// session_id, then GJC_SESSION_ID env var (set by AgentSession.sdk for
|
|
176
177
|
// agent-initiated CLI invocations). The env-var default keeps shell
|
|
177
178
|
// snippets in skill docs short while still routing writes/reads to the
|
|
178
179
|
// caller's session-scoped state files.
|
|
179
|
-
let sessionId =
|
|
180
|
+
let sessionId = explicitSessionId !== undefined ? explicitSessionId.trim() || undefined : undefined;
|
|
180
181
|
if (!sessionId && payload && typeof payload.session_id === "string") {
|
|
181
182
|
sessionId = payload.session_id.trim() || undefined;
|
|
182
183
|
}
|
|
183
|
-
if (!sessionId) {
|
|
184
|
+
if (!sessionId && explicitSessionId === undefined) {
|
|
184
185
|
const envSessionId = process.env.GJC_SESSION_ID?.trim();
|
|
185
186
|
if (envSessionId) sessionId = envSessionId;
|
|
186
187
|
}
|
|
@@ -16,7 +16,11 @@ import { validateGoalObjective } from "../runtime";
|
|
|
16
16
|
import type { Goal, GoalStatus, GoalToolDetails } from "../state";
|
|
17
17
|
|
|
18
18
|
const goalSchema = z.object({
|
|
19
|
-
op: z
|
|
19
|
+
op: z
|
|
20
|
+
.enum(["create", "get", "complete", "resume", "drop"])
|
|
21
|
+
.describe(
|
|
22
|
+
"op: get | create | complete | drop | resume — drop clears the active goal without exiting goal mode (tool stays callable for the next create)",
|
|
23
|
+
),
|
|
20
24
|
objective: z.string().describe("goal objective").optional(),
|
|
21
25
|
});
|
|
22
26
|
|