@gajae-code/coding-agent 0.3.0 → 0.3.1

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 (175) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/types/async/job-manager.d.ts +7 -0
  3. package/dist/types/cli/args.d.ts +1 -1
  4. package/dist/types/commands/deep-interview.d.ts +3 -0
  5. package/dist/types/config/keybindings.d.ts +5 -0
  6. package/dist/types/config/settings-schema.d.ts +4 -4
  7. package/dist/types/debug/crash-diagnostics.d.ts +45 -0
  8. package/dist/types/debug/runtime-gauges.d.ts +6 -0
  9. package/dist/types/deep-interview/render-middleware.d.ts +1 -0
  10. package/dist/types/eval/py/executor.d.ts +2 -0
  11. package/dist/types/eval/py/kernel.d.ts +2 -0
  12. package/dist/types/exec/bash-executor.d.ts +10 -0
  13. package/dist/types/gjc-runtime/cli-write-receipt.d.ts +24 -0
  14. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -0
  15. package/dist/types/gjc-runtime/state-migrations.d.ts +9 -0
  16. package/dist/types/gjc-runtime/state-schema.d.ts +317 -0
  17. package/dist/types/gjc-runtime/state-writer.d.ts +10 -0
  18. package/dist/types/gjc-runtime/workflow-command-ref.d.ts +43 -0
  19. package/dist/types/harness-control-plane/control-endpoint.d.ts +3 -2
  20. package/dist/types/hooks/skill-state.d.ts +21 -0
  21. package/dist/types/internal-urls/agent-protocol.d.ts +2 -2
  22. package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
  23. package/dist/types/internal-urls/registry-helpers.d.ts +8 -7
  24. package/dist/types/internal-urls/types.d.ts +4 -0
  25. package/dist/types/lsp/index.d.ts +10 -10
  26. package/dist/types/modes/bridge/auth.d.ts +12 -0
  27. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
  28. package/dist/types/modes/bridge/bridge-mode.d.ts +44 -0
  29. package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
  30. package/dist/types/modes/bridge/event-stream.d.ts +8 -0
  31. package/dist/types/modes/components/custom-editor.d.ts +6 -0
  32. package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
  33. package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
  34. package/dist/types/modes/components/status-line/types.d.ts +2 -0
  35. package/dist/types/modes/components/status-line.d.ts +2 -0
  36. package/dist/types/modes/controllers/input-controller.d.ts +1 -0
  37. package/dist/types/modes/controllers/selector-controller.d.ts +8 -0
  38. package/dist/types/modes/index.d.ts +1 -0
  39. package/dist/types/modes/interactive-mode.d.ts +1 -0
  40. package/dist/types/modes/jobs-observer.d.ts +57 -0
  41. package/dist/types/modes/rpc/host-tools.d.ts +1 -16
  42. package/dist/types/modes/rpc/host-uris.d.ts +1 -38
  43. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +20 -0
  44. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
  45. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +24 -0
  46. package/dist/types/modes/shared/agent-wire/handshake.d.ts +46 -0
  47. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
  48. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
  49. package/dist/types/modes/shared/agent-wire/protocol.d.ts +44 -0
  50. package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
  51. package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
  52. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
  53. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
  54. package/dist/types/modes/types.d.ts +1 -0
  55. package/dist/types/sdk.d.ts +2 -0
  56. package/dist/types/session/agent-session.d.ts +11 -1
  57. package/dist/types/skill-state/workflow-state-contract.d.ts +1 -2
  58. package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
  59. package/dist/types/task/id.d.ts +7 -0
  60. package/dist/types/task/index.d.ts +5 -0
  61. package/dist/types/task/receipt.d.ts +85 -0
  62. package/dist/types/task/spawn-gate.d.ts +38 -0
  63. package/dist/types/task/types.d.ts +143 -11
  64. package/dist/types/tools/cron.d.ts +6 -0
  65. package/dist/types/tools/index.d.ts +2 -0
  66. package/dist/types/tools/path-utils.d.ts +1 -0
  67. package/dist/types/tools/subagent.d.ts +15 -0
  68. package/package.json +7 -7
  69. package/scripts/build-binary.ts +7 -0
  70. package/src/async/job-manager.ts +36 -0
  71. package/src/cli/args.ts +9 -2
  72. package/src/commands/deep-interview.ts +1 -0
  73. package/src/commands/harness.ts +289 -19
  74. package/src/commands/launch.ts +2 -2
  75. package/src/commands/state.ts +2 -1
  76. package/src/commands/team.ts +22 -4
  77. package/src/config/keybindings.ts +6 -0
  78. package/src/config/settings-schema.ts +6 -3
  79. package/src/dap/client.ts +17 -3
  80. package/src/debug/crash-diagnostics.ts +223 -0
  81. package/src/debug/runtime-gauges.ts +20 -0
  82. package/src/deep-interview/render-middleware.ts +6 -0
  83. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
  84. package/src/defaults/gjc/skills/ralplan/SKILL.md +31 -2
  85. package/src/defaults/gjc/skills/ultragoal/SKILL.md +28 -2
  86. package/src/eval/py/executor.ts +21 -1
  87. package/src/eval/py/kernel.ts +15 -0
  88. package/src/exec/bash-executor.ts +41 -0
  89. package/src/gjc-runtime/cli-write-receipt.ts +31 -0
  90. package/src/gjc-runtime/deep-interview-runtime.ts +69 -32
  91. package/src/gjc-runtime/ralplan-runtime.ts +213 -36
  92. package/src/gjc-runtime/state-migrations.ts +54 -7
  93. package/src/gjc-runtime/state-runtime.ts +461 -64
  94. package/src/gjc-runtime/state-schema.ts +192 -0
  95. package/src/gjc-runtime/state-writer.ts +32 -1
  96. package/src/gjc-runtime/team-runtime.ts +177 -105
  97. package/src/gjc-runtime/ultragoal-runtime.ts +114 -26
  98. package/src/gjc-runtime/workflow-command-ref.ts +239 -0
  99. package/src/gjc-runtime/workflow-manifest.generated.json +108 -4
  100. package/src/gjc-runtime/workflow-manifest.ts +3 -1
  101. package/src/harness-control-plane/control-endpoint.ts +19 -8
  102. package/src/harness-control-plane/owner.ts +57 -10
  103. package/src/harness-control-plane/state-machine.ts +2 -1
  104. package/src/hooks/skill-state.ts +176 -26
  105. package/src/internal-urls/agent-protocol.ts +68 -21
  106. package/src/internal-urls/artifact-protocol.ts +12 -17
  107. package/src/internal-urls/docs-index.generated.ts +3 -2
  108. package/src/internal-urls/registry-helpers.ts +19 -16
  109. package/src/internal-urls/types.ts +4 -0
  110. package/src/lsp/client.ts +18 -2
  111. package/src/main.ts +21 -5
  112. package/src/modes/bridge/auth.ts +41 -0
  113. package/src/modes/bridge/bridge-client-bridge.ts +47 -0
  114. package/src/modes/bridge/bridge-mode.ts +520 -0
  115. package/src/modes/bridge/bridge-ui-context.ts +200 -0
  116. package/src/modes/bridge/event-stream.ts +70 -0
  117. package/src/modes/components/custom-editor.ts +101 -0
  118. package/src/modes/components/hook-selector.ts +61 -18
  119. package/src/modes/components/jobs-overlay-model.ts +109 -0
  120. package/src/modes/components/jobs-overlay.ts +172 -0
  121. package/src/modes/components/status-line/presets.ts +7 -5
  122. package/src/modes/components/status-line/segments.ts +25 -0
  123. package/src/modes/components/status-line/types.ts +2 -0
  124. package/src/modes/components/status-line.ts +9 -1
  125. package/src/modes/controllers/extension-ui-controller.ts +39 -3
  126. package/src/modes/controllers/input-controller.ts +97 -9
  127. package/src/modes/controllers/selector-controller.ts +29 -0
  128. package/src/modes/index.ts +1 -0
  129. package/src/modes/interactive-mode.ts +27 -0
  130. package/src/modes/jobs-observer.ts +204 -0
  131. package/src/modes/rpc/host-tools.ts +1 -186
  132. package/src/modes/rpc/host-uris.ts +1 -235
  133. package/src/modes/rpc/rpc-client.ts +25 -10
  134. package/src/modes/rpc/rpc-mode.ts +12 -381
  135. package/src/modes/shared/agent-wire/command-dispatch.ts +341 -0
  136. package/src/modes/shared/agent-wire/command-validation.ts +131 -0
  137. package/src/modes/shared/agent-wire/event-envelope.ts +108 -0
  138. package/src/modes/shared/agent-wire/handshake.ts +117 -0
  139. package/src/modes/shared/agent-wire/host-tool-bridge.ts +194 -0
  140. package/src/modes/shared/agent-wire/host-uri-bridge.ts +236 -0
  141. package/src/modes/shared/agent-wire/protocol.ts +96 -0
  142. package/src/modes/shared/agent-wire/responses.ts +17 -0
  143. package/src/modes/shared/agent-wire/scopes.ts +89 -0
  144. package/src/modes/shared/agent-wire/ui-request-broker.ts +150 -0
  145. package/src/modes/shared/agent-wire/ui-result.ts +48 -0
  146. package/src/modes/types.ts +1 -0
  147. package/src/prompts/tools/subagent.md +12 -7
  148. package/src/prompts/tools/task-summary.md +3 -9
  149. package/src/prompts/tools/task.md +5 -1
  150. package/src/sdk.ts +4 -0
  151. package/src/session/agent-session.ts +214 -38
  152. package/src/skill-state/deep-interview-mutation-guard.ts +23 -4
  153. package/src/skill-state/workflow-state-contract.ts +7 -4
  154. package/src/skill-state/workflow-state-version.ts +3 -0
  155. package/src/slash-commands/builtin-registry.ts +8 -0
  156. package/src/task/executor.ts +29 -5
  157. package/src/task/id.ts +33 -0
  158. package/src/task/index.ts +257 -67
  159. package/src/task/output-manager.ts +5 -4
  160. package/src/task/receipt.ts +297 -0
  161. package/src/task/render.ts +48 -131
  162. package/src/task/spawn-gate.ts +132 -0
  163. package/src/task/types.ts +48 -7
  164. package/src/tools/ask.ts +73 -33
  165. package/src/tools/ast-edit.ts +1 -0
  166. package/src/tools/ast-grep.ts +1 -0
  167. package/src/tools/bash.ts +1 -1
  168. package/src/tools/cron.ts +48 -0
  169. package/src/tools/find.ts +4 -1
  170. package/src/tools/index.ts +2 -0
  171. package/src/tools/path-utils.ts +3 -2
  172. package/src/tools/read.ts +1 -0
  173. package/src/tools/search.ts +1 -0
  174. package/src/tools/skill.ts +6 -1
  175. package/src/tools/subagent.ts +237 -84
@@ -2,6 +2,7 @@ import * as crypto from "node:crypto";
2
2
  import * as path from "node:path";
3
3
  import type { WorkflowHudSummary } from "../skill-state/active-state";
4
4
  import { buildUltragoalHudSummary as buildWorkflowUltragoalHudSummary } from "../skill-state/workflow-hud";
5
+ import { renderCliWriteReceipt } from "./cli-write-receipt";
5
6
  import { DEFAULT_ULTRAGOAL_OBJECTIVE } from "./goal-mode-request";
6
7
  import { renderUltragoalStatusMarkdown } from "./state-renderer";
7
8
  import { appendJsonl, writeArtifact, writeJsonAtomic } from "./state-writer";
@@ -474,13 +475,58 @@ export function buildUltragoalHudSummary(
474
475
  });
475
476
  }
476
477
 
477
- function titleFromBrief(brief: string): string {
478
- const firstLine = brief
478
+ function clampTitle(title: string): string {
479
+ return title.length > 80 ? `${title.slice(0, 77)}...` : title;
480
+ }
481
+
482
+ function firstNonEmptyLine(text: string): string | undefined {
483
+ return text
479
484
  .split(/\r?\n/)
480
485
  .map(line => line.trim())
481
486
  .find(line => line.length > 0);
487
+ }
488
+
489
+ function titleFromBrief(brief: string): string {
490
+ const firstLine = firstNonEmptyLine(brief);
482
491
  if (!firstLine) return "Complete ultragoal brief";
483
- return firstLine.length > 80 ? `${firstLine.slice(0, 77)}...` : firstLine;
492
+ return clampTitle(firstLine);
493
+ }
494
+
495
+ // A reserved, column-0 (unindented) `@goal` line opens a story. The character
496
+ // right after `@goal` must be `:`, an ASCII space or tab, or end-of-line, so
497
+ // `@goalish`, `@goals:`, `@goal-foo`, `@goal.foo`, `@goal/foo`, a non-breaking
498
+ // space, and indented or mid-line `@goal:` are all ordinary objective text and
499
+ // never delimiters.
500
+ const GOAL_DELIMITER = /^@goal(?::|[ \t]+|$)[ \t]*(.*)$/;
501
+
502
+ interface ParsedGoal {
503
+ title: string;
504
+ objective: string;
505
+ }
506
+
507
+ function parseGoalsFromBrief(brief: string): ParsedGoal[] {
508
+ const sections: { title: string; body: string[] }[] = [];
509
+ let current: { title: string; body: string[] } | undefined;
510
+ for (const line of brief.split(/\r?\n/)) {
511
+ const match = GOAL_DELIMITER.exec(line);
512
+ if (match) {
513
+ current = { title: match[1].trim(), body: [] };
514
+ sections.push(current);
515
+ continue;
516
+ }
517
+ current?.body.push(line);
518
+ }
519
+ if (sections.length === 0) {
520
+ return [{ title: titleFromBrief(brief), objective: brief.trim() }];
521
+ }
522
+ return sections.map((section, index) => {
523
+ const body = section.body.join("\n").trim();
524
+ const title = section.title || firstNonEmptyLine(body) || "";
525
+ if (!title && !body) {
526
+ throw new Error(`ultragoal @goal block ${index + 1} has no title or objective`);
527
+ }
528
+ return { title: clampTitle(title), objective: body || title };
529
+ });
484
530
  }
485
531
 
486
532
  export async function createUltragoalPlan(input: {
@@ -491,21 +537,23 @@ export async function createUltragoalPlan(input: {
491
537
  const brief = input.brief.trim();
492
538
  if (!brief) throw new Error("ultragoal brief is required");
493
539
  const now = new Date().toISOString();
540
+ // Parse the untrimmed brief so the raw-line delimiter contract holds: a
541
+ // leading-indented `@goal` on the first line must stay objective text rather
542
+ // than being promoted to column 0 by trimming.
543
+ const goals: UltragoalGoal[] = parseGoalsFromBrief(input.brief).map((goal, index) => ({
544
+ id: `G${String(index + 1).padStart(3, "0")}`,
545
+ title: goal.title,
546
+ objective: goal.objective,
547
+ status: "pending",
548
+ createdAt: now,
549
+ updatedAt: now,
550
+ }));
494
551
  const plan: UltragoalPlan = {
495
552
  version: 1,
496
553
  brief,
497
554
  gjcGoalMode: input.gjcGoalMode ?? "aggregate",
498
555
  gjcObjective: DEFAULT_ULTRAGOAL_OBJECTIVE,
499
- goals: [
500
- {
501
- id: "G001",
502
- title: titleFromBrief(brief),
503
- objective: brief,
504
- status: "pending",
505
- createdAt: now,
506
- updatedAt: now,
507
- },
508
- ],
556
+ goals,
509
557
  createdAt: now,
510
558
  updatedAt: now,
511
559
  };
@@ -1235,16 +1283,26 @@ function renderStatus(summary: UltragoalStatusSummary, json: boolean): string {
1235
1283
  function renderCompleteHandoff(
1236
1284
  result: { plan: UltragoalPlan; goal?: UltragoalGoal; allComplete: boolean },
1237
1285
  json: boolean,
1286
+ cwd: string,
1238
1287
  ): string {
1239
- if (json) return `${JSON.stringify(result, null, 2)}\n`;
1240
- if (result.allComplete) return "All ultragoal goals are complete.\n";
1241
- if (!result.goal) return "No schedulable ultragoal goal found.\n";
1288
+ if (json) {
1289
+ return renderCliWriteReceipt({
1290
+ ok: true,
1291
+ all_complete: result.allComplete,
1292
+ next_action: result.allComplete ? "none" : "execute-goal",
1293
+ goal_id: result.goal?.id,
1294
+ goal_status: result.goal?.status,
1295
+ gjc_objective: result.plan.gjcObjective,
1296
+ goals_path: getUltragoalPaths(cwd).goalsPath,
1297
+ });
1298
+ }
1299
+ if (result.allComplete) return "ultragoal complete all=true\n";
1300
+ if (!result.goal) return "ultragoal next-action=none\n";
1242
1301
  return [
1243
- `Ultragoal handoff: ${result.goal.id} — ${result.goal.title}`,
1244
- `Objective: ${result.goal.objective}`,
1245
- `GJC objective: ${result.plan.gjcObjective}`,
1246
- 'Call goal({"op":"get"}); call goal({"op":"create","objective":"<printed objective>"}) only if no active GJC goal exists, then keep the GJC goal active while this Ultragoal story is verified and checkpointed.',
1247
- 'Before checkpointing complete, obtain a passing architectReview (architecture/product/code CLEAR + APPROVE) and executorQa (e2e/red-team passed with contractCoverage, surfaceEvidence, adversarialCases, and artifactRefs matrix evidence), then checkpoint with --quality-gate-json and a fresh active goal snapshot; record blockers instead of completing on any finding, plan/code mismatch, shallow evidence, or missing artifact link; call goal({"op":"complete"}) only after the final aggregate receipt exists.',
1302
+ `ultragoal next-action=execute-goal goal-id=${result.goal.id}`,
1303
+ `objective=${result.goal.objective}`,
1304
+ `gjc-objective=${result.plan.gjcObjective}`,
1305
+ "checkpoint requires=architectReview:CLEAR+APPROVE,executorQa:passed",
1248
1306
  "",
1249
1307
  ].join("\n");
1250
1308
  }
@@ -1264,8 +1322,13 @@ export async function runNativeUltragoalCommand(args: string[], cwd = process.cw
1264
1322
  status: 0,
1265
1323
  createdPlan: true,
1266
1324
  stdout: json
1267
- ? `${JSON.stringify(plan, null, 2)}\n`
1268
- : `Created ultragoal plan with ${plan.goals.length} goal at ${getUltragoalPaths(cwd).goalsPath}.\n`,
1325
+ ? renderCliWriteReceipt({
1326
+ ok: true,
1327
+ goals_count: plan.goals.length,
1328
+ goal_ids: plan.goals.map(goal => goal.id),
1329
+ goals_path: getUltragoalPaths(cwd).goalsPath,
1330
+ })
1331
+ : `Created ultragoal plan with ${plan.goals.length} goal${plan.goals.length === 1 ? "" : "s"} at ${getUltragoalPaths(cwd).goalsPath}.\n`,
1269
1332
  };
1270
1333
  }
1271
1334
  case "complete-goals":
@@ -1274,6 +1337,7 @@ export async function runNativeUltragoalCommand(args: string[], cwd = process.cw
1274
1337
  stdout: renderCompleteHandoff(
1275
1338
  await startNextUltragoalGoal({ cwd, retryFailed: hasFlag(args, "--retry-failed") }),
1276
1339
  json,
1340
+ cwd,
1277
1341
  ),
1278
1342
  };
1279
1343
  case "checkpoint": {
@@ -1288,9 +1352,19 @@ export async function runNativeUltragoalCommand(args: string[], cwd = process.cw
1288
1352
  gjcGoalJson: flagValue(args, "--gjc-goal-json"),
1289
1353
  qualityGateJson: flagValue(args, "--quality-gate-json"),
1290
1354
  });
1355
+ const goal = plan.goals.find(item => item.id === goalId);
1291
1356
  return {
1292
1357
  status: 0,
1293
- stdout: json ? `${JSON.stringify(plan, null, 2)}\n` : `Checkpointed ${goalId} as ${status}.\n`,
1358
+ stdout: json
1359
+ ? renderCliWriteReceipt({
1360
+ ok: true,
1361
+ goal_id: goalId,
1362
+ status,
1363
+ goals_path: getUltragoalPaths(cwd).goalsPath,
1364
+ completion_receipt_kind: goal?.completionVerification?.receiptKind,
1365
+ quality_gate_hash: goal?.completionVerification?.qualityGateHash,
1366
+ })
1367
+ : `ultragoal checkpoint goal-id=${goalId} status=${status}\n`,
1294
1368
  };
1295
1369
  }
1296
1370
  case "steer": {
@@ -1303,9 +1377,17 @@ export async function runNativeUltragoalCommand(args: string[], cwd = process.cw
1303
1377
  evidence: flagValue(args, "--evidence") ?? "",
1304
1378
  rationale: flagValue(args, "--rationale") ?? "",
1305
1379
  });
1380
+ const goal = plan.goals.at(-1);
1306
1381
  return {
1307
1382
  status: 0,
1308
- stdout: json ? `${JSON.stringify(plan, null, 2)}\n` : "Accepted add_subgoal steering.\n",
1383
+ stdout: json
1384
+ ? renderCliWriteReceipt({
1385
+ ok: true,
1386
+ kind,
1387
+ goal_id: goal?.id,
1388
+ goals_path: getUltragoalPaths(cwd).goalsPath,
1389
+ })
1390
+ : "Accepted add_subgoal steering.\n",
1309
1391
  };
1310
1392
  }
1311
1393
  case "record-review-blockers": {
@@ -1317,7 +1399,13 @@ export async function runNativeUltragoalCommand(args: string[], cwd = process.cw
1317
1399
  evidence: flagValue(args, "--evidence") ?? "",
1318
1400
  gjcGoalJson: flagValue(args, "--gjc-goal-json"),
1319
1401
  });
1320
- return { status: 0, stdout: json ? `${JSON.stringify(plan, null, 2)}\n` : "Recorded review blockers.\n" };
1402
+ const goal = plan.goals.at(-1);
1403
+ return {
1404
+ status: 0,
1405
+ stdout: json
1406
+ ? renderCliWriteReceipt({ ok: true, goal_id: goal?.id, goals_path: getUltragoalPaths(cwd).goalsPath })
1407
+ : "Recorded review blockers.\n",
1408
+ };
1321
1409
  }
1322
1410
  default:
1323
1411
  return { status: 1, stderr: `Unknown gjc ultragoal command: ${command}\n` };
@@ -0,0 +1,239 @@
1
+ import type { CanonicalGjcWorkflowSkill } from "../skill-state/active-state";
2
+ import { CANONICAL_GJC_WORKFLOW_SKILLS } from "../skill-state/active-state";
3
+
4
+ export type CommandRefVisibility = "public" | "hidden" | "planned";
5
+ export type CommandRefIncludeWhen = "implemented-only" | "planned";
6
+
7
+ export interface CommandRefCommand {
8
+ tokens: string[];
9
+ rendered: string;
10
+ visibility: CommandRefVisibility;
11
+ includeWhen: CommandRefIncludeWhen;
12
+ note?: string;
13
+ }
14
+
15
+ export interface CommandRefExample {
16
+ label?: string;
17
+ bytes: string;
18
+ }
19
+
20
+ export interface CommandRefBridge {
21
+ from: string;
22
+ to: string;
23
+ rendered: string;
24
+ }
25
+
26
+ export interface CommandRefBlock {
27
+ skill: CanonicalGjcWorkflowSkill;
28
+ blockId: string;
29
+ sourcePath: string;
30
+ renderOrder: number;
31
+ markers: {
32
+ start: string;
33
+ end: string;
34
+ };
35
+ commands: CommandRefCommand[];
36
+ examples: CommandRefExample[];
37
+ aliasesAndBridges: CommandRefBridge[];
38
+ notes: string[];
39
+ }
40
+
41
+ export interface RenderedCommandRefBlock {
42
+ skill: CanonicalGjcWorkflowSkill;
43
+ blockId: string;
44
+ markers: CommandRefBlock["markers"];
45
+ bytes: string;
46
+ }
47
+
48
+ const skillPath = (skill: CanonicalGjcWorkflowSkill): string =>
49
+ `packages/coding-agent/src/defaults/gjc/skills/${skill}/SKILL.md`;
50
+
51
+ const stateWrite = (skill: CanonicalGjcWorkflowSkill): CommandRefCommand => ({
52
+ tokens: ["gjc", "state", skill, "write", "--input", `'{"current_phase":"handoff"}'`, "--json"],
53
+ rendered: `gjc state ${skill} write --input '{"current_phase":"handoff"}' --json`,
54
+ visibility: "public",
55
+ includeWhen: "implemented-only",
56
+ note: "Marks the workflow ready for the skill-tool chain guard.",
57
+ });
58
+
59
+ const stateHandoff = (
60
+ skill: CanonicalGjcWorkflowSkill,
61
+ targets: readonly CanonicalGjcWorkflowSkill[],
62
+ ): CommandRefCommand => ({
63
+ tokens: ["gjc", "state", skill, "handoff", "--to", `<${targets.join("|")}>`, "--json"],
64
+ rendered: `gjc state ${skill} handoff --to <${targets.join("|")}> --json`,
65
+ visibility: "public",
66
+ includeWhen: "implemented-only",
67
+ note: "Bridge command run in-process by the skill tool after slash-skill dispatch.",
68
+ });
69
+
70
+ export const WORKFLOW_COMMAND_REF_BLOCKS: readonly CommandRefBlock[] = [
71
+ {
72
+ skill: "deep-interview",
73
+ blockId: "state",
74
+ sourcePath: skillPath("deep-interview"),
75
+ renderOrder: 10,
76
+ markers: {
77
+ start: "<!-- gjc:cmdref:start state -->",
78
+ end: "<!-- gjc:cmdref:end state -->",
79
+ },
80
+ commands: [
81
+ stateWrite("deep-interview"),
82
+ {
83
+ tokens: [
84
+ "gjc",
85
+ "deep-interview",
86
+ "--write",
87
+ "--stage",
88
+ "final",
89
+ "--slug",
90
+ "{slug}",
91
+ "--spec",
92
+ "<markdown-or-path>",
93
+ "--deliberate",
94
+ "--json",
95
+ ],
96
+ rendered:
97
+ "gjc deep-interview --write --stage final --slug {slug} --spec <markdown-or-path> --deliberate --json",
98
+ visibility: "public",
99
+ includeWhen: "implemented-only",
100
+ note: "Sanctioned deliberate deep-interview to ralplan bridge.",
101
+ },
102
+ ],
103
+ examples: [
104
+ {
105
+ label: "handoff state write",
106
+ bytes: '```\ngjc state deep-interview write --input \'{"current_phase":"handoff"}\' --json\n```',
107
+ },
108
+ {
109
+ label: "deliberate bridge",
110
+ bytes: "```\ngjc \\\ndeep-interview --write --stage final --slug {slug} --spec <markdown-or-path> --deliberate --json\n```",
111
+ },
112
+ ],
113
+ aliasesAndBridges: [
114
+ {
115
+ from: "deep-interview",
116
+ to: "ralplan",
117
+ rendered:
118
+ "gjc deep-interview --write --stage final --slug {slug} --spec <markdown-or-path> --deliberate --json",
119
+ },
120
+ ],
121
+ notes: [
122
+ "Before invoking `/skill:ralplan`, `/skill:team`, or `/skill:ultragoal`, persist the final spec and mark deep-interview ready for handoff.",
123
+ ],
124
+ },
125
+ {
126
+ skill: "ralplan",
127
+ blockId: "state",
128
+ sourcePath: skillPath("ralplan"),
129
+ renderOrder: 10,
130
+ markers: { start: "<!-- gjc:cmdref:start state -->", end: "<!-- gjc:cmdref:end state -->" },
131
+ commands: [stateWrite("ralplan"), stateHandoff("ralplan", ["team", "ultragoal"])],
132
+ examples: [
133
+ {
134
+ label: "handoff state write",
135
+ bytes: '```\ngjc state ralplan write --input \'{"current_phase":"handoff"}\' --json\n```',
136
+ },
137
+ ],
138
+ aliasesAndBridges: [
139
+ { from: "ralplan", to: "team|ultragoal", rendered: "gjc state ralplan handoff --to <team|ultragoal> --json" },
140
+ ],
141
+ notes: [
142
+ "Before invoking `/skill:team` or `/skill:ultragoal`, mark ralplan ready for handoff so the skill tool's chain guard permits the transition.",
143
+ ],
144
+ },
145
+ {
146
+ skill: "ultragoal",
147
+ blockId: "state",
148
+ sourcePath: skillPath("ultragoal"),
149
+ renderOrder: 10,
150
+ markers: { start: "<!-- gjc:cmdref:start state -->", end: "<!-- gjc:cmdref:end state -->" },
151
+ commands: [stateWrite("ultragoal"), stateHandoff("ultragoal", ["ralplan", "deep-interview"])],
152
+ examples: [
153
+ {
154
+ label: "handoff state write",
155
+ bytes: '```\ngjc state ultragoal write --input \'{"current_phase":"handoff"}\' --json\n```',
156
+ },
157
+ ],
158
+ aliasesAndBridges: [
159
+ {
160
+ from: "ultragoal",
161
+ to: "ralplan|deep-interview",
162
+ rendered: "gjc state ultragoal handoff --to <ralplan|deep-interview> --json",
163
+ },
164
+ ],
165
+ notes: [
166
+ "When the aggregate ultragoal is complete OR the user requests return to planning/clarification, mark ultragoal ready for handoff.",
167
+ ],
168
+ },
169
+ {
170
+ skill: "team",
171
+ blockId: "state",
172
+ sourcePath: skillPath("team"),
173
+ renderOrder: 10,
174
+ markers: { start: "<!-- gjc:cmdref:start state -->", end: "<!-- gjc:cmdref:end state -->" },
175
+ commands: [stateWrite("team"), stateHandoff("team", ["ralplan", "deep-interview", "ultragoal"])],
176
+ examples: [
177
+ {
178
+ label: "handoff state write",
179
+ bytes: '```\ngjc state team write --input \'{"current_phase":"handoff"}\' --json\n```',
180
+ },
181
+ ],
182
+ aliasesAndBridges: [
183
+ {
184
+ from: "team",
185
+ to: "ralplan|deep-interview|ultragoal",
186
+ rendered: "gjc state team handoff --to <ralplan|deep-interview|ultragoal> --json",
187
+ },
188
+ ],
189
+ notes: [
190
+ "When the team task-set completes OR the user requests return to planning/persistence, mark team ready for handoff.",
191
+ ],
192
+ },
193
+ ] as const;
194
+
195
+ export function listCommandRefBlocks(skill?: CanonicalGjcWorkflowSkill): CommandRefBlock[] {
196
+ const blocks =
197
+ skill === undefined
198
+ ? WORKFLOW_COMMAND_REF_BLOCKS
199
+ : WORKFLOW_COMMAND_REF_BLOCKS.filter(block => block.skill === skill);
200
+ return [...blocks].sort(
201
+ (a, b) => a.skill.localeCompare(b.skill) || a.renderOrder - b.renderOrder || a.blockId.localeCompare(b.blockId),
202
+ );
203
+ }
204
+
205
+ export function renderCommandRefBlock(skill: CanonicalGjcWorkflowSkill, blockId = "state"): RenderedCommandRefBlock {
206
+ const block = WORKFLOW_COMMAND_REF_BLOCKS.find(item => item.skill === skill && item.blockId === blockId);
207
+ if (block === undefined) throw new Error(`Unknown command-reference block: ${skill}/${blockId}`);
208
+
209
+ const lines: string[] = [];
210
+ lines.push(block.markers.start);
211
+ lines.push(`### Generated command reference: ${block.blockId}`);
212
+ lines.push("");
213
+ for (const note of block.notes) lines.push(note);
214
+ lines.push("");
215
+ lines.push("Commands:");
216
+ for (const command of block.commands.filter(
217
+ item => item.visibility === "public" && item.includeWhen === "implemented-only",
218
+ )) {
219
+ lines.push(`- \`${command.rendered}\``);
220
+ if (command.note !== undefined) lines.push(` - ${command.note}`);
221
+ }
222
+ lines.push("");
223
+ lines.push("Examples:");
224
+ for (const example of block.examples) {
225
+ if (example.label !== undefined) lines.push(`- ${example.label}:`);
226
+ lines.push(example.bytes);
227
+ }
228
+ lines.push("");
229
+ lines.push("Aliases and bridges:");
230
+ for (const bridge of block.aliasesAndBridges) lines.push(`- ${bridge.from} -> ${bridge.to}: \`${bridge.rendered}\``);
231
+ lines.push(block.markers.end);
232
+ lines.push("");
233
+
234
+ return { skill, blockId: block.blockId, markers: block.markers, bytes: lines.join("\n") };
235
+ }
236
+
237
+ export function isCanonicalGjcWorkflowSkill(value: string): value is CanonicalGjcWorkflowSkill {
238
+ return (CANONICAL_GJC_WORKFLOW_SKILLS as readonly string[]).includes(value);
239
+ }
@@ -78,7 +78,8 @@
78
78
  "write",
79
79
  "clear",
80
80
  "contract",
81
- "handoff"
81
+ "handoff",
82
+ "doctor"
82
83
  ],
83
84
  "enumValues": [
84
85
  "deep-interview",
@@ -96,6 +97,7 @@
96
97
  "clear",
97
98
  "contract",
98
99
  "handoff",
100
+ "doctor",
99
101
  "kickoff",
100
102
  "write-spec",
101
103
  "write-artifact"
@@ -151,6 +153,26 @@
151
153
  "name": "force",
152
154
  "type": "boolean"
153
155
  },
156
+ {
157
+ "appliesToVerbs": [
158
+ "doctor"
159
+ ],
160
+ "enumValues": [
161
+ "deep-interview",
162
+ "ralplan",
163
+ "ultragoal",
164
+ "team"
165
+ ],
166
+ "name": "skill",
167
+ "type": "enum"
168
+ },
169
+ {
170
+ "appliesToVerbs": [
171
+ "doctor"
172
+ ],
173
+ "name": "json",
174
+ "type": "boolean"
175
+ },
154
176
  {
155
177
  "appliesToVerbs": [
156
178
  "kickoff"
@@ -267,6 +289,10 @@
267
289
  "name": "handoff",
268
290
  "surface": "state-action"
269
291
  },
292
+ {
293
+ "name": "doctor",
294
+ "surface": "state-action"
295
+ },
270
296
  {
271
297
  "name": "kickoff",
272
298
  "surface": "command-flag"
@@ -426,7 +452,8 @@
426
452
  "write",
427
453
  "clear",
428
454
  "contract",
429
- "handoff"
455
+ "handoff",
456
+ "doctor"
430
457
  ],
431
458
  "enumValues": [
432
459
  "deep-interview",
@@ -444,6 +471,7 @@
444
471
  "clear",
445
472
  "contract",
446
473
  "handoff",
474
+ "doctor",
447
475
  "kickoff",
448
476
  "write-spec",
449
477
  "write-artifact"
@@ -499,6 +527,26 @@
499
527
  "name": "force",
500
528
  "type": "boolean"
501
529
  },
530
+ {
531
+ "appliesToVerbs": [
532
+ "doctor"
533
+ ],
534
+ "enumValues": [
535
+ "deep-interview",
536
+ "ralplan",
537
+ "ultragoal",
538
+ "team"
539
+ ],
540
+ "name": "skill",
541
+ "type": "enum"
542
+ },
543
+ {
544
+ "appliesToVerbs": [
545
+ "doctor"
546
+ ],
547
+ "name": "json",
548
+ "type": "boolean"
549
+ },
502
550
  {
503
551
  "appliesToVerbs": [
504
552
  "kickoff"
@@ -604,6 +652,10 @@
604
652
  "name": "handoff",
605
653
  "surface": "state-action"
606
654
  },
655
+ {
656
+ "name": "doctor",
657
+ "surface": "state-action"
658
+ },
607
659
  {
608
660
  "name": "kickoff",
609
661
  "surface": "command-flag"
@@ -783,7 +835,8 @@
783
835
  "write",
784
836
  "clear",
785
837
  "contract",
786
- "handoff"
838
+ "handoff",
839
+ "doctor"
787
840
  ],
788
841
  "enumValues": [
789
842
  "deep-interview",
@@ -801,6 +854,7 @@
801
854
  "clear",
802
855
  "contract",
803
856
  "handoff",
857
+ "doctor",
804
858
  "kickoff",
805
859
  "write-spec",
806
860
  "write-artifact"
@@ -856,6 +910,26 @@
856
910
  "name": "force",
857
911
  "type": "boolean"
858
912
  },
913
+ {
914
+ "appliesToVerbs": [
915
+ "doctor"
916
+ ],
917
+ "enumValues": [
918
+ "deep-interview",
919
+ "ralplan",
920
+ "ultragoal",
921
+ "team"
922
+ ],
923
+ "name": "skill",
924
+ "type": "enum"
925
+ },
926
+ {
927
+ "appliesToVerbs": [
928
+ "doctor"
929
+ ],
930
+ "name": "json",
931
+ "type": "boolean"
932
+ },
859
933
  {
860
934
  "appliesToVerbs": [
861
935
  "start"
@@ -1010,6 +1084,10 @@
1010
1084
  "name": "handoff",
1011
1085
  "surface": "state-action"
1012
1086
  },
1087
+ {
1088
+ "name": "doctor",
1089
+ "surface": "state-action"
1090
+ },
1013
1091
  {
1014
1092
  "name": "start",
1015
1093
  "surface": "command-positional"
@@ -1196,7 +1274,8 @@
1196
1274
  "write",
1197
1275
  "clear",
1198
1276
  "contract",
1199
- "handoff"
1277
+ "handoff",
1278
+ "doctor"
1200
1279
  ],
1201
1280
  "enumValues": [
1202
1281
  "deep-interview",
@@ -1214,6 +1293,7 @@
1214
1293
  "clear",
1215
1294
  "contract",
1216
1295
  "handoff",
1296
+ "doctor",
1217
1297
  "kickoff",
1218
1298
  "write-spec",
1219
1299
  "write-artifact"
@@ -1269,6 +1349,26 @@
1269
1349
  "name": "force",
1270
1350
  "type": "boolean"
1271
1351
  },
1352
+ {
1353
+ "appliesToVerbs": [
1354
+ "doctor"
1355
+ ],
1356
+ "enumValues": [
1357
+ "deep-interview",
1358
+ "ralplan",
1359
+ "ultragoal",
1360
+ "team"
1361
+ ],
1362
+ "name": "skill",
1363
+ "type": "enum"
1364
+ },
1365
+ {
1366
+ "appliesToVerbs": [
1367
+ "doctor"
1368
+ ],
1369
+ "name": "json",
1370
+ "type": "boolean"
1371
+ },
1272
1372
  {
1273
1373
  "appliesToVerbs": [
1274
1374
  "create-goals"
@@ -1444,6 +1544,10 @@
1444
1544
  "name": "handoff",
1445
1545
  "surface": "state-action"
1446
1546
  },
1547
+ {
1548
+ "name": "doctor",
1549
+ "surface": "state-action"
1550
+ },
1447
1551
  {
1448
1552
  "name": "status",
1449
1553
  "surface": "command-positional"
@@ -64,7 +64,7 @@ const AGENTS_RETENTION: RetentionPolicy = { category: "agents" };
64
64
  const PRUNE_RETENTION: RetentionPolicy = { category: "prune/delete", maxAgeDays: 30 };
65
65
  const FORCE_RETENTION: RetentionPolicy = { category: "force", maxAgeDays: 90 };
66
66
 
67
- const STATE_VERBS = ["read", "write", "clear", "contract", "handoff"] as const;
67
+ const STATE_VERBS = ["read", "write", "clear", "contract", "handoff", "doctor"] as const;
68
68
  const PLANNED_ADMIN_VERBS = ["graph", "prune", "migrate", "force-overwrite"] as const;
69
69
 
70
70
  const COMMON_TYPED_ARGS: TypedArgSpec[] = [
@@ -82,6 +82,8 @@ const COMMON_TYPED_ARGS: TypedArgSpec[] = [
82
82
  },
83
83
  { name: "replace", type: "boolean", appliesToVerbs: ["write"] },
84
84
  { name: "force", type: "boolean", appliesToVerbs: ["write", "clear", "handoff"] },
85
+ { name: "skill", type: "enum", enumValues: [...CANONICAL_GJC_WORKFLOW_SKILLS], appliesToVerbs: ["doctor"] },
86
+ { name: "json", type: "boolean", appliesToVerbs: ["doctor"] },
85
87
  ];
86
88
 
87
89
  function verb(name: string, surface: WorkflowVerb["surface"]): WorkflowVerb {