@gajae-code/coding-agent 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/CHANGELOG.md +59 -1
  2. package/dist/types/cli/setup-cli.d.ts +1 -0
  3. package/dist/types/commands/contribution-prep.d.ts +18 -0
  4. package/dist/types/commands/deep-interview.d.ts +41 -0
  5. package/dist/types/commands/session.d.ts +24 -0
  6. package/dist/types/commands/setup.d.ts +3 -0
  7. package/dist/types/config/model-registry.d.ts +2 -2
  8. package/dist/types/config/models-config-schema.d.ts +17 -9
  9. package/dist/types/config/settings-schema.d.ts +37 -24
  10. package/dist/types/discovery/helpers.d.ts +2 -0
  11. package/dist/types/extensibility/extensions/types.d.ts +6 -0
  12. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +33 -0
  13. package/dist/types/gjc-runtime/goal-mode-request.d.ts +1 -1
  14. package/dist/types/gjc-runtime/launch-tmux.d.ts +12 -11
  15. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +25 -0
  16. package/dist/types/gjc-runtime/state-runtime.d.ts +13 -0
  17. package/dist/types/gjc-runtime/team-runtime.d.ts +37 -5
  18. package/dist/types/gjc-runtime/tmux-common.d.ts +41 -0
  19. package/dist/types/gjc-runtime/tmux-sessions.d.ts +17 -0
  20. package/dist/types/goals/runtime.d.ts +3 -9
  21. package/dist/types/goals/state.d.ts +3 -6
  22. package/dist/types/goals/tools/goal-tool.d.ts +1 -69
  23. package/dist/types/hooks/skill-state.d.ts +5 -0
  24. package/dist/types/memories/index.d.ts +1 -1
  25. package/dist/types/memory-backend/local-backend.d.ts +3 -3
  26. package/dist/types/modes/components/hook-selector.d.ts +7 -0
  27. package/dist/types/modes/components/settings-selector.d.ts +0 -2
  28. package/dist/types/modes/components/status-line/types.d.ts +0 -3
  29. package/dist/types/modes/components/status-line.d.ts +0 -3
  30. package/dist/types/modes/controllers/command-controller.d.ts +1 -0
  31. package/dist/types/modes/interactive-mode.d.ts +1 -12
  32. package/dist/types/modes/theme/defaults/index.d.ts +0 -2
  33. package/dist/types/modes/theme/theme.d.ts +1 -2
  34. package/dist/types/modes/types.d.ts +1 -7
  35. package/dist/types/modes/utils/context-usage.d.ts +6 -2
  36. package/dist/types/sdk.d.ts +6 -2
  37. package/dist/types/session/agent-session.d.ts +47 -1
  38. package/dist/types/session/contribution-prep.d.ts +47 -0
  39. package/dist/types/session/session-manager.d.ts +3 -0
  40. package/dist/types/setup/model-onboarding-guidance.d.ts +1 -0
  41. package/dist/types/setup/provider-onboarding.d.ts +29 -5
  42. package/dist/types/skill-state/active-state.d.ts +30 -1
  43. package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +6 -1
  44. package/dist/types/skill-state/initial-phase.d.ts +12 -0
  45. package/dist/types/skill-state/workflow-hud.d.ts +9 -4
  46. package/dist/types/skill-state/workflow-state-contract.d.ts +34 -0
  47. package/dist/types/task/executor.d.ts +2 -0
  48. package/dist/types/task/types.d.ts +11 -0
  49. package/dist/types/tools/index.d.ts +20 -1
  50. package/dist/types/tools/skill.d.ts +47 -0
  51. package/dist/types/utils/changelog.d.ts +18 -2
  52. package/package.json +7 -7
  53. package/src/cli/args.ts +3 -2
  54. package/src/cli/setup-cli.ts +26 -12
  55. package/src/cli.ts +7 -1
  56. package/src/commands/contribution-prep.ts +41 -0
  57. package/src/commands/deep-interview.ts +30 -23
  58. package/src/commands/launch.ts +10 -1
  59. package/src/commands/ralplan.ts +10 -22
  60. package/src/commands/session.ts +150 -0
  61. package/src/commands/setup.ts +2 -0
  62. package/src/commands/state.ts +15 -4
  63. package/src/commands/team.ts +23 -3
  64. package/src/config/model-registry.ts +10 -2
  65. package/src/config/models-config-schema.ts +120 -102
  66. package/src/config/settings-schema.ts +42 -25
  67. package/src/config.ts +1 -1
  68. package/src/defaults/gjc/skills/deep-interview/SKILL.md +32 -13
  69. package/src/defaults/gjc/skills/ralplan/SKILL.md +22 -2
  70. package/src/defaults/gjc/skills/team/SKILL.md +39 -7
  71. package/src/defaults/gjc/skills/ultragoal/SKILL.md +33 -25
  72. package/src/discovery/helpers.ts +24 -1
  73. package/src/eval/py/prelude.py +1 -1
  74. package/src/extensibility/extensions/types.ts +6 -0
  75. package/src/gjc-runtime/deep-interview-runtime.ts +546 -0
  76. package/src/gjc-runtime/goal-mode-request.ts +2 -19
  77. package/src/gjc-runtime/launch-tmux.ts +83 -43
  78. package/src/gjc-runtime/ralplan-runtime.ts +460 -0
  79. package/src/gjc-runtime/state-runtime.ts +731 -0
  80. package/src/gjc-runtime/team-runtime.ts +708 -52
  81. package/src/gjc-runtime/tmux-common.ts +119 -0
  82. package/src/gjc-runtime/tmux-sessions.ts +165 -0
  83. package/src/gjc-runtime/ultragoal-guard.ts +6 -3
  84. package/src/gjc-runtime/ultragoal-runtime.ts +5 -4
  85. package/src/goals/runtime.ts +38 -144
  86. package/src/goals/state.ts +36 -7
  87. package/src/goals/tools/goal-tool.ts +15 -172
  88. package/src/hooks/skill-state.ts +39 -18
  89. package/src/internal-urls/docs-index.generated.ts +5 -4
  90. package/src/internal-urls/memory-protocol.ts +3 -2
  91. package/src/main.ts +2 -3
  92. package/src/memories/index.ts +2 -1
  93. package/src/memory-backend/local-backend.ts +14 -6
  94. package/src/modes/components/hook-selector.ts +156 -1
  95. package/src/modes/components/settings-selector.ts +5 -12
  96. package/src/modes/components/skill-hud/render.ts +4 -0
  97. package/src/modes/components/status-line/segments.ts +5 -16
  98. package/src/modes/components/status-line/types.ts +0 -3
  99. package/src/modes/components/status-line.ts +0 -6
  100. package/src/modes/controllers/command-controller.ts +27 -4
  101. package/src/modes/controllers/extension-ui-controller.ts +1 -0
  102. package/src/modes/controllers/input-controller.ts +0 -15
  103. package/src/modes/controllers/selector-controller.ts +4 -11
  104. package/src/modes/interactive-mode.ts +18 -219
  105. package/src/modes/theme/defaults/dark-poimandres.json +0 -1
  106. package/src/modes/theme/defaults/light-poimandres.json +0 -1
  107. package/src/modes/theme/theme.ts +0 -6
  108. package/src/modes/types.ts +1 -7
  109. package/src/modes/utils/context-usage.ts +66 -17
  110. package/src/prompts/agents/architect.md +3 -0
  111. package/src/prompts/agents/executor.md +2 -0
  112. package/src/prompts/agents/frontmatter.md +1 -0
  113. package/src/prompts/goals/goal-continuation.md +1 -4
  114. package/src/prompts/goals/goal-mode-active.md +3 -5
  115. package/src/prompts/system/subagent-system-prompt.md +6 -0
  116. package/src/prompts/system/system-prompt.md +5 -7
  117. package/src/prompts/tools/goal.md +4 -4
  118. package/src/prompts/tools/skill.md +28 -0
  119. package/src/prompts/tools/task.md +3 -0
  120. package/src/sdk.ts +51 -11
  121. package/src/session/agent-session.ts +222 -21
  122. package/src/session/contribution-prep.ts +320 -0
  123. package/src/session/session-manager.ts +9 -1
  124. package/src/setup/model-onboarding-guidance.ts +6 -3
  125. package/src/setup/provider-onboarding.ts +177 -16
  126. package/src/skill-state/active-state.ts +188 -25
  127. package/src/skill-state/deep-interview-mutation-guard.ts +72 -21
  128. package/src/skill-state/initial-phase.ts +17 -0
  129. package/src/skill-state/workflow-hud.ts +23 -5
  130. package/src/skill-state/workflow-state-contract.ts +121 -0
  131. package/src/slash-commands/builtin-registry.ts +75 -25
  132. package/src/slash-commands/helpers/context-report.ts +123 -13
  133. package/src/task/agents.ts +1 -0
  134. package/src/task/commands.ts +1 -5
  135. package/src/task/executor.ts +9 -1
  136. package/src/task/index.ts +91 -4
  137. package/src/task/types.ts +6 -0
  138. package/src/tools/ask.ts +2 -0
  139. package/src/tools/gh.ts +212 -2
  140. package/src/tools/index.ts +25 -6
  141. package/src/tools/skill.ts +153 -0
  142. package/src/utils/changelog.ts +67 -44
  143. package/dist/types/commands/gjc-runtime-bridge.d.ts +0 -30
  144. package/dist/types/commands/question.d.ts +0 -7
  145. package/dist/types/modes/loop-limit.d.ts +0 -22
  146. package/src/commands/gjc-runtime-bridge.ts +0 -227
  147. package/src/commands/question.ts +0 -12
  148. package/src/modes/loop-limit.ts +0 -140
  149. package/src/prompts/commands/orchestrate.md +0 -49
  150. package/src/prompts/goals/goal-budget-limit.md +0 -16
  151. package/src/prompts/tools/create-goal.md +0 -3
  152. package/src/prompts/tools/get-goal.md +0 -3
  153. package/src/prompts/tools/update-goal.md +0 -3
@@ -6,92 +6,50 @@ import * as z from "zod/v4";
6
6
  import type { RenderResultOptions } from "../../extensibility/custom-tools/types";
7
7
  import { assertCanCompleteCurrentGoal } from "../../gjc-runtime/ultragoal-guard";
8
8
  import type { Theme, ThemeColor } from "../../modes/theme/theme";
9
- import createGoalDescription from "../../prompts/tools/create-goal.md" with { type: "text" };
10
- import getGoalDescription from "../../prompts/tools/get-goal.md" with { type: "text" };
11
9
  import goalDescription from "../../prompts/tools/goal.md" with { type: "text" };
12
- import updateGoalDescription from "../../prompts/tools/update-goal.md" with { type: "text" };
13
10
  import { formatDuration } from "../../slash-commands/helpers/format";
14
11
  import type { ToolSession } from "../../tools";
15
12
  import { formatErrorMessage, TRUNCATE_LENGTHS } from "../../tools/render-utils";
16
13
  import { ToolError } from "../../tools/tool-errors";
17
14
  import { renderStatusLine, truncateToWidth } from "../../tui";
18
- import { completionBudgetReport, remainingTokens, validateGoalObjective } from "../runtime";
15
+ import { validateGoalObjective } from "../runtime";
19
16
  import type { Goal, GoalStatus, GoalToolDetails } from "../state";
20
17
 
21
18
  const goalSchema = z.object({
22
19
  op: z.enum(["create", "get", "complete", "resume", "drop"]).describe("goal operation"),
23
20
  objective: z.string().describe("goal objective").optional(),
24
- token_budget: z.number().int().describe("token budget").optional(),
25
- });
26
-
27
- const getGoalSchema = z.object({});
28
-
29
- const createGoalSchema = z.object({
30
- objective: z.string().describe("goal objective"),
31
- token_budget: z.number().int().describe("token budget").optional(),
32
- });
33
-
34
- const updateGoalSchema = z.object({
35
- status: z.enum(["complete", "dropped"]).describe("new goal status"),
36
21
  });
37
22
 
38
23
  export type GoalToolInput = z.infer<typeof goalSchema>;
39
- export type GetGoalToolInput = z.infer<typeof getGoalSchema>;
40
- export type CreateGoalToolInput = z.infer<typeof createGoalSchema>;
41
- export type UpdateGoalToolInput = z.infer<typeof updateGoalSchema>;
42
24
 
43
25
  export interface GoalToolResponse {
44
26
  goal: Goal | null;
45
- remainingTokens: number | null;
46
- completionBudgetReport: string | null;
47
27
  }
48
28
 
49
- export function buildGoalToolResponse(
50
- goal: Goal | null | undefined,
51
- options?: { includeCompletionReport?: boolean },
52
- ): GoalToolResponse {
53
- const resolvedGoal = goal ?? null;
54
- return {
55
- goal: resolvedGoal,
56
- remainingTokens: remainingTokens(resolvedGoal),
57
- completionBudgetReport:
58
- options?.includeCompletionReport && resolvedGoal?.status === "complete"
59
- ? completionBudgetReport(resolvedGoal)
60
- : null,
61
- };
29
+ export function buildGoalToolResponse(goal: Goal | null | undefined): GoalToolResponse {
30
+ return { goal: goal ?? null };
31
+ }
32
+
33
+ function rejectUnsupportedGoalArgs(params: Record<string, unknown>): void {
34
+ if ("token_budget" in params || "tokenBudget" in params) {
35
+ throw new ToolError("token_budget is not supported for goals");
36
+ }
62
37
  }
63
38
 
64
- function validateCreateParams(params: { objective?: string; token_budget?: number }): {
65
- objective: string;
66
- tokenBudget?: number;
67
- } {
39
+ function validateCreateParams(params: { objective?: string }): { objective: string } {
68
40
  let objective: string;
69
41
  try {
70
42
  objective = validateGoalObjective(params.objective ?? "", "create");
71
43
  } catch (error) {
72
44
  throw new ToolError(error instanceof Error ? error.message : String(error));
73
45
  }
74
- const tokenBudget = params.token_budget;
75
- if (tokenBudget !== undefined && (!Number.isInteger(tokenBudget) || tokenBudget <= 0)) {
76
- throw new ToolError("token_budget must be a positive integer when provided");
77
- }
78
- return { objective, tokenBudget };
46
+ return { objective };
79
47
  }
80
48
 
81
49
  function renderGoalToolResponse(response: GoalToolResponse): string {
82
50
  if (!response.goal) return "No active goal.";
83
51
 
84
- let text = `Goal: ${response.goal.objective}\nStatus: ${response.goal.status}\nTokens: ${response.goal.tokensUsed} used`;
85
- if (response.goal.tokenBudget !== undefined) {
86
- text += ` / ${response.goal.tokenBudget} budget`;
87
- }
88
- if (response.remainingTokens !== null) {
89
- text += `\nRemaining tokens: ${response.remainingTokens}`;
90
- }
91
- if (response.completionBudgetReport) {
92
- text += `\n\n${response.completionBudgetReport}`;
93
- }
94
- return text;
52
+ return `Goal: ${response.goal.objective}\nStatus: ${response.goal.status}\nTokens used: ${response.goal.tokensUsed}`;
95
53
  }
96
54
 
97
55
  function buildGoalToolResult(op: GoalToolDetails["op"], response: GoalToolResponse): AgentToolResult<GoalToolDetails> {
@@ -100,13 +58,12 @@ function buildGoalToolResult(op: GoalToolDetails["op"], response: GoalToolRespon
100
58
  details: {
101
59
  op,
102
60
  goal: response.goal,
103
- remainingTokens: response.remainingTokens,
104
- completionBudgetReport: response.completionBudgetReport,
105
61
  },
106
62
  };
107
63
  }
108
64
 
109
65
  async function executeGoalOperation(session: ToolSession, params: GoalToolInput): Promise<GoalToolResponse> {
66
+ rejectUnsupportedGoalArgs(params as Record<string, unknown>);
110
67
  if (params.op === "get") {
111
68
  const state = session.getGoalModeState?.();
112
69
  return buildGoalToolResponse(state?.goal ?? null);
@@ -135,7 +92,7 @@ async function executeGoalOperation(session: ToolSession, params: GoalToolInput)
135
92
  throw new ToolError(error instanceof Error ? error.message : String(error));
136
93
  }
137
94
  const completed = await runtime.completeGoalFromTool();
138
- return buildGoalToolResponse(completed, { includeCompletionReport: true });
95
+ return buildGoalToolResponse(completed);
139
96
  }
140
97
 
141
98
  export class GoalTool implements AgentTool<typeof goalSchema, GoalToolDetails> {
@@ -164,102 +121,6 @@ export class GoalTool implements AgentTool<typeof goalSchema, GoalToolDetails> {
164
121
  }
165
122
  }
166
123
 
167
- export class GetGoalTool implements AgentTool<typeof getGoalSchema, GoalToolDetails> {
168
- readonly name = "get_goal";
169
- readonly label = "Get Goal";
170
- readonly loadMode = "essential" as const;
171
- readonly description = prompt.render(getGoalDescription);
172
- readonly parameters = getGoalSchema;
173
- readonly strict = true;
174
- readonly intent = "omit" as const;
175
- readonly #session: ToolSession;
176
-
177
- static createIf(session: ToolSession): GetGoalTool | null {
178
- return session.getGoalModeState || session.getGoalRuntime ? new GetGoalTool(session) : null;
179
- }
180
-
181
- constructor(session: ToolSession) {
182
- this.#session = session;
183
- }
184
-
185
- async execute(
186
- _toolCallId: string,
187
- _params: GetGoalToolInput,
188
- _signal?: AbortSignal,
189
- _onUpdate?: AgentToolUpdateCallback<GoalToolDetails>,
190
- _context?: AgentToolContext,
191
- ): Promise<AgentToolResult<GoalToolDetails>> {
192
- const response = await executeGoalOperation(this.#session, { op: "get" });
193
- return buildGoalToolResult("get", response);
194
- }
195
- }
196
-
197
- export class CreateGoalTool implements AgentTool<typeof createGoalSchema, GoalToolDetails> {
198
- readonly name = "create_goal";
199
- readonly label = "Create Goal";
200
- readonly loadMode = "essential" as const;
201
- readonly description = prompt.render(createGoalDescription);
202
- readonly parameters = createGoalSchema;
203
- readonly strict = true;
204
- readonly intent = "omit" as const;
205
- readonly #session: ToolSession;
206
-
207
- static createIf(session: ToolSession): CreateGoalTool | null {
208
- return session.getGoalRuntime ? new CreateGoalTool(session) : null;
209
- }
210
-
211
- constructor(session: ToolSession) {
212
- this.#session = session;
213
- }
214
-
215
- async execute(
216
- _toolCallId: string,
217
- params: CreateGoalToolInput,
218
- _signal?: AbortSignal,
219
- _onUpdate?: AgentToolUpdateCallback<GoalToolDetails>,
220
- _context?: AgentToolContext,
221
- ): Promise<AgentToolResult<GoalToolDetails>> {
222
- const response = await executeGoalOperation(this.#session, {
223
- op: "create",
224
- objective: params.objective,
225
- token_budget: params.token_budget,
226
- });
227
- return buildGoalToolResult("create", response);
228
- }
229
- }
230
-
231
- export class UpdateGoalTool implements AgentTool<typeof updateGoalSchema, GoalToolDetails> {
232
- readonly name = "update_goal";
233
- readonly label = "Update Goal";
234
- readonly loadMode = "essential" as const;
235
- readonly description = prompt.render(updateGoalDescription);
236
- readonly parameters = updateGoalSchema;
237
- readonly strict = true;
238
- readonly intent = "omit" as const;
239
- readonly #session: ToolSession;
240
-
241
- static createIf(session: ToolSession): UpdateGoalTool | null {
242
- return session.getGoalRuntime ? new UpdateGoalTool(session) : null;
243
- }
244
-
245
- constructor(session: ToolSession) {
246
- this.#session = session;
247
- }
248
-
249
- async execute(
250
- _toolCallId: string,
251
- params: UpdateGoalToolInput,
252
- _signal?: AbortSignal,
253
- _onUpdate?: AgentToolUpdateCallback<GoalToolDetails>,
254
- _context?: AgentToolContext,
255
- ): Promise<AgentToolResult<GoalToolDetails>> {
256
- const response = await executeGoalOperation(this.#session, {
257
- op: params.status === "dropped" ? "drop" : "complete",
258
- });
259
- return buildGoalToolResult(params.status === "dropped" ? "drop" : "complete", response);
260
- }
261
- }
262
-
263
124
  function describeOp(op: string | undefined): string {
264
125
  switch (op) {
265
126
  case "create":
@@ -281,8 +142,6 @@ function goalBadgeColor(status: GoalStatus): ThemeColor {
281
142
  switch (status) {
282
143
  case "complete":
283
144
  return "success";
284
- case "budget-limited":
285
- return "warning";
286
145
  case "paused":
287
146
  case "dropped":
288
147
  return "muted";
@@ -294,7 +153,6 @@ function goalBadgeColor(status: GoalStatus): ThemeColor {
294
153
  interface GoalRenderArgs {
295
154
  op?: GoalToolInput["op"];
296
155
  objective?: string;
297
- token_budget?: number;
298
156
  }
299
157
 
300
158
  export const goalToolRenderer = {
@@ -306,9 +164,6 @@ export const goalToolRenderer = {
306
164
  const objective = truncateToWidth(trimmedObjective, TRUNCATE_LENGTHS.TITLE);
307
165
  meta.push(uiTheme.italic(uiTheme.fg("muted", `"${objective}"`)));
308
166
  }
309
- if (args.op === "create" && args.token_budget !== undefined) {
310
- meta.push(`budget ${formatNumber(args.token_budget)}`);
311
- }
312
167
  const text = renderStatusLine({ icon: "pending", title: "Goal", description, meta }, uiTheme);
313
168
  return new Text(text, 0, 0);
314
169
  },
@@ -352,24 +207,12 @@ export const goalToolRenderer = {
352
207
 
353
208
  const objectiveText = truncateToWidth(goal.objective.trim(), TRUNCATE_LENGTHS.LONG);
354
209
  lines.push(` ${uiTheme.italic(uiTheme.fg("muted", `"${objectiveText}"`))}`);
355
-
356
- const used = formatNumber(goal.tokensUsed);
357
- const tokensLine =
358
- goal.tokenBudget !== undefined
359
- ? `${used} / ${formatNumber(goal.tokenBudget)} tokens (${formatNumber(Math.max(0, goal.tokenBudget - goal.tokensUsed))} left)`
360
- : `${used} tokens`;
361
- lines.push(` ${uiTheme.fg("dim", tokensLine)}`);
210
+ lines.push(` ${uiTheme.fg("dim", `${formatNumber(goal.tokensUsed)} tokens used`)}`);
362
211
 
363
212
  if (goal.timeUsedSeconds > 0) {
364
213
  lines.push(` ${uiTheme.fg("dim", `${formatDuration(goal.timeUsedSeconds * 1000)} elapsed`)}`);
365
214
  }
366
215
 
367
- const report = details?.completionBudgetReport;
368
- if (report) {
369
- lines.push("");
370
- lines.push(uiTheme.italic(uiTheme.fg("muted", report)));
371
- }
372
-
373
216
  return new Text(lines.join("\n"), 0, 0);
374
217
  },
375
218
 
@@ -21,6 +21,7 @@ export interface EffectiveSkillConfigInput {
21
21
  }
22
22
 
23
23
  const SANITIZED_CONFIG_VALUE_LIMIT = 80;
24
+ const DEFAULT_DEEP_INTERVIEW_AMBIGUITY_THRESHOLD = 0.05;
24
25
 
25
26
  function sanitizeConfigValue(value: string): string {
26
27
  const compact = value.replace(/[\r\n\t]+/g, " ").trim();
@@ -111,6 +112,9 @@ export interface ModeState {
111
112
  thread_id?: string;
112
113
  cwd?: string;
113
114
  updated_at?: string;
115
+ handoff_from?: string;
116
+ handoff_to?: string;
117
+ handoff_at?: string;
114
118
  [key: string]: unknown;
115
119
  }
116
120
 
@@ -219,11 +223,10 @@ function encodeStatePathSegment(value: string): string {
219
223
  return encodeURIComponent(value).replaceAll(".", "%2E");
220
224
  }
221
225
 
222
- function initialPhaseForSkill(skill: GjcWorkflowSkill): string {
223
- if (skill === "deep-interview") return "interviewing";
224
- if (skill === "ultragoal") return "goal-planning";
225
- return "planning";
226
- }
226
+ import { initialPhaseForSkill } from "../skill-state/initial-phase";
227
+
228
+ // Re-export for existing callers and tests that imported it from this module.
229
+ export { initialPhaseForSkill };
227
230
 
228
231
  function modeStateFileName(skill: GjcWorkflowSkill): string {
229
232
  return `${skill}-state.json`;
@@ -329,6 +332,10 @@ export async function recordSkillActivation(input: RecordSkillActivationInput):
329
332
  ...(input.threadId ? { thread_id: input.threadId } : {}),
330
333
  ...(input.turnId ? { turn_id: input.turnId } : {}),
331
334
  };
335
+ if (match.skill === "deep-interview") {
336
+ modeState.threshold = DEFAULT_DEEP_INTERVIEW_AMBIGUITY_THRESHOLD;
337
+ modeState.threshold_source = "default";
338
+ }
332
339
 
333
340
  await writeJsonFile(initializedStatePath, modeState);
334
341
  await writeJsonFile(skillStatePath(resolvedStateDir, input.sessionId), state);
@@ -342,7 +349,7 @@ function isTerminalModeState(state: ModeState | null): boolean {
342
349
  const phase = String(state.current_phase ?? "")
343
350
  .trim()
344
351
  .toLowerCase();
345
- return ["complete", "completed", "failed", "cancelled", "canceled", "inactive"].includes(phase);
352
+ return ["complete", "completed", "handoff", "failed", "cancelled", "canceled", "inactive"].includes(phase);
346
353
  }
347
354
 
348
355
  async function readVisibleModeState(
@@ -389,20 +396,34 @@ export async function buildActiveUltragoalPromptContext(input: UserPromptSubmitS
389
396
  if (!stateMatchesContext(visibleModeState.state, input.sessionId, input.threadId)) return null;
390
397
 
391
398
  const phase = String(visibleModeState.state.current_phase ?? "active");
392
- const objective =
393
- (await readCurrentGoalObjectiveFromSessionFile(input.sessionFile)) ??
394
- (typeof visibleModeState.state.objective === "string"
399
+ const stateObjective =
400
+ typeof visibleModeState.state.objective === "string"
395
401
  ? visibleModeState.state.objective
396
402
  : typeof visibleModeState.state.gjcObjective === "string"
397
403
  ? visibleModeState.state.gjcObjective
398
- : "");
399
- if (input.prompt && isUltragoalBypassPrompt(input.prompt) && objective) {
400
- const diagnostic = await readUltragoalVerificationState({
401
- cwd: input.cwd,
402
- currentGoal: { objective },
403
- });
404
- if (!["inactive", "unrelated_goal", "active_verified_complete"].includes(diagnostic.state)) {
405
- return `BLOCK_ULTRAGOAL_COMPLETION: ${diagnostic.message} Use durable blocker work or run strict \`gjc ultragoal checkpoint --status complete --quality-gate-json <file> --gjc-goal-json <file>\` before completion.`;
404
+ : "";
405
+ const sessionObjective = await readCurrentGoalObjectiveFromSessionFile(input.sessionFile);
406
+ const normalizedPrompt = input.prompt?.replace(/\\?"/g, '"');
407
+ const isBypassPrompt = Boolean(
408
+ (normalizedPrompt && isUltragoalBypassPrompt(normalizedPrompt)) ||
409
+ (input.prompt && /goal[\s\S]{0,80}complete/i.test(input.prompt)),
410
+ );
411
+ if (isBypassPrompt) {
412
+ const objectives = [sessionObjective, stateObjective].filter(
413
+ (value): value is string => typeof value === "string" && value.trim().length > 0,
414
+ );
415
+ if (objectives.length === 0) {
416
+ return "BLOCK_ULTRAGOAL_COMPLETION: Active Ultragoal completion is blocked until a current GJC goal objective can be verified. Use durable blocker work or run strict `gjc ultragoal checkpoint --status complete --quality-gate-json <file> --gjc-goal-json <file>` before completion.";
417
+ }
418
+ for (const objective of objectives) {
419
+ const diagnostic = await readUltragoalVerificationState({
420
+ cwd: input.cwd,
421
+ currentGoal: { objective },
422
+ });
423
+ if (diagnostic.state === "unrelated_goal") continue;
424
+ if (!["inactive", "active_verified_complete"].includes(diagnostic.state)) {
425
+ return `BLOCK_ULTRAGOAL_COMPLETION: ${diagnostic.message} Use durable blocker work or run strict \`gjc ultragoal checkpoint --status complete --quality-gate-json <file> --gjc-goal-json <file>\` before completion.`;
426
+ }
406
427
  }
407
428
  }
408
429
  return `Ultragoal is active (phase: ${phase}; state: ${visibleModeState.statePath}). If the user prompt is a steering request, use \`gjc ultragoal steer\` to add or steer subgoals. Normal prose should not mutate Ultragoal state.`;
@@ -465,7 +486,7 @@ export function buildSkillActivationAdditionalContext(
465
486
  return [
466
487
  `GJC native UserPromptSubmit detected workflow keyword "${state.keyword}" -> ${state.skill}.`,
467
488
  state.initialized_mode && state.initialized_state_path
468
- ? `skill: ${state.initialized_mode} activated and initial state initialized at ${state.initialized_state_path}; use \`gjc state write/read/clear --input '<json>' --json\` for runtime state updates when the private GJC runtime endpoint is available.`
489
+ ? `skill: ${state.initialized_mode} activated and initial state initialized at ${state.initialized_state_path}; use \`gjc state write/read/clear --input '<json>' --json\` for runtime state updates.`
469
490
  : null,
470
491
  state.skill === "ultragoal"
471
492
  ? "Ultragoal is active. If the user prompt is a steering request, use `gjc ultragoal steer` to add or steer subgoals."