owlrunkit 0.17.1 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.md +105 -14
- package/docs/architecture/OWLCODA_RUNKIT_017_AGENT_NATIVE_PRODUCT_DEFINITION.md +2 -3
- package/docs/architecture/OWLCODA_RUNKIT_018_PROJECT_DRIVER_PRODUCT_DEFINITION.md +165 -0
- package/integrations/codex/skills/owlcoda-runkit/SKILL.md +93 -14
- package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
- package/package.json +2 -2
- package/packages/attest/distribution-manifest-v1.json +10 -0
- package/packages/attest/src/quick.mjs +10 -0
- package/registry-release-policy-v1.json +5 -5
- package/sbom.spdx.json +5 -5
- package/scripts/runkit-contract/core-contract.mjs +3 -1
- package/scripts/runkit-contract/human-status.mjs +49 -0
- package/scripts/runkit-contract/inspect-presentation.mjs +58 -12
- package/scripts/runkit-contract/onboarding-doctor.mjs +34 -10
- package/scripts/runkit-contract/project-cli-resolver.mjs +6 -0
- package/scripts/runkit-contract/project-control-parser.mjs +17 -0
- package/scripts/runkit-contract/runkit-cli.mjs +568 -21
- package/scripts/runkit-contract/schemas/team-project-event-v1.schema.json +16 -1
- package/scripts/runkit-contract/schemas/team-project-status-v1.schema.json +34 -1
- package/scripts/runkit-contract/schemas/team-project-successor-receipt-v1.schema.json +204 -0
- package/scripts/runkit-contract/team-project-successor.mjs +1176 -0
- package/scripts/runkit-contract/team-project.mjs +1082 -43
|
@@ -138,11 +138,24 @@ import {
|
|
|
138
138
|
import { OFFICIAL_NPM_REGISTRY } from "./registry-adoption-gate.mjs";
|
|
139
139
|
import {
|
|
140
140
|
appendTeamProjectEventV1,
|
|
141
|
+
assignTeamProjectV1,
|
|
141
142
|
buildTeamProjectTakeoverV1,
|
|
143
|
+
checkpointTeamProjectV1,
|
|
144
|
+
closeTeamProjectVerificationV1,
|
|
145
|
+
deferTeamProjectVerificationV1,
|
|
142
146
|
formatTeamProjectStatusHumanV1,
|
|
147
|
+
formatTeamProjectTakeoverHumanV1,
|
|
148
|
+
handoffTeamProjectV1,
|
|
143
149
|
initializeTeamProjectV1,
|
|
150
|
+
integrateTeamProjectV1,
|
|
151
|
+
openTeamProjectDecisionV1,
|
|
144
152
|
readTeamProjectStatusV1,
|
|
153
|
+
resolveTeamProjectDecisionV1,
|
|
145
154
|
} from "./team-project.mjs";
|
|
155
|
+
import {
|
|
156
|
+
formatTeamProjectSuccessorHumanV1,
|
|
157
|
+
successorTeamProjectV1,
|
|
158
|
+
} from "./team-project-successor.mjs";
|
|
146
159
|
|
|
147
160
|
const TOP_LEVEL_HELP = `OwlRunKit ${CORE_VERSION}
|
|
148
161
|
|
|
@@ -179,7 +192,7 @@ Fleet and status
|
|
|
179
192
|
owlrunkit fleet discover; owlrunkit status --workspace .
|
|
180
193
|
|
|
181
194
|
Agent team projects
|
|
182
|
-
owlrunkit project <init|assign|checkpoint|handoff|decision|capture|status|takeover> [options]
|
|
195
|
+
owlrunkit project <init|assign|checkpoint|handoff|decision|verification|capture|status|takeover|successor> [options]
|
|
183
196
|
Durable Agent work, dependencies, decisions, gates, progress, and handoffs.
|
|
184
197
|
Core successor
|
|
185
198
|
owlrunkit core-successor <plan|apply|resume> --workspace . [...]
|
|
@@ -340,9 +353,35 @@ action without granting any authority.
|
|
|
340
353
|
`,
|
|
341
354
|
project: `Usage:
|
|
342
355
|
owlrunkit project init --workspace <directory> --definition <project.json>
|
|
343
|
-
owlrunkit project
|
|
356
|
+
owlrunkit project assign --workspace <directory> --assignment-id <id> --at <ISO-UTC> --work-item <id> --agent <id>
|
|
357
|
+
[--supersedes <current-assignment-id>] [--execution-run-id <id> --execution-work-item <id>] [--json]
|
|
358
|
+
owlrunkit project handoff --workspace <directory> --handoff-id <id> --at <ISO-UTC>
|
|
359
|
+
--assignment-id <current> --work-item <id> --from-agent <id> --to-agent <id>
|
|
360
|
+
--summary <text> --next <text> --evidence <ref> [--evidence <ref> ...] [--json]
|
|
361
|
+
owlrunkit project decision --workspace <directory> --open --decision-id <id> --at <ISO-UTC>
|
|
362
|
+
--title <text> --question <text> --owner-agent <id>
|
|
363
|
+
[--blocking-work-item <id> ...] --option <text> [--option <text> ...] [--json]
|
|
364
|
+
owlrunkit project decision --workspace <directory> --resolve --decision-id <id> --at <ISO-UTC>
|
|
365
|
+
--resolution <text> --rationale <text> --evidence <ref> [--evidence <ref> ...] [--json]
|
|
366
|
+
owlrunkit project checkpoint --workspace <directory> --checkpoint-id <id> --at <ISO-UTC>
|
|
367
|
+
--assignment-id <current> --work-item <id>
|
|
368
|
+
--state <active|waiting_dependency|waiting_decision|verifying|ready_to_integrate|completed|failed>
|
|
369
|
+
--summary <text> [--completed-units <nonnegative-int>]
|
|
370
|
+
[--evidence <ref> ...] [--blocker <ref> ...] [--decision <id> ...]
|
|
371
|
+
[--next <text>] [--source-fingerprint <sha256>] [--json]
|
|
372
|
+
owlrunkit project verification --workspace <directory> --defer --verification-id <id> --at <ISO-UTC>
|
|
373
|
+
--work-item <id> --owner-agent <id> --check <check-id> [--check <check-id> ...]
|
|
374
|
+
--reason <text> --due-gate <gate-id> [--json]
|
|
375
|
+
owlrunkit project verification --workspace <directory> --close --verification-id <id> --at <ISO-UTC>
|
|
376
|
+
--disposition <verified|no_longer_required> --summary <text>
|
|
377
|
+
[--evidence <ref> ...] [--decision <resolved-decision-id> ...] [--json]
|
|
378
|
+
owlrunkit project integrate --workspace <directory> --gate <gate-id> --at <ISO-UTC>
|
|
379
|
+
--summary <text> --evidence <ref> [--evidence <ref> ...] [--json]
|
|
380
|
+
owlrunkit project <checkpoint|handoff|decision|verification|integrate|capture> --workspace <directory> --request <event.json>
|
|
344
381
|
owlrunkit project status --workspace <directory> [--json]
|
|
345
382
|
owlrunkit project takeover --workspace <directory> --agent <id> [--json]
|
|
383
|
+
owlrunkit project successor --workspace <directory> --transition-id <id> --at <ISO-UTC>
|
|
384
|
+
--definition <project.json> --reason <text> [--json]
|
|
346
385
|
|
|
347
386
|
Project status is derived from durable work items, Agent assignments,
|
|
348
387
|
dependencies, decisions, checkpoints, integration gates, and evidence refs.
|
|
@@ -355,6 +394,13 @@ No self-reported percentage is accepted.
|
|
|
355
394
|
owlrunkit project takeover --workspace <directory> --agent <id> [--json]
|
|
356
395
|
|
|
357
396
|
Builds a read-only blank-session recovery packet for one Agent.
|
|
397
|
+
`,
|
|
398
|
+
"project successor": `Usage:
|
|
399
|
+
owlrunkit project successor --workspace <directory> --transition-id <id> --at <ISO-UTC>
|
|
400
|
+
--definition <project.json> --reason <text> [--json]
|
|
401
|
+
|
|
402
|
+
Archives one derived-completed active project and installs one fresh active
|
|
403
|
+
project with no inherited events. The receipt grants no repository or release authority.
|
|
358
404
|
`,
|
|
359
405
|
});
|
|
360
406
|
|
|
@@ -368,13 +414,100 @@ function withHumanOutput(result, humanOutput) {
|
|
|
368
414
|
return result;
|
|
369
415
|
}
|
|
370
416
|
|
|
417
|
+
function formatTeamProjectAssignmentHuman(result) {
|
|
418
|
+
const disposition = result.resumed ? "Resumed" : "Assigned";
|
|
419
|
+
const nextAction = result.nextAction === null
|
|
420
|
+
? "none"
|
|
421
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
422
|
+
return [
|
|
423
|
+
`${disposition} WorkItem ${result.workItemId} to Agent ${result.agentId}.`,
|
|
424
|
+
`Project next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
425
|
+
`Assignment: ${result.assignmentId}`,
|
|
426
|
+
"",
|
|
427
|
+
].join("\n");
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function formatTeamProjectHandoffHuman(result) {
|
|
431
|
+
const disposition = result.resumed ? "Resumed" : "Handed off";
|
|
432
|
+
const targetNextAction = result.targetNextAction === null
|
|
433
|
+
? "none"
|
|
434
|
+
: String(result.targetNextAction).replace(/\s+/gu, " ").trim();
|
|
435
|
+
const projectNextAction = result.nextAction === null
|
|
436
|
+
? "none"
|
|
437
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
438
|
+
return [
|
|
439
|
+
`${disposition} WorkItem ${result.workItemId} from Agent ${result.fromAgentId} to Agent ${result.toAgentId}.`,
|
|
440
|
+
`Target next: ${targetNextAction}`,
|
|
441
|
+
`Project next: ${projectNextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
442
|
+
`Handoff: ${result.handoffId}`,
|
|
443
|
+
"",
|
|
444
|
+
].join("\n");
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function formatTeamProjectDecisionHuman(result) {
|
|
448
|
+
const disposition = result.resumed
|
|
449
|
+
? "Resumed"
|
|
450
|
+
: result.operation === "opened" ? "Opened" : "Resolved";
|
|
451
|
+
const owner = result.ownerAgentId ? ` for Agent ${result.ownerAgentId}` : "";
|
|
452
|
+
const nextAction = result.nextAction === null
|
|
453
|
+
? "none"
|
|
454
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
455
|
+
return [
|
|
456
|
+
`${disposition} decision ${result.decisionId}${owner}.`,
|
|
457
|
+
`Project next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
458
|
+
`Decision: ${result.decisionId}`,
|
|
459
|
+
"",
|
|
460
|
+
].join("\n");
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function formatTeamProjectVerificationHuman(result) {
|
|
464
|
+
const disposition = result.resumed
|
|
465
|
+
? "Resumed"
|
|
466
|
+
: result.operation === "deferred" ? "Deferred" : "Closed";
|
|
467
|
+
const nextAction = result.nextAction === null
|
|
468
|
+
? "none"
|
|
469
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
470
|
+
return [
|
|
471
|
+
`${disposition} project verification ${result.verificationId}: ${result.verificationStatus}.`,
|
|
472
|
+
`Due gate: ${result.dueGateId}; gate state: ${result.gateStatus}.`,
|
|
473
|
+
`Project state: ${result.overall}; next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
474
|
+
"No verification command, Git, or release action was performed.",
|
|
475
|
+
"",
|
|
476
|
+
].join("\n");
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function formatTeamProjectIntegrationHuman(result) {
|
|
480
|
+
const disposition = result.resumed ? "Resumed" : "Passed";
|
|
481
|
+
const nextAction = result.nextAction === null
|
|
482
|
+
? "none"
|
|
483
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
484
|
+
return [
|
|
485
|
+
`${disposition} project integration gate ${result.gateId}.`,
|
|
486
|
+
`Project state: ${result.overall}; next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
487
|
+
"Git/release not performed.",
|
|
488
|
+
"",
|
|
489
|
+
].join("\n");
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function formatTeamProjectCheckpointHuman(result) {
|
|
493
|
+
const disposition = result.resumed ? "Resumed" : "Recorded";
|
|
494
|
+
const nextAction = result.nextAction === null
|
|
495
|
+
? "none"
|
|
496
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
497
|
+
return [
|
|
498
|
+
`${disposition} checkpoint ${result.checkpointId} for WorkItem ${result.workItemId}: ${result.state}.`,
|
|
499
|
+
`Project state: ${result.overall}; next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
500
|
+
"",
|
|
501
|
+
].join("\n");
|
|
502
|
+
}
|
|
503
|
+
|
|
371
504
|
function profilesReadiness(root) {
|
|
372
505
|
if (!root) return { valid: false, launcherWarnings: [] };
|
|
373
506
|
try {
|
|
374
507
|
const validation = validateProfiles({ workspaceRoot: root });
|
|
375
508
|
const launchers = readProfileLauncherReadiness({ workspaceRoot: root });
|
|
376
509
|
return {
|
|
377
|
-
valid: validation.valid === true && launchers.
|
|
510
|
+
valid: validation.valid === true && launchers.status === "ok",
|
|
378
511
|
launcherWarnings: launchers.launcherWarnings,
|
|
379
512
|
};
|
|
380
513
|
} catch {
|
|
@@ -389,8 +522,17 @@ function onboardingProjection(root, recovery = null) {
|
|
|
389
522
|
: { status: "missing" };
|
|
390
523
|
const profilesReady = profiles.valid;
|
|
391
524
|
const adoptionReady = adoption.status === "ok";
|
|
525
|
+
const maintenanceNextAction = profiles.launcherWarnings.length > 0
|
|
526
|
+
? "review_profile_launchers"
|
|
527
|
+
: null;
|
|
392
528
|
if (profilesReady && adoptionReady) {
|
|
393
529
|
return {
|
|
530
|
+
...(maintenanceNextAction
|
|
531
|
+
? {
|
|
532
|
+
status: "completed_with_maintenance_warnings",
|
|
533
|
+
maintenanceNextAction,
|
|
534
|
+
}
|
|
535
|
+
: {}),
|
|
394
536
|
nextAllowedAction: recovery?.nextAllowedAction ?? "plan_new_execution",
|
|
395
537
|
completed: true,
|
|
396
538
|
steps: [],
|
|
@@ -402,12 +544,7 @@ function onboardingProjection(root, recovery = null) {
|
|
|
402
544
|
command: "owlrunkit doctor --workspace .",
|
|
403
545
|
},
|
|
404
546
|
...(!profilesReady
|
|
405
|
-
?
|
|
406
|
-
? [{
|
|
407
|
-
id: "profile_launchers_review",
|
|
408
|
-
command: "owlrunkit doctor --workspace .",
|
|
409
|
-
}]
|
|
410
|
-
: [{
|
|
547
|
+
? [{
|
|
411
548
|
id: "profiles_detect",
|
|
412
549
|
command: "owlrunkit profiles detect --workspace . --dry-run",
|
|
413
550
|
}]
|
|
@@ -421,6 +558,7 @@ function onboardingProjection(root, recovery = null) {
|
|
|
421
558
|
];
|
|
422
559
|
return {
|
|
423
560
|
nextAllowedAction: "run_onboarding_diagnostics",
|
|
561
|
+
...(maintenanceNextAction ? { maintenanceNextAction } : {}),
|
|
424
562
|
completed: false,
|
|
425
563
|
steps,
|
|
426
564
|
};
|
|
@@ -460,6 +598,30 @@ function requireOption(options, name) {
|
|
|
460
598
|
return value;
|
|
461
599
|
}
|
|
462
600
|
|
|
601
|
+
function assertOnlyOptions(options, allowedNames) {
|
|
602
|
+
const allowed = new Set(allowedNames);
|
|
603
|
+
const unsupported = Object.keys(options)
|
|
604
|
+
.filter(name => !allowed.has(name))
|
|
605
|
+
.sort();
|
|
606
|
+
if (unsupported.length > 0) {
|
|
607
|
+
throw new Error(
|
|
608
|
+
`Unsupported option${unsupported.length === 1 ? "" : "s"}: `
|
|
609
|
+
+ unsupported.map(name => `--${name}`).join(", "),
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
function parseCanonicalNonnegativeSafeInteger(value, label) {
|
|
615
|
+
if (typeof value !== "string" || !/^(?:0|[1-9]\d*)$/u.test(value)) {
|
|
616
|
+
throw new Error(`--${label} must be a canonical non-negative safe integer.`);
|
|
617
|
+
}
|
|
618
|
+
const parsed = Number(value);
|
|
619
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
620
|
+
throw new Error(`--${label} must be a canonical non-negative safe integer.`);
|
|
621
|
+
}
|
|
622
|
+
return parsed;
|
|
623
|
+
}
|
|
624
|
+
|
|
463
625
|
function readWorkspaceArtifact(root, value, label) {
|
|
464
626
|
const relativePath = safeRelativePath(value, label);
|
|
465
627
|
return readJson(realpathSync(path.join(root, relativePath)));
|
|
@@ -1387,7 +1549,10 @@ function inspect(options) {
|
|
|
1387
1549
|
if (requestedRunId && !executions.some(execution => execution.runId === requestedRunId)) {
|
|
1388
1550
|
throw new Error(`Execution was not found: ${requestedRunId}`);
|
|
1389
1551
|
}
|
|
1390
|
-
const
|
|
1552
|
+
const onboarding = onboardingProjection(root, recovery);
|
|
1553
|
+
const summary = buildInspectSummary(result, {
|
|
1554
|
+
maintenanceNextAction: onboarding.maintenanceNextAction ?? null,
|
|
1555
|
+
});
|
|
1391
1556
|
const view = options.history
|
|
1392
1557
|
? { mode: "history" }
|
|
1393
1558
|
: requestedRunId
|
|
@@ -1398,7 +1563,7 @@ function inspect(options) {
|
|
|
1398
1563
|
execution: executions.find(execution => execution.runId === requestedRunId),
|
|
1399
1564
|
}
|
|
1400
1565
|
: { mode: "summary" };
|
|
1401
|
-
return { ...result, summary, view, onboarding
|
|
1566
|
+
return { ...result, summary, view, onboarding };
|
|
1402
1567
|
}
|
|
1403
1568
|
|
|
1404
1569
|
function closeout(options) {
|
|
@@ -1650,12 +1815,26 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
1650
1815
|
|| command === "start"
|
|
1651
1816
|
|| (command === "formal" && action === "start")
|
|
1652
1817
|
? ["owned-path"]
|
|
1818
|
+
: command === "project" && action === "handoff"
|
|
1819
|
+
? ["evidence"]
|
|
1820
|
+
: command === "project" && action === "integrate"
|
|
1821
|
+
? ["evidence"]
|
|
1822
|
+
: command === "project" && action === "verification"
|
|
1823
|
+
? ["check", "evidence", "decision"]
|
|
1824
|
+
: command === "project" && action === "checkpoint"
|
|
1825
|
+
? ["evidence", "blocker", "decision"]
|
|
1826
|
+
: command === "project" && action === "decision"
|
|
1827
|
+
? ["blocking-work-item", "option", "evidence"]
|
|
1653
1828
|
: [],
|
|
1654
1829
|
boolean: command === "inspect"
|
|
1655
1830
|
? ["json", "verbose", "history"]
|
|
1656
1831
|
: command === "init"
|
|
1657
1832
|
? ["json"]
|
|
1658
|
-
: command === "project" &&
|
|
1833
|
+
: command === "project" && action === "decision"
|
|
1834
|
+
? ["json", "open", "resolve"]
|
|
1835
|
+
: command === "project" && action === "verification"
|
|
1836
|
+
? ["json", "defer", "close"]
|
|
1837
|
+
: command === "project" && new Set(["assign", "handoff", "checkpoint", "integrate", "status", "takeover", "successor"]).has(action)
|
|
1659
1838
|
? ["json"]
|
|
1660
1839
|
: command === "doctor" || command === "adopt" || command === "status"
|
|
1661
1840
|
? ["json"]
|
|
@@ -2405,6 +2584,40 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2405
2584
|
);
|
|
2406
2585
|
}
|
|
2407
2586
|
if (command === "project") {
|
|
2587
|
+
const allowedProjectOptions = {
|
|
2588
|
+
init: ["workspace", "definition"],
|
|
2589
|
+
assign: [
|
|
2590
|
+
"workspace", "request", "assignment-id", "at", "work-item", "agent",
|
|
2591
|
+
"supersedes", "execution-run-id", "execution-work-item", "json",
|
|
2592
|
+
],
|
|
2593
|
+
handoff: [
|
|
2594
|
+
"workspace", "request", "handoff-id", "at", "assignment-id", "work-item",
|
|
2595
|
+
"from-agent", "to-agent", "summary", "next", "evidence", "json",
|
|
2596
|
+
],
|
|
2597
|
+
decision: [
|
|
2598
|
+
"workspace", "request", "open", "resolve", "decision-id", "at", "title",
|
|
2599
|
+
"question", "owner-agent", "blocking-work-item", "option", "resolution",
|
|
2600
|
+
"rationale", "evidence", "json",
|
|
2601
|
+
],
|
|
2602
|
+
checkpoint: [
|
|
2603
|
+
"workspace", "request", "checkpoint-id", "at", "assignment-id", "work-item",
|
|
2604
|
+
"state", "summary", "completed-units", "evidence", "blocker", "decision",
|
|
2605
|
+
"next", "source-fingerprint", "json",
|
|
2606
|
+
],
|
|
2607
|
+
verification: [
|
|
2608
|
+
"workspace", "request", "defer", "close", "verification-id", "at",
|
|
2609
|
+
"work-item", "owner-agent", "check", "reason", "due-gate",
|
|
2610
|
+
"disposition", "summary", "evidence", "decision", "json",
|
|
2611
|
+
],
|
|
2612
|
+
integrate: ["workspace", "request", "gate", "at", "summary", "evidence", "json"],
|
|
2613
|
+
capture: ["workspace", "request"],
|
|
2614
|
+
status: ["workspace", "json"],
|
|
2615
|
+
takeover: ["workspace", "agent", "json"],
|
|
2616
|
+
successor: ["workspace", "transition-id", "at", "definition", "reason", "json"],
|
|
2617
|
+
};
|
|
2618
|
+
if (Object.hasOwn(allowedProjectOptions, action)) {
|
|
2619
|
+
assertOnlyOptions(options, allowedProjectOptions[action]);
|
|
2620
|
+
}
|
|
2408
2621
|
const root = requireOption(options, "workspace");
|
|
2409
2622
|
if (action === "init") {
|
|
2410
2623
|
return initializeTeamProjectV1({
|
|
@@ -2412,7 +2625,334 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2412
2625
|
definition: readJson(realpathSync(requireOption(options, "definition"))),
|
|
2413
2626
|
});
|
|
2414
2627
|
}
|
|
2415
|
-
if (
|
|
2628
|
+
if (action === "assign") {
|
|
2629
|
+
const directAssignmentFields = [
|
|
2630
|
+
"assignment-id",
|
|
2631
|
+
"at",
|
|
2632
|
+
"work-item",
|
|
2633
|
+
"agent",
|
|
2634
|
+
"supersedes",
|
|
2635
|
+
"execution-run-id",
|
|
2636
|
+
"execution-work-item",
|
|
2637
|
+
];
|
|
2638
|
+
const hasDirectAssignmentFields = directAssignmentFields.some(
|
|
2639
|
+
name => options[name] !== undefined,
|
|
2640
|
+
);
|
|
2641
|
+
if (options.request !== undefined && hasDirectAssignmentFields) {
|
|
2642
|
+
throw new Error("--request cannot be combined with direct assignment fields.");
|
|
2643
|
+
}
|
|
2644
|
+
if (options.request !== undefined) {
|
|
2645
|
+
return appendTeamProjectEventV1({
|
|
2646
|
+
workspaceRoot: root,
|
|
2647
|
+
event: readJson(realpathSync(requireOption(options, "request"))),
|
|
2648
|
+
});
|
|
2649
|
+
}
|
|
2650
|
+
const assigned = assignTeamProjectV1({
|
|
2651
|
+
workspaceRoot: root,
|
|
2652
|
+
assignmentId: options["assignment-id"],
|
|
2653
|
+
occurredAt: options.at,
|
|
2654
|
+
workItemId: options["work-item"],
|
|
2655
|
+
agentId: options.agent,
|
|
2656
|
+
supersedesAssignmentId: options.supersedes,
|
|
2657
|
+
executionRunId: options["execution-run-id"],
|
|
2658
|
+
executionWorkItemId: options["execution-work-item"],
|
|
2659
|
+
});
|
|
2660
|
+
return options.json === true
|
|
2661
|
+
? assigned
|
|
2662
|
+
: withHumanOutput(assigned, formatTeamProjectAssignmentHuman(assigned));
|
|
2663
|
+
}
|
|
2664
|
+
if (action === "handoff") {
|
|
2665
|
+
const directHandoffFields = [
|
|
2666
|
+
"handoff-id",
|
|
2667
|
+
"at",
|
|
2668
|
+
"assignment-id",
|
|
2669
|
+
"work-item",
|
|
2670
|
+
"from-agent",
|
|
2671
|
+
"to-agent",
|
|
2672
|
+
"summary",
|
|
2673
|
+
"next",
|
|
2674
|
+
"evidence",
|
|
2675
|
+
];
|
|
2676
|
+
const hasDirectHandoffFields = directHandoffFields.some(
|
|
2677
|
+
name => options[name] !== undefined,
|
|
2678
|
+
);
|
|
2679
|
+
if (options.request !== undefined && hasDirectHandoffFields) {
|
|
2680
|
+
throw new Error("--request cannot be combined with direct handoff fields.");
|
|
2681
|
+
}
|
|
2682
|
+
if (options.request !== undefined) {
|
|
2683
|
+
return appendTeamProjectEventV1({
|
|
2684
|
+
workspaceRoot: root,
|
|
2685
|
+
event: readJson(realpathSync(requireOption(options, "request"))),
|
|
2686
|
+
});
|
|
2687
|
+
}
|
|
2688
|
+
const handedOff = handoffTeamProjectV1({
|
|
2689
|
+
workspaceRoot: root,
|
|
2690
|
+
handoffId: options["handoff-id"],
|
|
2691
|
+
occurredAt: options.at,
|
|
2692
|
+
assignmentId: options["assignment-id"],
|
|
2693
|
+
workItemId: options["work-item"],
|
|
2694
|
+
fromAgentId: options["from-agent"],
|
|
2695
|
+
toAgentId: options["to-agent"],
|
|
2696
|
+
summary: options.summary,
|
|
2697
|
+
nextAction: options.next,
|
|
2698
|
+
evidenceRefs: options.evidence,
|
|
2699
|
+
});
|
|
2700
|
+
return options.json === true
|
|
2701
|
+
? handedOff
|
|
2702
|
+
: withHumanOutput(handedOff, formatTeamProjectHandoffHuman(handedOff));
|
|
2703
|
+
}
|
|
2704
|
+
if (action === "decision") {
|
|
2705
|
+
const directDecisionFields = [
|
|
2706
|
+
"open",
|
|
2707
|
+
"resolve",
|
|
2708
|
+
"decision-id",
|
|
2709
|
+
"at",
|
|
2710
|
+
"title",
|
|
2711
|
+
"question",
|
|
2712
|
+
"owner-agent",
|
|
2713
|
+
"blocking-work-item",
|
|
2714
|
+
"option",
|
|
2715
|
+
"resolution",
|
|
2716
|
+
"rationale",
|
|
2717
|
+
"evidence",
|
|
2718
|
+
];
|
|
2719
|
+
const hasDirectDecisionFields = directDecisionFields.some(
|
|
2720
|
+
name => options[name] !== undefined,
|
|
2721
|
+
);
|
|
2722
|
+
if (options.request !== undefined && hasDirectDecisionFields) {
|
|
2723
|
+
throw new Error("--request cannot be combined with direct decision fields.");
|
|
2724
|
+
}
|
|
2725
|
+
if (options.request !== undefined) {
|
|
2726
|
+
return appendTeamProjectEventV1({
|
|
2727
|
+
workspaceRoot: root,
|
|
2728
|
+
event: readJson(realpathSync(requireOption(options, "request"))),
|
|
2729
|
+
});
|
|
2730
|
+
}
|
|
2731
|
+
if (options.open === options.resolve) {
|
|
2732
|
+
throw new Error("Exactly one of --open or --resolve is required.");
|
|
2733
|
+
}
|
|
2734
|
+
const decisionId = requireOption(options, "decision-id");
|
|
2735
|
+
const occurredAt = requireOption(options, "at");
|
|
2736
|
+
if (options.open === true) {
|
|
2737
|
+
if (options.resolution !== undefined
|
|
2738
|
+
|| options.rationale !== undefined
|
|
2739
|
+
|| options.evidence !== undefined) {
|
|
2740
|
+
throw new Error("Decision open cannot accept resolution, rationale, or evidence.");
|
|
2741
|
+
}
|
|
2742
|
+
if ((options.option ?? []).length === 0) {
|
|
2743
|
+
throw new Error("Decision open requires at least one --option.");
|
|
2744
|
+
}
|
|
2745
|
+
const opened = openTeamProjectDecisionV1({
|
|
2746
|
+
workspaceRoot: root,
|
|
2747
|
+
decisionId,
|
|
2748
|
+
occurredAt,
|
|
2749
|
+
title: requireOption(options, "title"),
|
|
2750
|
+
question: requireOption(options, "question"),
|
|
2751
|
+
ownerAgentId: requireOption(options, "owner-agent"),
|
|
2752
|
+
blockingWorkItemIds: options["blocking-work-item"] ?? [],
|
|
2753
|
+
options: options.option,
|
|
2754
|
+
});
|
|
2755
|
+
return options.json === true
|
|
2756
|
+
? opened
|
|
2757
|
+
: withHumanOutput(opened, formatTeamProjectDecisionHuman(opened));
|
|
2758
|
+
}
|
|
2759
|
+
if (options.title !== undefined
|
|
2760
|
+
|| options.question !== undefined
|
|
2761
|
+
|| options["owner-agent"] !== undefined
|
|
2762
|
+
|| options["blocking-work-item"] !== undefined
|
|
2763
|
+
|| options.option !== undefined) {
|
|
2764
|
+
throw new Error("Decision resolve cannot accept title, question, owner-agent, blocking-work-item, or option.");
|
|
2765
|
+
}
|
|
2766
|
+
if ((options.evidence ?? []).length === 0) {
|
|
2767
|
+
throw new Error("Decision resolve requires at least one --evidence.");
|
|
2768
|
+
}
|
|
2769
|
+
const resolved = resolveTeamProjectDecisionV1({
|
|
2770
|
+
workspaceRoot: root,
|
|
2771
|
+
decisionId,
|
|
2772
|
+
occurredAt,
|
|
2773
|
+
resolution: requireOption(options, "resolution"),
|
|
2774
|
+
rationale: requireOption(options, "rationale"),
|
|
2775
|
+
evidenceRefs: options.evidence,
|
|
2776
|
+
});
|
|
2777
|
+
return options.json === true
|
|
2778
|
+
? resolved
|
|
2779
|
+
: withHumanOutput(resolved, formatTeamProjectDecisionHuman(resolved));
|
|
2780
|
+
}
|
|
2781
|
+
if (action === "verification") {
|
|
2782
|
+
const directVerificationFields = [
|
|
2783
|
+
"defer",
|
|
2784
|
+
"close",
|
|
2785
|
+
"verification-id",
|
|
2786
|
+
"at",
|
|
2787
|
+
"work-item",
|
|
2788
|
+
"owner-agent",
|
|
2789
|
+
"check",
|
|
2790
|
+
"reason",
|
|
2791
|
+
"due-gate",
|
|
2792
|
+
"disposition",
|
|
2793
|
+
"summary",
|
|
2794
|
+
"evidence",
|
|
2795
|
+
"decision",
|
|
2796
|
+
];
|
|
2797
|
+
const hasDirectVerificationFields = directVerificationFields.some(
|
|
2798
|
+
name => options[name] !== undefined,
|
|
2799
|
+
);
|
|
2800
|
+
if (options.request !== undefined && hasDirectVerificationFields) {
|
|
2801
|
+
throw new Error("--request cannot be combined with direct verification fields.");
|
|
2802
|
+
}
|
|
2803
|
+
if (options.request !== undefined) {
|
|
2804
|
+
const requestedEvent = readJson(realpathSync(requireOption(options, "request")));
|
|
2805
|
+
if (!new Set(["verification_deferred", "verification_closed"])
|
|
2806
|
+
.has(requestedEvent?.type)) {
|
|
2807
|
+
throw new Error(
|
|
2808
|
+
"Project verification request only accepts type=verification_deferred or verification_closed.",
|
|
2809
|
+
);
|
|
2810
|
+
}
|
|
2811
|
+
return appendTeamProjectEventV1({
|
|
2812
|
+
workspaceRoot: root,
|
|
2813
|
+
event: requestedEvent,
|
|
2814
|
+
});
|
|
2815
|
+
}
|
|
2816
|
+
if (options.defer === options.close) {
|
|
2817
|
+
throw new Error("Exactly one of --defer or --close is required.");
|
|
2818
|
+
}
|
|
2819
|
+
const verificationId = requireOption(options, "verification-id");
|
|
2820
|
+
const occurredAt = requireOption(options, "at");
|
|
2821
|
+
if (options.defer === true) {
|
|
2822
|
+
if (options.disposition !== undefined
|
|
2823
|
+
|| options.summary !== undefined
|
|
2824
|
+
|| options.evidence !== undefined
|
|
2825
|
+
|| options.decision !== undefined) {
|
|
2826
|
+
throw new Error(
|
|
2827
|
+
"Verification defer cannot accept disposition, summary, evidence, or decision.",
|
|
2828
|
+
);
|
|
2829
|
+
}
|
|
2830
|
+
if ((options.check ?? []).length === 0) {
|
|
2831
|
+
throw new Error("Verification defer requires at least one --check.");
|
|
2832
|
+
}
|
|
2833
|
+
const deferred = deferTeamProjectVerificationV1({
|
|
2834
|
+
workspaceRoot: root,
|
|
2835
|
+
verificationId,
|
|
2836
|
+
occurredAt,
|
|
2837
|
+
workItemId: requireOption(options, "work-item"),
|
|
2838
|
+
ownerAgentId: requireOption(options, "owner-agent"),
|
|
2839
|
+
checkIds: options.check,
|
|
2840
|
+
reason: requireOption(options, "reason"),
|
|
2841
|
+
dueGateId: requireOption(options, "due-gate"),
|
|
2842
|
+
});
|
|
2843
|
+
return options.json === true
|
|
2844
|
+
? deferred
|
|
2845
|
+
: withHumanOutput(deferred, formatTeamProjectVerificationHuman(deferred));
|
|
2846
|
+
}
|
|
2847
|
+
if (options["work-item"] !== undefined
|
|
2848
|
+
|| options["owner-agent"] !== undefined
|
|
2849
|
+
|| options.check !== undefined
|
|
2850
|
+
|| options.reason !== undefined
|
|
2851
|
+
|| options["due-gate"] !== undefined) {
|
|
2852
|
+
throw new Error(
|
|
2853
|
+
"Verification close cannot accept work-item, owner-agent, check, reason, or due-gate.",
|
|
2854
|
+
);
|
|
2855
|
+
}
|
|
2856
|
+
const closed = closeTeamProjectVerificationV1({
|
|
2857
|
+
workspaceRoot: root,
|
|
2858
|
+
verificationId,
|
|
2859
|
+
occurredAt,
|
|
2860
|
+
disposition: requireOption(options, "disposition"),
|
|
2861
|
+
summary: requireOption(options, "summary"),
|
|
2862
|
+
evidenceRefs: options.evidence ?? [],
|
|
2863
|
+
decisionIds: options.decision ?? [],
|
|
2864
|
+
});
|
|
2865
|
+
return options.json === true
|
|
2866
|
+
? closed
|
|
2867
|
+
: withHumanOutput(closed, formatTeamProjectVerificationHuman(closed));
|
|
2868
|
+
}
|
|
2869
|
+
if (action === "checkpoint") {
|
|
2870
|
+
const directCheckpointFields = [
|
|
2871
|
+
"checkpoint-id",
|
|
2872
|
+
"at",
|
|
2873
|
+
"assignment-id",
|
|
2874
|
+
"work-item",
|
|
2875
|
+
"state",
|
|
2876
|
+
"summary",
|
|
2877
|
+
"completed-units",
|
|
2878
|
+
"evidence",
|
|
2879
|
+
"blocker",
|
|
2880
|
+
"decision",
|
|
2881
|
+
"next",
|
|
2882
|
+
"source-fingerprint",
|
|
2883
|
+
];
|
|
2884
|
+
const hasDirectCheckpointFields = directCheckpointFields.some(
|
|
2885
|
+
name => options[name] !== undefined,
|
|
2886
|
+
);
|
|
2887
|
+
if (options.request !== undefined && hasDirectCheckpointFields) {
|
|
2888
|
+
throw new Error("--request cannot be combined with direct checkpoint fields.");
|
|
2889
|
+
}
|
|
2890
|
+
if (options.request !== undefined) {
|
|
2891
|
+
const requestedEvent = readJson(realpathSync(requireOption(options, "request")));
|
|
2892
|
+
if (requestedEvent?.type !== "checkpoint_recorded") {
|
|
2893
|
+
throw new Error("Project checkpoint request only accepts type=checkpoint_recorded.");
|
|
2894
|
+
}
|
|
2895
|
+
return appendTeamProjectEventV1({
|
|
2896
|
+
workspaceRoot: root,
|
|
2897
|
+
event: requestedEvent,
|
|
2898
|
+
});
|
|
2899
|
+
}
|
|
2900
|
+
const completedUnits = options["completed-units"] === undefined
|
|
2901
|
+
? undefined
|
|
2902
|
+
: parseCanonicalNonnegativeSafeInteger(options["completed-units"], "completed-units");
|
|
2903
|
+
const checkpointed = checkpointTeamProjectV1({
|
|
2904
|
+
workspaceRoot: root,
|
|
2905
|
+
checkpointId: requireOption(options, "checkpoint-id"),
|
|
2906
|
+
occurredAt: requireOption(options, "at"),
|
|
2907
|
+
assignmentId: requireOption(options, "assignment-id"),
|
|
2908
|
+
workItemId: requireOption(options, "work-item"),
|
|
2909
|
+
state: requireOption(options, "state"),
|
|
2910
|
+
summary: requireOption(options, "summary"),
|
|
2911
|
+
completedUnits,
|
|
2912
|
+
evidenceRefs: options.evidence ?? [],
|
|
2913
|
+
blockerRefs: options.blocker ?? [],
|
|
2914
|
+
decisionRefs: options.decision ?? [],
|
|
2915
|
+
nextAction: options.next ?? null,
|
|
2916
|
+
sourceFingerprint: options["source-fingerprint"],
|
|
2917
|
+
});
|
|
2918
|
+
return options.json === true
|
|
2919
|
+
? checkpointed
|
|
2920
|
+
: withHumanOutput(checkpointed, formatTeamProjectCheckpointHuman(checkpointed));
|
|
2921
|
+
}
|
|
2922
|
+
if (action === "integrate") {
|
|
2923
|
+
const directIntegrationFields = ["gate", "at", "summary", "evidence"];
|
|
2924
|
+
const hasDirectIntegrationFields = directIntegrationFields.some(
|
|
2925
|
+
name => options[name] !== undefined,
|
|
2926
|
+
);
|
|
2927
|
+
if (options.request !== undefined && hasDirectIntegrationFields) {
|
|
2928
|
+
throw new Error("--request cannot be combined with direct integrate fields.");
|
|
2929
|
+
}
|
|
2930
|
+
if (options.request !== undefined) {
|
|
2931
|
+
const requestedEvent = readJson(realpathSync(requireOption(options, "request")));
|
|
2932
|
+
if (requestedEvent?.type !== "integration_gate_passed") {
|
|
2933
|
+
throw new Error("Project integrate request only accepts type=integration_gate_passed.");
|
|
2934
|
+
}
|
|
2935
|
+
return appendTeamProjectEventV1({
|
|
2936
|
+
workspaceRoot: root,
|
|
2937
|
+
event: requestedEvent,
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2940
|
+
const evidenceRefs = options.evidence ?? [];
|
|
2941
|
+
if (evidenceRefs.length === 0) {
|
|
2942
|
+
throw new Error("Project integrate requires at least one --evidence.");
|
|
2943
|
+
}
|
|
2944
|
+
const integrated = integrateTeamProjectV1({
|
|
2945
|
+
workspaceRoot: root,
|
|
2946
|
+
gateId: requireOption(options, "gate"),
|
|
2947
|
+
occurredAt: requireOption(options, "at"),
|
|
2948
|
+
summary: requireOption(options, "summary"),
|
|
2949
|
+
evidenceRefs,
|
|
2950
|
+
});
|
|
2951
|
+
return options.json === true
|
|
2952
|
+
? integrated
|
|
2953
|
+
: withHumanOutput(integrated, formatTeamProjectIntegrationHuman(integrated));
|
|
2954
|
+
}
|
|
2955
|
+
if (new Set(["checkpoint", "capture"]).has(action)) {
|
|
2416
2956
|
return appendTeamProjectEventV1({
|
|
2417
2957
|
workspaceRoot: root,
|
|
2418
2958
|
event: readJson(realpathSync(requireOption(options, "request"))),
|
|
@@ -2431,15 +2971,22 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2431
2971
|
});
|
|
2432
2972
|
return options.json === true
|
|
2433
2973
|
? takeover
|
|
2434
|
-
: withHumanOutput(takeover,
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2974
|
+
: withHumanOutput(takeover, formatTeamProjectTakeoverHumanV1(takeover));
|
|
2975
|
+
}
|
|
2976
|
+
if (action === "successor") {
|
|
2977
|
+
const successor = successorTeamProjectV1({
|
|
2978
|
+
workspaceRoot: root,
|
|
2979
|
+
transitionId: requireOption(options, "transition-id"),
|
|
2980
|
+
occurredAt: requireOption(options, "at"),
|
|
2981
|
+
definitionPath: requireOption(options, "definition"),
|
|
2982
|
+
reason: requireOption(options, "reason"),
|
|
2983
|
+
onDurableStep: runtimeHooks.onTeamProjectSuccessorStep,
|
|
2984
|
+
});
|
|
2985
|
+
return options.json === true
|
|
2986
|
+
? successor
|
|
2987
|
+
: withHumanOutput(successor, formatTeamProjectSuccessorHumanV1(successor));
|
|
2441
2988
|
}
|
|
2442
|
-
throw new Error("Usage: owlrunkit project <init|assign|checkpoint|handoff|decision|capture|status|takeover> [options]");
|
|
2989
|
+
throw new Error("Usage: owlrunkit project <init|assign|checkpoint|handoff|decision|verification|integrate|capture|status|takeover|successor> [options]");
|
|
2443
2990
|
}
|
|
2444
2991
|
if (command === "profiles") {
|
|
2445
2992
|
const root = requireOption(options, "workspace");
|