@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.
- package/CHANGELOG.md +18 -0
- package/dist/types/async/job-manager.d.ts +7 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +4 -4
- package/dist/types/debug/crash-diagnostics.d.ts +45 -0
- package/dist/types/debug/runtime-gauges.d.ts +6 -0
- package/dist/types/deep-interview/render-middleware.d.ts +1 -0
- package/dist/types/eval/py/executor.d.ts +2 -0
- package/dist/types/eval/py/kernel.d.ts +2 -0
- package/dist/types/exec/bash-executor.d.ts +10 -0
- package/dist/types/gjc-runtime/cli-write-receipt.d.ts +24 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -0
- package/dist/types/gjc-runtime/state-migrations.d.ts +9 -0
- package/dist/types/gjc-runtime/state-schema.d.ts +317 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +10 -0
- package/dist/types/gjc-runtime/workflow-command-ref.d.ts +43 -0
- package/dist/types/harness-control-plane/control-endpoint.d.ts +3 -2
- package/dist/types/hooks/skill-state.d.ts +21 -0
- package/dist/types/internal-urls/agent-protocol.d.ts +2 -2
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
- package/dist/types/internal-urls/registry-helpers.d.ts +8 -7
- package/dist/types/internal-urls/types.d.ts +4 -0
- package/dist/types/lsp/index.d.ts +10 -10
- package/dist/types/modes/bridge/auth.d.ts +12 -0
- package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
- package/dist/types/modes/bridge/bridge-mode.d.ts +44 -0
- package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
- package/dist/types/modes/bridge/event-stream.d.ts +8 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -0
- package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
- package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/status-line.d.ts +2 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +8 -0
- package/dist/types/modes/index.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/jobs-observer.d.ts +57 -0
- package/dist/types/modes/rpc/host-tools.d.ts +1 -16
- package/dist/types/modes/rpc/host-uris.d.ts +1 -38
- package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +20 -0
- package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +24 -0
- package/dist/types/modes/shared/agent-wire/handshake.d.ts +46 -0
- package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
- package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
- package/dist/types/modes/shared/agent-wire/protocol.d.ts +44 -0
- package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
- package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
- package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
- package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/sdk.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +11 -1
- package/dist/types/skill-state/workflow-state-contract.d.ts +1 -2
- package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
- package/dist/types/task/id.d.ts +7 -0
- package/dist/types/task/index.d.ts +5 -0
- package/dist/types/task/receipt.d.ts +85 -0
- package/dist/types/task/spawn-gate.d.ts +38 -0
- package/dist/types/task/types.d.ts +143 -11
- package/dist/types/tools/cron.d.ts +6 -0
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/subagent.d.ts +15 -0
- package/package.json +7 -7
- package/scripts/build-binary.ts +7 -0
- package/src/async/job-manager.ts +36 -0
- package/src/cli/args.ts +9 -2
- package/src/commands/deep-interview.ts +1 -0
- package/src/commands/harness.ts +289 -19
- package/src/commands/launch.ts +2 -2
- package/src/commands/state.ts +2 -1
- package/src/commands/team.ts +22 -4
- package/src/config/keybindings.ts +6 -0
- package/src/config/settings-schema.ts +6 -3
- package/src/dap/client.ts +17 -3
- package/src/debug/crash-diagnostics.ts +223 -0
- package/src/debug/runtime-gauges.ts +20 -0
- package/src/deep-interview/render-middleware.ts +6 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ralplan/SKILL.md +31 -2
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +28 -2
- package/src/eval/py/executor.ts +21 -1
- package/src/eval/py/kernel.ts +15 -0
- package/src/exec/bash-executor.ts +41 -0
- package/src/gjc-runtime/cli-write-receipt.ts +31 -0
- package/src/gjc-runtime/deep-interview-runtime.ts +69 -32
- package/src/gjc-runtime/ralplan-runtime.ts +213 -36
- package/src/gjc-runtime/state-migrations.ts +54 -7
- package/src/gjc-runtime/state-runtime.ts +461 -64
- package/src/gjc-runtime/state-schema.ts +192 -0
- package/src/gjc-runtime/state-writer.ts +32 -1
- package/src/gjc-runtime/team-runtime.ts +177 -105
- package/src/gjc-runtime/ultragoal-runtime.ts +114 -26
- package/src/gjc-runtime/workflow-command-ref.ts +239 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +108 -4
- package/src/gjc-runtime/workflow-manifest.ts +3 -1
- package/src/harness-control-plane/control-endpoint.ts +19 -8
- package/src/harness-control-plane/owner.ts +57 -10
- package/src/harness-control-plane/state-machine.ts +2 -1
- package/src/hooks/skill-state.ts +176 -26
- package/src/internal-urls/agent-protocol.ts +68 -21
- package/src/internal-urls/artifact-protocol.ts +12 -17
- package/src/internal-urls/docs-index.generated.ts +3 -2
- package/src/internal-urls/registry-helpers.ts +19 -16
- package/src/internal-urls/types.ts +4 -0
- package/src/lsp/client.ts +18 -2
- package/src/main.ts +21 -5
- package/src/modes/bridge/auth.ts +41 -0
- package/src/modes/bridge/bridge-client-bridge.ts +47 -0
- package/src/modes/bridge/bridge-mode.ts +520 -0
- package/src/modes/bridge/bridge-ui-context.ts +200 -0
- package/src/modes/bridge/event-stream.ts +70 -0
- package/src/modes/components/custom-editor.ts +101 -0
- package/src/modes/components/hook-selector.ts +61 -18
- package/src/modes/components/jobs-overlay-model.ts +109 -0
- package/src/modes/components/jobs-overlay.ts +172 -0
- package/src/modes/components/status-line/presets.ts +7 -5
- package/src/modes/components/status-line/segments.ts +25 -0
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/status-line.ts +9 -1
- package/src/modes/controllers/extension-ui-controller.ts +39 -3
- package/src/modes/controllers/input-controller.ts +97 -9
- package/src/modes/controllers/selector-controller.ts +29 -0
- package/src/modes/index.ts +1 -0
- package/src/modes/interactive-mode.ts +27 -0
- package/src/modes/jobs-observer.ts +204 -0
- package/src/modes/rpc/host-tools.ts +1 -186
- package/src/modes/rpc/host-uris.ts +1 -235
- package/src/modes/rpc/rpc-client.ts +25 -10
- package/src/modes/rpc/rpc-mode.ts +12 -381
- package/src/modes/shared/agent-wire/command-dispatch.ts +341 -0
- package/src/modes/shared/agent-wire/command-validation.ts +131 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +108 -0
- package/src/modes/shared/agent-wire/handshake.ts +117 -0
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +194 -0
- package/src/modes/shared/agent-wire/host-uri-bridge.ts +236 -0
- package/src/modes/shared/agent-wire/protocol.ts +96 -0
- package/src/modes/shared/agent-wire/responses.ts +17 -0
- package/src/modes/shared/agent-wire/scopes.ts +89 -0
- package/src/modes/shared/agent-wire/ui-request-broker.ts +150 -0
- package/src/modes/shared/agent-wire/ui-result.ts +48 -0
- package/src/modes/types.ts +1 -0
- package/src/prompts/tools/subagent.md +12 -7
- package/src/prompts/tools/task-summary.md +3 -9
- package/src/prompts/tools/task.md +5 -1
- package/src/sdk.ts +4 -0
- package/src/session/agent-session.ts +214 -38
- package/src/skill-state/deep-interview-mutation-guard.ts +23 -4
- package/src/skill-state/workflow-state-contract.ts +7 -4
- package/src/skill-state/workflow-state-version.ts +3 -0
- package/src/slash-commands/builtin-registry.ts +8 -0
- package/src/task/executor.ts +29 -5
- package/src/task/id.ts +33 -0
- package/src/task/index.ts +257 -67
- package/src/task/output-manager.ts +5 -4
- package/src/task/receipt.ts +297 -0
- package/src/task/render.ts +48 -131
- package/src/task/spawn-gate.ts +132 -0
- package/src/task/types.ts +48 -7
- package/src/tools/ask.ts +73 -33
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash.ts +1 -1
- package/src/tools/cron.ts +48 -0
- package/src/tools/find.ts +4 -1
- package/src/tools/index.ts +2 -0
- package/src/tools/path-utils.ts +3 -2
- package/src/tools/read.ts +1 -0
- package/src/tools/search.ts +1 -0
- package/src/tools/skill.ts +6 -1
- 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
|
|
478
|
-
|
|
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
|
|
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)
|
|
1240
|
-
|
|
1241
|
-
|
|
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
|
-
`
|
|
1244
|
-
`
|
|
1245
|
-
`
|
|
1246
|
-
|
|
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
|
-
?
|
|
1268
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 {
|