owlrunkit 0.17.2 → 0.18.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 +64 -0
- package/README.md +117 -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/docs/architecture/OWLCODA_RUNKIT_USAGE_MODE_SELECTION_PRODUCT_DECISION_20260811.md +142 -0
- package/integrations/codex/skills/owlcoda-runkit/SKILL.md +127 -23
- 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/assurance-router.mjs +28 -20
- package/scripts/runkit-contract/core-contract.mjs +7 -1
- package/scripts/runkit-contract/inspect-presentation.mjs +38 -5
- package/scripts/runkit-contract/install-codex-skill.mjs +60 -1
- package/scripts/runkit-contract/onboarding-doctor.mjs +19 -1
- package/scripts/runkit-contract/profile-onboarding.mjs +597 -22
- package/scripts/runkit-contract/project-cli-resolver.mjs +6 -0
- package/scripts/runkit-contract/quick-attest.mjs +1 -0
- package/scripts/runkit-contract/quick-metrics.mjs +43 -5
- package/scripts/runkit-contract/quick-verify.mjs +15 -4
- package/scripts/runkit-contract/runkit-cli.mjs +747 -20
- package/scripts/runkit-contract/schemas/profile-reconcile-plan-v1.schema.json +105 -0
- package/scripts/runkit-contract/schemas/profile-reconcile-receipt-v1.schema.json +60 -0
- 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/schemas/usage-mode-recommendation-v1.schema.json +136 -0
- package/scripts/runkit-contract/team-project-successor.mjs +1176 -0
- package/scripts/runkit-contract/team-project.mjs +1082 -43
- package/scripts/runkit-contract/templates/assurance-request.json +6 -0
- package/scripts/runkit-contract/usage-mode.mjs +229 -0
|
@@ -89,6 +89,7 @@ import {
|
|
|
89
89
|
applyDetectedProfilesV2,
|
|
90
90
|
detectProfiles,
|
|
91
91
|
detectProfilesV2,
|
|
92
|
+
reconcileProfilesV2,
|
|
92
93
|
resolveProfilesImpact,
|
|
93
94
|
validateProfiles,
|
|
94
95
|
} from "./profile-onboarding.mjs";
|
|
@@ -100,6 +101,10 @@ import {
|
|
|
100
101
|
rollbackFleetRegistry,
|
|
101
102
|
} from "./fleet-discovery.mjs";
|
|
102
103
|
import { routeRunKitAssuranceV1 } from "./assurance-router.mjs";
|
|
104
|
+
import {
|
|
105
|
+
formatUsageModeHumanV1,
|
|
106
|
+
recommendUsageModeV1,
|
|
107
|
+
} from "./usage-mode.mjs";
|
|
103
108
|
import { deriveHumanStatusFromInspectV1 } from "./human-status.mjs";
|
|
104
109
|
import {
|
|
105
110
|
closeDeploymentExecuteChildRun,
|
|
@@ -138,11 +143,24 @@ import {
|
|
|
138
143
|
import { OFFICIAL_NPM_REGISTRY } from "./registry-adoption-gate.mjs";
|
|
139
144
|
import {
|
|
140
145
|
appendTeamProjectEventV1,
|
|
146
|
+
assignTeamProjectV1,
|
|
141
147
|
buildTeamProjectTakeoverV1,
|
|
148
|
+
checkpointTeamProjectV1,
|
|
149
|
+
closeTeamProjectVerificationV1,
|
|
150
|
+
deferTeamProjectVerificationV1,
|
|
142
151
|
formatTeamProjectStatusHumanV1,
|
|
152
|
+
formatTeamProjectTakeoverHumanV1,
|
|
153
|
+
handoffTeamProjectV1,
|
|
143
154
|
initializeTeamProjectV1,
|
|
155
|
+
integrateTeamProjectV1,
|
|
156
|
+
openTeamProjectDecisionV1,
|
|
144
157
|
readTeamProjectStatusV1,
|
|
158
|
+
resolveTeamProjectDecisionV1,
|
|
145
159
|
} from "./team-project.mjs";
|
|
160
|
+
import {
|
|
161
|
+
formatTeamProjectSuccessorHumanV1,
|
|
162
|
+
successorTeamProjectV1,
|
|
163
|
+
} from "./team-project-successor.mjs";
|
|
146
164
|
|
|
147
165
|
const TOP_LEVEL_HELP = `OwlRunKit ${CORE_VERSION}
|
|
148
166
|
|
|
@@ -150,20 +168,20 @@ Usage:
|
|
|
150
168
|
owlrunkit <command> [options]
|
|
151
169
|
|
|
152
170
|
Start here:
|
|
171
|
+
owlrunkit mode recommend --workspace .
|
|
153
172
|
owlrunkit doctor --workspace .
|
|
154
173
|
owlrunkit profiles detect --workspace . --dry-run
|
|
155
174
|
owlrunkit profiles detect --workspace . --apply
|
|
156
175
|
owlrunkit assurance route --workspace . --request <risk-facts.json>
|
|
157
176
|
owlrunkit adopt --workspace . --exact owlrunkit@${CORE_VERSION}
|
|
158
|
-
|
|
159
177
|
Quick Verification
|
|
160
178
|
owlrunkit quick-verify --workspace . -- <command> [args...]
|
|
161
179
|
Low-risk, source-bound reusable evidence without writer leases or acceptance.
|
|
162
180
|
|
|
163
181
|
Formal Delivery
|
|
164
182
|
owlrunkit formal <start|check|finish> --workspace . --run-id <id> [...]
|
|
165
|
-
Use for multi-writer,
|
|
166
|
-
|
|
183
|
+
Use for multi-writer, permissions, security, funds, irreversible change,
|
|
184
|
+
uncertain rollback, schema/data migration, or explicit Formal acceptance.
|
|
167
185
|
|
|
168
186
|
Frozen dirty source
|
|
169
187
|
owlrunkit candidate <freeze|verify|materialize> --workspace . [...]
|
|
@@ -179,7 +197,7 @@ Fleet and status
|
|
|
179
197
|
owlrunkit fleet discover; owlrunkit status --workspace .
|
|
180
198
|
|
|
181
199
|
Agent team projects
|
|
182
|
-
owlrunkit project <init|assign|checkpoint|handoff|decision|capture|status|takeover> [options]
|
|
200
|
+
owlrunkit project <init|assign|checkpoint|handoff|decision|verification|capture|status|takeover|successor> [options]
|
|
183
201
|
Durable Agent work, dependencies, decisions, gates, progress, and handoffs.
|
|
184
202
|
Core successor
|
|
185
203
|
owlrunkit core-successor <plan|apply|resume> --workspace . [...]
|
|
@@ -191,6 +209,13 @@ Formal accepted does not grant Git or release authority; Quick cannot become For
|
|
|
191
209
|
`;
|
|
192
210
|
|
|
193
211
|
const COMMAND_HELP = Object.freeze({
|
|
212
|
+
adopt: `Usage:
|
|
213
|
+
owlrunkit adopt --workspace <directory> --exact owlrunkit@${CORE_VERSION}
|
|
214
|
+
[--registry <url>] [--timeout-ms <milliseconds>] [--json]
|
|
215
|
+
|
|
216
|
+
Verifies the exact registry release against the project-local install and writes
|
|
217
|
+
project-owned adoption evidence. It grants no Git or release authority.
|
|
218
|
+
`,
|
|
194
219
|
assurance: `Usage:
|
|
195
220
|
owlrunkit assurance route --workspace <directory> --request <risk-facts.json>
|
|
196
221
|
|
|
@@ -202,6 +227,38 @@ repository, release, deployment, or destructive authority.
|
|
|
202
227
|
|
|
203
228
|
Required:
|
|
204
229
|
--request <file> Structured assurance risk facts.
|
|
230
|
+
`,
|
|
231
|
+
mode: `Usage:
|
|
232
|
+
owlrunkit mode recommend --workspace <directory> [risk facts]
|
|
233
|
+
owlrunkit mode status --workspace <directory> [--json]
|
|
234
|
+
|
|
235
|
+
Selects continuity and assurance independently. Recommendation and status are
|
|
236
|
+
read-only and grant no Git, release, deployment, production, or business authority.
|
|
237
|
+
`,
|
|
238
|
+
"mode recommend": `Usage:
|
|
239
|
+
owlrunkit mode recommend --workspace <directory>
|
|
240
|
+
[--requested-mode auto|off|light|managed|formal]
|
|
241
|
+
[--needs-evidence] [--exact-command-count <count>] [--writer-count <count>]
|
|
242
|
+
[--cross-session] [--long-running] [--interruption-recovery]
|
|
243
|
+
[--may-mutate-project] [--external-side-effects]
|
|
244
|
+
[--irreversible] [--rollback-uncertain]
|
|
245
|
+
[--permission-sensitive] [--security-sensitive] [--funds-at-risk]
|
|
246
|
+
[--schema-or-data-migration] [--formal-acceptance]
|
|
247
|
+
[--risk-category <category>] [--json]
|
|
248
|
+
|
|
249
|
+
Returns one user mode plus the independent continuity and assurance selections.
|
|
250
|
+
Persisted mode preferences are not part of this release.
|
|
251
|
+
`,
|
|
252
|
+
"mode status": `Usage:
|
|
253
|
+
owlrunkit mode status --workspace <directory> [--json]
|
|
254
|
+
|
|
255
|
+
Reads the current mode preference source without creating project state.
|
|
256
|
+
`,
|
|
257
|
+
"quick-attest": `Usage:
|
|
258
|
+
owlrunkit quick-attest --workspace <directory> --receipt <receipt.json> [--json]
|
|
259
|
+
|
|
260
|
+
Attests one Quick Receipt against its bound materials and current workspace.
|
|
261
|
+
It never grants repository or business authority.
|
|
205
262
|
`,
|
|
206
263
|
fleet: `Usage:
|
|
207
264
|
owlrunkit fleet register-root --fleet-root <directory>
|
|
@@ -241,6 +298,7 @@ With no source option, discovers the complete fleet inside registered roots.
|
|
|
241
298
|
`,
|
|
242
299
|
profiles: `Usage:
|
|
243
300
|
owlrunkit profiles detect --workspace <directory> [--dry-run | --apply]
|
|
301
|
+
owlrunkit profiles reconcile --workspace <directory> (--dry-run | --apply)
|
|
244
302
|
owlrunkit profiles validate --workspace <directory>
|
|
245
303
|
owlrunkit profiles impact --workspace <directory> --changed <path>
|
|
246
304
|
`,
|
|
@@ -249,6 +307,12 @@ With no source option, discovers the complete fleet inside registered roots.
|
|
|
249
307
|
|
|
250
308
|
--dry-run reports deterministic candidates. --apply atomically adopts only a
|
|
251
309
|
high-confidence unambiguous profile.
|
|
310
|
+
`,
|
|
311
|
+
"profiles reconcile": `Usage:
|
|
312
|
+
owlrunkit profiles reconcile --workspace <directory> (--dry-run | --apply)
|
|
313
|
+
|
|
314
|
+
--dry-run previews deterministic additions and command updates without writing.
|
|
315
|
+
--apply atomically updates profiles.json and writes a hash-bound migration receipt.
|
|
252
316
|
`,
|
|
253
317
|
formal: `Usage:
|
|
254
318
|
owlrunkit formal start --workspace <directory> --run-id <id> [...]
|
|
@@ -340,9 +404,35 @@ action without granting any authority.
|
|
|
340
404
|
`,
|
|
341
405
|
project: `Usage:
|
|
342
406
|
owlrunkit project init --workspace <directory> --definition <project.json>
|
|
343
|
-
owlrunkit project
|
|
407
|
+
owlrunkit project assign --workspace <directory> --assignment-id <id> --at <ISO-UTC> --work-item <id> --agent <id>
|
|
408
|
+
[--supersedes <current-assignment-id>] [--execution-run-id <id> --execution-work-item <id>] [--json]
|
|
409
|
+
owlrunkit project handoff --workspace <directory> --handoff-id <id> --at <ISO-UTC>
|
|
410
|
+
--assignment-id <current> --work-item <id> --from-agent <id> --to-agent <id>
|
|
411
|
+
--summary <text> --next <text> --evidence <ref> [--evidence <ref> ...] [--json]
|
|
412
|
+
owlrunkit project decision --workspace <directory> --open --decision-id <id> --at <ISO-UTC>
|
|
413
|
+
--title <text> --question <text> --owner-agent <id>
|
|
414
|
+
[--blocking-work-item <id> ...] --option <text> [--option <text> ...] [--json]
|
|
415
|
+
owlrunkit project decision --workspace <directory> --resolve --decision-id <id> --at <ISO-UTC>
|
|
416
|
+
--resolution <text> --rationale <text> --evidence <ref> [--evidence <ref> ...] [--json]
|
|
417
|
+
owlrunkit project checkpoint --workspace <directory> --checkpoint-id <id> --at <ISO-UTC>
|
|
418
|
+
--assignment-id <current> --work-item <id>
|
|
419
|
+
--state <active|waiting_dependency|waiting_decision|verifying|ready_to_integrate|completed|failed>
|
|
420
|
+
--summary <text> [--completed-units <nonnegative-int>]
|
|
421
|
+
[--evidence <ref> ...] [--blocker <ref> ...] [--decision <id> ...]
|
|
422
|
+
[--next <text>] [--source-fingerprint <sha256>] [--json]
|
|
423
|
+
owlrunkit project verification --workspace <directory> --defer --verification-id <id> --at <ISO-UTC>
|
|
424
|
+
--work-item <id> --owner-agent <id> --check <check-id> [--check <check-id> ...]
|
|
425
|
+
--reason <text> --due-gate <gate-id> [--json]
|
|
426
|
+
owlrunkit project verification --workspace <directory> --close --verification-id <id> --at <ISO-UTC>
|
|
427
|
+
--disposition <verified|no_longer_required> --summary <text>
|
|
428
|
+
[--evidence <ref> ...] [--decision <resolved-decision-id> ...] [--json]
|
|
429
|
+
owlrunkit project integrate --workspace <directory> --gate <gate-id> --at <ISO-UTC>
|
|
430
|
+
--summary <text> --evidence <ref> [--evidence <ref> ...] [--json]
|
|
431
|
+
owlrunkit project <checkpoint|handoff|decision|verification|integrate|capture> --workspace <directory> --request <event.json>
|
|
344
432
|
owlrunkit project status --workspace <directory> [--json]
|
|
345
433
|
owlrunkit project takeover --workspace <directory> --agent <id> [--json]
|
|
434
|
+
owlrunkit project successor --workspace <directory> --transition-id <id> --at <ISO-UTC>
|
|
435
|
+
--definition <project.json> --reason <text> [--json]
|
|
346
436
|
|
|
347
437
|
Project status is derived from durable work items, Agent assignments,
|
|
348
438
|
dependencies, decisions, checkpoints, integration gates, and evidence refs.
|
|
@@ -355,6 +445,13 @@ No self-reported percentage is accepted.
|
|
|
355
445
|
owlrunkit project takeover --workspace <directory> --agent <id> [--json]
|
|
356
446
|
|
|
357
447
|
Builds a read-only blank-session recovery packet for one Agent.
|
|
448
|
+
`,
|
|
449
|
+
"project successor": `Usage:
|
|
450
|
+
owlrunkit project successor --workspace <directory> --transition-id <id> --at <ISO-UTC>
|
|
451
|
+
--definition <project.json> --reason <text> [--json]
|
|
452
|
+
|
|
453
|
+
Archives one derived-completed active project and installs one fresh active
|
|
454
|
+
project with no inherited events. The receipt grants no repository or release authority.
|
|
358
455
|
`,
|
|
359
456
|
});
|
|
360
457
|
|
|
@@ -368,6 +465,93 @@ function withHumanOutput(result, humanOutput) {
|
|
|
368
465
|
return result;
|
|
369
466
|
}
|
|
370
467
|
|
|
468
|
+
function formatTeamProjectAssignmentHuman(result) {
|
|
469
|
+
const disposition = result.resumed ? "Resumed" : "Assigned";
|
|
470
|
+
const nextAction = result.nextAction === null
|
|
471
|
+
? "none"
|
|
472
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
473
|
+
return [
|
|
474
|
+
`${disposition} WorkItem ${result.workItemId} to Agent ${result.agentId}.`,
|
|
475
|
+
`Project next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
476
|
+
`Assignment: ${result.assignmentId}`,
|
|
477
|
+
"",
|
|
478
|
+
].join("\n");
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function formatTeamProjectHandoffHuman(result) {
|
|
482
|
+
const disposition = result.resumed ? "Resumed" : "Handed off";
|
|
483
|
+
const targetNextAction = result.targetNextAction === null
|
|
484
|
+
? "none"
|
|
485
|
+
: String(result.targetNextAction).replace(/\s+/gu, " ").trim();
|
|
486
|
+
const projectNextAction = result.nextAction === null
|
|
487
|
+
? "none"
|
|
488
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
489
|
+
return [
|
|
490
|
+
`${disposition} WorkItem ${result.workItemId} from Agent ${result.fromAgentId} to Agent ${result.toAgentId}.`,
|
|
491
|
+
`Target next: ${targetNextAction}`,
|
|
492
|
+
`Project next: ${projectNextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
493
|
+
`Handoff: ${result.handoffId}`,
|
|
494
|
+
"",
|
|
495
|
+
].join("\n");
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function formatTeamProjectDecisionHuman(result) {
|
|
499
|
+
const disposition = result.resumed
|
|
500
|
+
? "Resumed"
|
|
501
|
+
: result.operation === "opened" ? "Opened" : "Resolved";
|
|
502
|
+
const owner = result.ownerAgentId ? ` for Agent ${result.ownerAgentId}` : "";
|
|
503
|
+
const nextAction = result.nextAction === null
|
|
504
|
+
? "none"
|
|
505
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
506
|
+
return [
|
|
507
|
+
`${disposition} decision ${result.decisionId}${owner}.`,
|
|
508
|
+
`Project next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
509
|
+
`Decision: ${result.decisionId}`,
|
|
510
|
+
"",
|
|
511
|
+
].join("\n");
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function formatTeamProjectVerificationHuman(result) {
|
|
515
|
+
const disposition = result.resumed
|
|
516
|
+
? "Resumed"
|
|
517
|
+
: result.operation === "deferred" ? "Deferred" : "Closed";
|
|
518
|
+
const nextAction = result.nextAction === null
|
|
519
|
+
? "none"
|
|
520
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
521
|
+
return [
|
|
522
|
+
`${disposition} project verification ${result.verificationId}: ${result.verificationStatus}.`,
|
|
523
|
+
`Due gate: ${result.dueGateId}; gate state: ${result.gateStatus}.`,
|
|
524
|
+
`Project state: ${result.overall}; next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
525
|
+
"No verification command, Git, or release action was performed.",
|
|
526
|
+
"",
|
|
527
|
+
].join("\n");
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function formatTeamProjectIntegrationHuman(result) {
|
|
531
|
+
const disposition = result.resumed ? "Resumed" : "Passed";
|
|
532
|
+
const nextAction = result.nextAction === null
|
|
533
|
+
? "none"
|
|
534
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
535
|
+
return [
|
|
536
|
+
`${disposition} project integration gate ${result.gateId}.`,
|
|
537
|
+
`Project state: ${result.overall}; next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
538
|
+
"Git/release not performed.",
|
|
539
|
+
"",
|
|
540
|
+
].join("\n");
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function formatTeamProjectCheckpointHuman(result) {
|
|
544
|
+
const disposition = result.resumed ? "Resumed" : "Recorded";
|
|
545
|
+
const nextAction = result.nextAction === null
|
|
546
|
+
? "none"
|
|
547
|
+
: String(result.nextAction).replace(/\s+/gu, " ").trim();
|
|
548
|
+
return [
|
|
549
|
+
`${disposition} checkpoint ${result.checkpointId} for WorkItem ${result.workItemId}: ${result.state}.`,
|
|
550
|
+
`Project state: ${result.overall}; next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
|
|
551
|
+
"",
|
|
552
|
+
].join("\n");
|
|
553
|
+
}
|
|
554
|
+
|
|
371
555
|
function profilesReadiness(root) {
|
|
372
556
|
if (!root) return { valid: false, launcherWarnings: [] };
|
|
373
557
|
try {
|
|
@@ -465,6 +649,30 @@ function requireOption(options, name) {
|
|
|
465
649
|
return value;
|
|
466
650
|
}
|
|
467
651
|
|
|
652
|
+
function assertOnlyOptions(options, allowedNames) {
|
|
653
|
+
const allowed = new Set(allowedNames);
|
|
654
|
+
const unsupported = Object.keys(options)
|
|
655
|
+
.filter(name => !allowed.has(name))
|
|
656
|
+
.sort();
|
|
657
|
+
if (unsupported.length > 0) {
|
|
658
|
+
throw new Error(
|
|
659
|
+
`Unsupported option${unsupported.length === 1 ? "" : "s"}: `
|
|
660
|
+
+ unsupported.map(name => `--${name}`).join(", "),
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function parseCanonicalNonnegativeSafeInteger(value, label) {
|
|
666
|
+
if (typeof value !== "string" || !/^(?:0|[1-9]\d*)$/u.test(value)) {
|
|
667
|
+
throw new Error(`--${label} must be a canonical non-negative safe integer.`);
|
|
668
|
+
}
|
|
669
|
+
const parsed = Number(value);
|
|
670
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
671
|
+
throw new Error(`--${label} must be a canonical non-negative safe integer.`);
|
|
672
|
+
}
|
|
673
|
+
return parsed;
|
|
674
|
+
}
|
|
675
|
+
|
|
468
676
|
function readWorkspaceArtifact(root, value, label) {
|
|
469
677
|
const relativePath = safeRelativePath(value, label);
|
|
470
678
|
return readJson(realpathSync(path.join(root, relativePath)));
|
|
@@ -1393,8 +1601,13 @@ function inspect(options) {
|
|
|
1393
1601
|
throw new Error(`Execution was not found: ${requestedRunId}`);
|
|
1394
1602
|
}
|
|
1395
1603
|
const onboarding = onboardingProjection(root, recovery);
|
|
1604
|
+
const projectDefinitionPath = runtimePath(root, "project", "definition.json");
|
|
1605
|
+
const projectDriver = pathEntryExists(projectDefinitionPath)
|
|
1606
|
+
? readTeamProjectStatusV1({ workspaceRoot: root })
|
|
1607
|
+
: null;
|
|
1396
1608
|
const summary = buildInspectSummary(result, {
|
|
1397
1609
|
maintenanceNextAction: onboarding.maintenanceNextAction ?? null,
|
|
1610
|
+
projectDriver,
|
|
1398
1611
|
});
|
|
1399
1612
|
const view = options.history
|
|
1400
1613
|
? { mode: "history" }
|
|
@@ -1406,7 +1619,13 @@ function inspect(options) {
|
|
|
1406
1619
|
execution: executions.find(execution => execution.runId === requestedRunId),
|
|
1407
1620
|
}
|
|
1408
1621
|
: { mode: "summary" };
|
|
1409
|
-
return {
|
|
1622
|
+
return {
|
|
1623
|
+
...result,
|
|
1624
|
+
summary,
|
|
1625
|
+
view,
|
|
1626
|
+
onboarding,
|
|
1627
|
+
...(projectDriver === null ? {} : { projectDriver }),
|
|
1628
|
+
};
|
|
1410
1629
|
}
|
|
1411
1630
|
|
|
1412
1631
|
function closeout(options) {
|
|
@@ -1627,6 +1846,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
1627
1846
|
"fleet",
|
|
1628
1847
|
"formal",
|
|
1629
1848
|
"lease",
|
|
1849
|
+
"mode",
|
|
1630
1850
|
"profiles",
|
|
1631
1851
|
"project",
|
|
1632
1852
|
]).has(command);
|
|
@@ -1649,7 +1869,9 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
1649
1869
|
}
|
|
1650
1870
|
}
|
|
1651
1871
|
const options = parseOptions(nested ? nestedOptions : optionValues, {
|
|
1652
|
-
multi: command === "
|
|
1872
|
+
multi: command === "mode"
|
|
1873
|
+
? ["risk-category"]
|
|
1874
|
+
: command === "profiles" && action === "impact"
|
|
1653
1875
|
? ["changed"]
|
|
1654
1876
|
: (command === "fleet" && action === "discover")
|
|
1655
1877
|
|| (command === "core-successor" && action === "plan")
|
|
@@ -1658,12 +1880,46 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
1658
1880
|
|| command === "start"
|
|
1659
1881
|
|| (command === "formal" && action === "start")
|
|
1660
1882
|
? ["owned-path"]
|
|
1883
|
+
: command === "project" && action === "handoff"
|
|
1884
|
+
? ["evidence"]
|
|
1885
|
+
: command === "project" && action === "integrate"
|
|
1886
|
+
? ["evidence"]
|
|
1887
|
+
: command === "project" && action === "verification"
|
|
1888
|
+
? ["check", "evidence", "decision"]
|
|
1889
|
+
: command === "project" && action === "checkpoint"
|
|
1890
|
+
? ["evidence", "blocker", "decision"]
|
|
1891
|
+
: command === "project" && action === "decision"
|
|
1892
|
+
? ["blocking-work-item", "option", "evidence"]
|
|
1661
1893
|
: [],
|
|
1662
|
-
boolean: command === "
|
|
1894
|
+
boolean: command === "mode" && action === "recommend"
|
|
1895
|
+
? [
|
|
1896
|
+
"json",
|
|
1897
|
+
"needs-evidence",
|
|
1898
|
+
"may-mutate-project",
|
|
1899
|
+
"external-side-effects",
|
|
1900
|
+
"cross-session",
|
|
1901
|
+
"long-running",
|
|
1902
|
+
"interruption-recovery",
|
|
1903
|
+
"dirty-parallel-workspace",
|
|
1904
|
+
"irreversible",
|
|
1905
|
+
"rollback-uncertain",
|
|
1906
|
+
"permission-sensitive",
|
|
1907
|
+
"security-sensitive",
|
|
1908
|
+
"funds-at-risk",
|
|
1909
|
+
"schema-or-data-migration",
|
|
1910
|
+
"formal-acceptance",
|
|
1911
|
+
]
|
|
1912
|
+
: command === "mode" && action === "status"
|
|
1913
|
+
? ["json"]
|
|
1914
|
+
: command === "inspect"
|
|
1663
1915
|
? ["json", "verbose", "history"]
|
|
1664
1916
|
: command === "init"
|
|
1665
1917
|
? ["json"]
|
|
1666
|
-
: command === "project" &&
|
|
1918
|
+
: command === "project" && action === "decision"
|
|
1919
|
+
? ["json", "open", "resolve"]
|
|
1920
|
+
: command === "project" && action === "verification"
|
|
1921
|
+
? ["json", "defer", "close"]
|
|
1922
|
+
: command === "project" && new Set(["assign", "handoff", "checkpoint", "integrate", "status", "takeover", "successor"]).has(action)
|
|
1667
1923
|
? ["json"]
|
|
1668
1924
|
: command === "doctor" || command === "adopt" || command === "status"
|
|
1669
1925
|
? ["json"]
|
|
@@ -1716,6 +1972,97 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
1716
1972
|
const requestPath = realpathSync(requireOption(options, "request"));
|
|
1717
1973
|
return routeRunKitAssuranceV1(readJson(requestPath));
|
|
1718
1974
|
}
|
|
1975
|
+
if (command === "mode") {
|
|
1976
|
+
const root = workspace(options);
|
|
1977
|
+
if (action === "recommend") {
|
|
1978
|
+
assertOnlyOptions(options, [
|
|
1979
|
+
"workspace",
|
|
1980
|
+
"requested-mode",
|
|
1981
|
+
"needs-evidence",
|
|
1982
|
+
"exact-command-count",
|
|
1983
|
+
"writer-count",
|
|
1984
|
+
"may-mutate-project",
|
|
1985
|
+
"external-side-effects",
|
|
1986
|
+
"cross-session",
|
|
1987
|
+
"long-running",
|
|
1988
|
+
"interruption-recovery",
|
|
1989
|
+
"dirty-parallel-workspace",
|
|
1990
|
+
"irreversible",
|
|
1991
|
+
"rollback-uncertain",
|
|
1992
|
+
"permission-sensitive",
|
|
1993
|
+
"security-sensitive",
|
|
1994
|
+
"funds-at-risk",
|
|
1995
|
+
"schema-or-data-migration",
|
|
1996
|
+
"formal-acceptance",
|
|
1997
|
+
"risk-category",
|
|
1998
|
+
"json",
|
|
1999
|
+
]);
|
|
2000
|
+
const recommendation = recommendUsageModeV1({
|
|
2001
|
+
workspaceRoot: root,
|
|
2002
|
+
requestedMode: options["requested-mode"] ?? "auto",
|
|
2003
|
+
needsDurableEvidence: options["needs-evidence"] === true,
|
|
2004
|
+
exactCommandCount: parseCanonicalNonnegativeSafeInteger(
|
|
2005
|
+
options["exact-command-count"] ?? "0",
|
|
2006
|
+
"exact-command-count",
|
|
2007
|
+
),
|
|
2008
|
+
writerCount: parseCanonicalNonnegativeSafeInteger(
|
|
2009
|
+
options["writer-count"] ?? "1",
|
|
2010
|
+
"writer-count",
|
|
2011
|
+
),
|
|
2012
|
+
mayMutateProject: options["may-mutate-project"] === true,
|
|
2013
|
+
externalSideEffects: options["external-side-effects"] === true,
|
|
2014
|
+
crossSession: options["cross-session"] === true,
|
|
2015
|
+
longRunning: options["long-running"] === true,
|
|
2016
|
+
interruptionRecovery: options["interruption-recovery"] === true,
|
|
2017
|
+
dirtyParallelWorkspace: options["dirty-parallel-workspace"] === true,
|
|
2018
|
+
irreversibleChange: options.irreversible === true,
|
|
2019
|
+
rollbackUncertain: options["rollback-uncertain"] === true,
|
|
2020
|
+
permissionSensitive: options["permission-sensitive"] === true,
|
|
2021
|
+
securitySensitive: options["security-sensitive"] === true,
|
|
2022
|
+
fundsAtRisk: options["funds-at-risk"] === true,
|
|
2023
|
+
schemaOrDataMigration: options["schema-or-data-migration"] === true,
|
|
2024
|
+
needsFormalAcceptance: options["formal-acceptance"] === true,
|
|
2025
|
+
riskCategories: options["risk-category"] ?? [],
|
|
2026
|
+
});
|
|
2027
|
+
return options.json === true
|
|
2028
|
+
? recommendation
|
|
2029
|
+
: withHumanOutput(recommendation, formatUsageModeHumanV1(recommendation));
|
|
2030
|
+
}
|
|
2031
|
+
if (action === "status") {
|
|
2032
|
+
assertOnlyOptions(options, ["workspace", "json"]);
|
|
2033
|
+
const recommendation = recommendUsageModeV1({
|
|
2034
|
+
workspaceRoot: root,
|
|
2035
|
+
requestedMode: "auto",
|
|
2036
|
+
needsDurableEvidence: false,
|
|
2037
|
+
exactCommandCount: 0,
|
|
2038
|
+
writerCount: 1,
|
|
2039
|
+
mayMutateProject: false,
|
|
2040
|
+
externalSideEffects: false,
|
|
2041
|
+
crossSession: false,
|
|
2042
|
+
longRunning: false,
|
|
2043
|
+
interruptionRecovery: false,
|
|
2044
|
+
dirtyParallelWorkspace: false,
|
|
2045
|
+
irreversibleChange: false,
|
|
2046
|
+
rollbackUncertain: false,
|
|
2047
|
+
permissionSensitive: false,
|
|
2048
|
+
securitySensitive: false,
|
|
2049
|
+
fundsAtRisk: false,
|
|
2050
|
+
schemaOrDataMigration: false,
|
|
2051
|
+
needsFormalAcceptance: false,
|
|
2052
|
+
riskCategories: [],
|
|
2053
|
+
});
|
|
2054
|
+
const status = {
|
|
2055
|
+
...recommendation,
|
|
2056
|
+
status: "mode_status",
|
|
2057
|
+
preferenceSource: "default_auto",
|
|
2058
|
+
persistedPreference: null,
|
|
2059
|
+
};
|
|
2060
|
+
return options.json === true
|
|
2061
|
+
? status
|
|
2062
|
+
: withHumanOutput(status, formatUsageModeHumanV1(status));
|
|
2063
|
+
}
|
|
2064
|
+
throw new Error("Usage: owlrunkit mode <recommend|status> --workspace <directory>");
|
|
2065
|
+
}
|
|
1719
2066
|
if (command === "fleet") {
|
|
1720
2067
|
if (action === "register-root") {
|
|
1721
2068
|
const registered = await registerFleetCoverageRoot({
|
|
@@ -2413,6 +2760,40 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2413
2760
|
);
|
|
2414
2761
|
}
|
|
2415
2762
|
if (command === "project") {
|
|
2763
|
+
const allowedProjectOptions = {
|
|
2764
|
+
init: ["workspace", "definition"],
|
|
2765
|
+
assign: [
|
|
2766
|
+
"workspace", "request", "assignment-id", "at", "work-item", "agent",
|
|
2767
|
+
"supersedes", "execution-run-id", "execution-work-item", "json",
|
|
2768
|
+
],
|
|
2769
|
+
handoff: [
|
|
2770
|
+
"workspace", "request", "handoff-id", "at", "assignment-id", "work-item",
|
|
2771
|
+
"from-agent", "to-agent", "summary", "next", "evidence", "json",
|
|
2772
|
+
],
|
|
2773
|
+
decision: [
|
|
2774
|
+
"workspace", "request", "open", "resolve", "decision-id", "at", "title",
|
|
2775
|
+
"question", "owner-agent", "blocking-work-item", "option", "resolution",
|
|
2776
|
+
"rationale", "evidence", "json",
|
|
2777
|
+
],
|
|
2778
|
+
checkpoint: [
|
|
2779
|
+
"workspace", "request", "checkpoint-id", "at", "assignment-id", "work-item",
|
|
2780
|
+
"state", "summary", "completed-units", "evidence", "blocker", "decision",
|
|
2781
|
+
"next", "source-fingerprint", "json",
|
|
2782
|
+
],
|
|
2783
|
+
verification: [
|
|
2784
|
+
"workspace", "request", "defer", "close", "verification-id", "at",
|
|
2785
|
+
"work-item", "owner-agent", "check", "reason", "due-gate",
|
|
2786
|
+
"disposition", "summary", "evidence", "decision", "json",
|
|
2787
|
+
],
|
|
2788
|
+
integrate: ["workspace", "request", "gate", "at", "summary", "evidence", "json"],
|
|
2789
|
+
capture: ["workspace", "request"],
|
|
2790
|
+
status: ["workspace", "json"],
|
|
2791
|
+
takeover: ["workspace", "agent", "json"],
|
|
2792
|
+
successor: ["workspace", "transition-id", "at", "definition", "reason", "json"],
|
|
2793
|
+
};
|
|
2794
|
+
if (Object.hasOwn(allowedProjectOptions, action)) {
|
|
2795
|
+
assertOnlyOptions(options, allowedProjectOptions[action]);
|
|
2796
|
+
}
|
|
2416
2797
|
const root = requireOption(options, "workspace");
|
|
2417
2798
|
if (action === "init") {
|
|
2418
2799
|
return initializeTeamProjectV1({
|
|
@@ -2420,7 +2801,334 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2420
2801
|
definition: readJson(realpathSync(requireOption(options, "definition"))),
|
|
2421
2802
|
});
|
|
2422
2803
|
}
|
|
2423
|
-
if (
|
|
2804
|
+
if (action === "assign") {
|
|
2805
|
+
const directAssignmentFields = [
|
|
2806
|
+
"assignment-id",
|
|
2807
|
+
"at",
|
|
2808
|
+
"work-item",
|
|
2809
|
+
"agent",
|
|
2810
|
+
"supersedes",
|
|
2811
|
+
"execution-run-id",
|
|
2812
|
+
"execution-work-item",
|
|
2813
|
+
];
|
|
2814
|
+
const hasDirectAssignmentFields = directAssignmentFields.some(
|
|
2815
|
+
name => options[name] !== undefined,
|
|
2816
|
+
);
|
|
2817
|
+
if (options.request !== undefined && hasDirectAssignmentFields) {
|
|
2818
|
+
throw new Error("--request cannot be combined with direct assignment fields.");
|
|
2819
|
+
}
|
|
2820
|
+
if (options.request !== undefined) {
|
|
2821
|
+
return appendTeamProjectEventV1({
|
|
2822
|
+
workspaceRoot: root,
|
|
2823
|
+
event: readJson(realpathSync(requireOption(options, "request"))),
|
|
2824
|
+
});
|
|
2825
|
+
}
|
|
2826
|
+
const assigned = assignTeamProjectV1({
|
|
2827
|
+
workspaceRoot: root,
|
|
2828
|
+
assignmentId: options["assignment-id"],
|
|
2829
|
+
occurredAt: options.at,
|
|
2830
|
+
workItemId: options["work-item"],
|
|
2831
|
+
agentId: options.agent,
|
|
2832
|
+
supersedesAssignmentId: options.supersedes,
|
|
2833
|
+
executionRunId: options["execution-run-id"],
|
|
2834
|
+
executionWorkItemId: options["execution-work-item"],
|
|
2835
|
+
});
|
|
2836
|
+
return options.json === true
|
|
2837
|
+
? assigned
|
|
2838
|
+
: withHumanOutput(assigned, formatTeamProjectAssignmentHuman(assigned));
|
|
2839
|
+
}
|
|
2840
|
+
if (action === "handoff") {
|
|
2841
|
+
const directHandoffFields = [
|
|
2842
|
+
"handoff-id",
|
|
2843
|
+
"at",
|
|
2844
|
+
"assignment-id",
|
|
2845
|
+
"work-item",
|
|
2846
|
+
"from-agent",
|
|
2847
|
+
"to-agent",
|
|
2848
|
+
"summary",
|
|
2849
|
+
"next",
|
|
2850
|
+
"evidence",
|
|
2851
|
+
];
|
|
2852
|
+
const hasDirectHandoffFields = directHandoffFields.some(
|
|
2853
|
+
name => options[name] !== undefined,
|
|
2854
|
+
);
|
|
2855
|
+
if (options.request !== undefined && hasDirectHandoffFields) {
|
|
2856
|
+
throw new Error("--request cannot be combined with direct handoff fields.");
|
|
2857
|
+
}
|
|
2858
|
+
if (options.request !== undefined) {
|
|
2859
|
+
return appendTeamProjectEventV1({
|
|
2860
|
+
workspaceRoot: root,
|
|
2861
|
+
event: readJson(realpathSync(requireOption(options, "request"))),
|
|
2862
|
+
});
|
|
2863
|
+
}
|
|
2864
|
+
const handedOff = handoffTeamProjectV1({
|
|
2865
|
+
workspaceRoot: root,
|
|
2866
|
+
handoffId: options["handoff-id"],
|
|
2867
|
+
occurredAt: options.at,
|
|
2868
|
+
assignmentId: options["assignment-id"],
|
|
2869
|
+
workItemId: options["work-item"],
|
|
2870
|
+
fromAgentId: options["from-agent"],
|
|
2871
|
+
toAgentId: options["to-agent"],
|
|
2872
|
+
summary: options.summary,
|
|
2873
|
+
nextAction: options.next,
|
|
2874
|
+
evidenceRefs: options.evidence,
|
|
2875
|
+
});
|
|
2876
|
+
return options.json === true
|
|
2877
|
+
? handedOff
|
|
2878
|
+
: withHumanOutput(handedOff, formatTeamProjectHandoffHuman(handedOff));
|
|
2879
|
+
}
|
|
2880
|
+
if (action === "decision") {
|
|
2881
|
+
const directDecisionFields = [
|
|
2882
|
+
"open",
|
|
2883
|
+
"resolve",
|
|
2884
|
+
"decision-id",
|
|
2885
|
+
"at",
|
|
2886
|
+
"title",
|
|
2887
|
+
"question",
|
|
2888
|
+
"owner-agent",
|
|
2889
|
+
"blocking-work-item",
|
|
2890
|
+
"option",
|
|
2891
|
+
"resolution",
|
|
2892
|
+
"rationale",
|
|
2893
|
+
"evidence",
|
|
2894
|
+
];
|
|
2895
|
+
const hasDirectDecisionFields = directDecisionFields.some(
|
|
2896
|
+
name => options[name] !== undefined,
|
|
2897
|
+
);
|
|
2898
|
+
if (options.request !== undefined && hasDirectDecisionFields) {
|
|
2899
|
+
throw new Error("--request cannot be combined with direct decision fields.");
|
|
2900
|
+
}
|
|
2901
|
+
if (options.request !== undefined) {
|
|
2902
|
+
return appendTeamProjectEventV1({
|
|
2903
|
+
workspaceRoot: root,
|
|
2904
|
+
event: readJson(realpathSync(requireOption(options, "request"))),
|
|
2905
|
+
});
|
|
2906
|
+
}
|
|
2907
|
+
if (options.open === options.resolve) {
|
|
2908
|
+
throw new Error("Exactly one of --open or --resolve is required.");
|
|
2909
|
+
}
|
|
2910
|
+
const decisionId = requireOption(options, "decision-id");
|
|
2911
|
+
const occurredAt = requireOption(options, "at");
|
|
2912
|
+
if (options.open === true) {
|
|
2913
|
+
if (options.resolution !== undefined
|
|
2914
|
+
|| options.rationale !== undefined
|
|
2915
|
+
|| options.evidence !== undefined) {
|
|
2916
|
+
throw new Error("Decision open cannot accept resolution, rationale, or evidence.");
|
|
2917
|
+
}
|
|
2918
|
+
if ((options.option ?? []).length === 0) {
|
|
2919
|
+
throw new Error("Decision open requires at least one --option.");
|
|
2920
|
+
}
|
|
2921
|
+
const opened = openTeamProjectDecisionV1({
|
|
2922
|
+
workspaceRoot: root,
|
|
2923
|
+
decisionId,
|
|
2924
|
+
occurredAt,
|
|
2925
|
+
title: requireOption(options, "title"),
|
|
2926
|
+
question: requireOption(options, "question"),
|
|
2927
|
+
ownerAgentId: requireOption(options, "owner-agent"),
|
|
2928
|
+
blockingWorkItemIds: options["blocking-work-item"] ?? [],
|
|
2929
|
+
options: options.option,
|
|
2930
|
+
});
|
|
2931
|
+
return options.json === true
|
|
2932
|
+
? opened
|
|
2933
|
+
: withHumanOutput(opened, formatTeamProjectDecisionHuman(opened));
|
|
2934
|
+
}
|
|
2935
|
+
if (options.title !== undefined
|
|
2936
|
+
|| options.question !== undefined
|
|
2937
|
+
|| options["owner-agent"] !== undefined
|
|
2938
|
+
|| options["blocking-work-item"] !== undefined
|
|
2939
|
+
|| options.option !== undefined) {
|
|
2940
|
+
throw new Error("Decision resolve cannot accept title, question, owner-agent, blocking-work-item, or option.");
|
|
2941
|
+
}
|
|
2942
|
+
if ((options.evidence ?? []).length === 0) {
|
|
2943
|
+
throw new Error("Decision resolve requires at least one --evidence.");
|
|
2944
|
+
}
|
|
2945
|
+
const resolved = resolveTeamProjectDecisionV1({
|
|
2946
|
+
workspaceRoot: root,
|
|
2947
|
+
decisionId,
|
|
2948
|
+
occurredAt,
|
|
2949
|
+
resolution: requireOption(options, "resolution"),
|
|
2950
|
+
rationale: requireOption(options, "rationale"),
|
|
2951
|
+
evidenceRefs: options.evidence,
|
|
2952
|
+
});
|
|
2953
|
+
return options.json === true
|
|
2954
|
+
? resolved
|
|
2955
|
+
: withHumanOutput(resolved, formatTeamProjectDecisionHuman(resolved));
|
|
2956
|
+
}
|
|
2957
|
+
if (action === "verification") {
|
|
2958
|
+
const directVerificationFields = [
|
|
2959
|
+
"defer",
|
|
2960
|
+
"close",
|
|
2961
|
+
"verification-id",
|
|
2962
|
+
"at",
|
|
2963
|
+
"work-item",
|
|
2964
|
+
"owner-agent",
|
|
2965
|
+
"check",
|
|
2966
|
+
"reason",
|
|
2967
|
+
"due-gate",
|
|
2968
|
+
"disposition",
|
|
2969
|
+
"summary",
|
|
2970
|
+
"evidence",
|
|
2971
|
+
"decision",
|
|
2972
|
+
];
|
|
2973
|
+
const hasDirectVerificationFields = directVerificationFields.some(
|
|
2974
|
+
name => options[name] !== undefined,
|
|
2975
|
+
);
|
|
2976
|
+
if (options.request !== undefined && hasDirectVerificationFields) {
|
|
2977
|
+
throw new Error("--request cannot be combined with direct verification fields.");
|
|
2978
|
+
}
|
|
2979
|
+
if (options.request !== undefined) {
|
|
2980
|
+
const requestedEvent = readJson(realpathSync(requireOption(options, "request")));
|
|
2981
|
+
if (!new Set(["verification_deferred", "verification_closed"])
|
|
2982
|
+
.has(requestedEvent?.type)) {
|
|
2983
|
+
throw new Error(
|
|
2984
|
+
"Project verification request only accepts type=verification_deferred or verification_closed.",
|
|
2985
|
+
);
|
|
2986
|
+
}
|
|
2987
|
+
return appendTeamProjectEventV1({
|
|
2988
|
+
workspaceRoot: root,
|
|
2989
|
+
event: requestedEvent,
|
|
2990
|
+
});
|
|
2991
|
+
}
|
|
2992
|
+
if (options.defer === options.close) {
|
|
2993
|
+
throw new Error("Exactly one of --defer or --close is required.");
|
|
2994
|
+
}
|
|
2995
|
+
const verificationId = requireOption(options, "verification-id");
|
|
2996
|
+
const occurredAt = requireOption(options, "at");
|
|
2997
|
+
if (options.defer === true) {
|
|
2998
|
+
if (options.disposition !== undefined
|
|
2999
|
+
|| options.summary !== undefined
|
|
3000
|
+
|| options.evidence !== undefined
|
|
3001
|
+
|| options.decision !== undefined) {
|
|
3002
|
+
throw new Error(
|
|
3003
|
+
"Verification defer cannot accept disposition, summary, evidence, or decision.",
|
|
3004
|
+
);
|
|
3005
|
+
}
|
|
3006
|
+
if ((options.check ?? []).length === 0) {
|
|
3007
|
+
throw new Error("Verification defer requires at least one --check.");
|
|
3008
|
+
}
|
|
3009
|
+
const deferred = deferTeamProjectVerificationV1({
|
|
3010
|
+
workspaceRoot: root,
|
|
3011
|
+
verificationId,
|
|
3012
|
+
occurredAt,
|
|
3013
|
+
workItemId: requireOption(options, "work-item"),
|
|
3014
|
+
ownerAgentId: requireOption(options, "owner-agent"),
|
|
3015
|
+
checkIds: options.check,
|
|
3016
|
+
reason: requireOption(options, "reason"),
|
|
3017
|
+
dueGateId: requireOption(options, "due-gate"),
|
|
3018
|
+
});
|
|
3019
|
+
return options.json === true
|
|
3020
|
+
? deferred
|
|
3021
|
+
: withHumanOutput(deferred, formatTeamProjectVerificationHuman(deferred));
|
|
3022
|
+
}
|
|
3023
|
+
if (options["work-item"] !== undefined
|
|
3024
|
+
|| options["owner-agent"] !== undefined
|
|
3025
|
+
|| options.check !== undefined
|
|
3026
|
+
|| options.reason !== undefined
|
|
3027
|
+
|| options["due-gate"] !== undefined) {
|
|
3028
|
+
throw new Error(
|
|
3029
|
+
"Verification close cannot accept work-item, owner-agent, check, reason, or due-gate.",
|
|
3030
|
+
);
|
|
3031
|
+
}
|
|
3032
|
+
const closed = closeTeamProjectVerificationV1({
|
|
3033
|
+
workspaceRoot: root,
|
|
3034
|
+
verificationId,
|
|
3035
|
+
occurredAt,
|
|
3036
|
+
disposition: requireOption(options, "disposition"),
|
|
3037
|
+
summary: requireOption(options, "summary"),
|
|
3038
|
+
evidenceRefs: options.evidence ?? [],
|
|
3039
|
+
decisionIds: options.decision ?? [],
|
|
3040
|
+
});
|
|
3041
|
+
return options.json === true
|
|
3042
|
+
? closed
|
|
3043
|
+
: withHumanOutput(closed, formatTeamProjectVerificationHuman(closed));
|
|
3044
|
+
}
|
|
3045
|
+
if (action === "checkpoint") {
|
|
3046
|
+
const directCheckpointFields = [
|
|
3047
|
+
"checkpoint-id",
|
|
3048
|
+
"at",
|
|
3049
|
+
"assignment-id",
|
|
3050
|
+
"work-item",
|
|
3051
|
+
"state",
|
|
3052
|
+
"summary",
|
|
3053
|
+
"completed-units",
|
|
3054
|
+
"evidence",
|
|
3055
|
+
"blocker",
|
|
3056
|
+
"decision",
|
|
3057
|
+
"next",
|
|
3058
|
+
"source-fingerprint",
|
|
3059
|
+
];
|
|
3060
|
+
const hasDirectCheckpointFields = directCheckpointFields.some(
|
|
3061
|
+
name => options[name] !== undefined,
|
|
3062
|
+
);
|
|
3063
|
+
if (options.request !== undefined && hasDirectCheckpointFields) {
|
|
3064
|
+
throw new Error("--request cannot be combined with direct checkpoint fields.");
|
|
3065
|
+
}
|
|
3066
|
+
if (options.request !== undefined) {
|
|
3067
|
+
const requestedEvent = readJson(realpathSync(requireOption(options, "request")));
|
|
3068
|
+
if (requestedEvent?.type !== "checkpoint_recorded") {
|
|
3069
|
+
throw new Error("Project checkpoint request only accepts type=checkpoint_recorded.");
|
|
3070
|
+
}
|
|
3071
|
+
return appendTeamProjectEventV1({
|
|
3072
|
+
workspaceRoot: root,
|
|
3073
|
+
event: requestedEvent,
|
|
3074
|
+
});
|
|
3075
|
+
}
|
|
3076
|
+
const completedUnits = options["completed-units"] === undefined
|
|
3077
|
+
? undefined
|
|
3078
|
+
: parseCanonicalNonnegativeSafeInteger(options["completed-units"], "completed-units");
|
|
3079
|
+
const checkpointed = checkpointTeamProjectV1({
|
|
3080
|
+
workspaceRoot: root,
|
|
3081
|
+
checkpointId: requireOption(options, "checkpoint-id"),
|
|
3082
|
+
occurredAt: requireOption(options, "at"),
|
|
3083
|
+
assignmentId: requireOption(options, "assignment-id"),
|
|
3084
|
+
workItemId: requireOption(options, "work-item"),
|
|
3085
|
+
state: requireOption(options, "state"),
|
|
3086
|
+
summary: requireOption(options, "summary"),
|
|
3087
|
+
completedUnits,
|
|
3088
|
+
evidenceRefs: options.evidence ?? [],
|
|
3089
|
+
blockerRefs: options.blocker ?? [],
|
|
3090
|
+
decisionRefs: options.decision ?? [],
|
|
3091
|
+
nextAction: options.next ?? null,
|
|
3092
|
+
sourceFingerprint: options["source-fingerprint"],
|
|
3093
|
+
});
|
|
3094
|
+
return options.json === true
|
|
3095
|
+
? checkpointed
|
|
3096
|
+
: withHumanOutput(checkpointed, formatTeamProjectCheckpointHuman(checkpointed));
|
|
3097
|
+
}
|
|
3098
|
+
if (action === "integrate") {
|
|
3099
|
+
const directIntegrationFields = ["gate", "at", "summary", "evidence"];
|
|
3100
|
+
const hasDirectIntegrationFields = directIntegrationFields.some(
|
|
3101
|
+
name => options[name] !== undefined,
|
|
3102
|
+
);
|
|
3103
|
+
if (options.request !== undefined && hasDirectIntegrationFields) {
|
|
3104
|
+
throw new Error("--request cannot be combined with direct integrate fields.");
|
|
3105
|
+
}
|
|
3106
|
+
if (options.request !== undefined) {
|
|
3107
|
+
const requestedEvent = readJson(realpathSync(requireOption(options, "request")));
|
|
3108
|
+
if (requestedEvent?.type !== "integration_gate_passed") {
|
|
3109
|
+
throw new Error("Project integrate request only accepts type=integration_gate_passed.");
|
|
3110
|
+
}
|
|
3111
|
+
return appendTeamProjectEventV1({
|
|
3112
|
+
workspaceRoot: root,
|
|
3113
|
+
event: requestedEvent,
|
|
3114
|
+
});
|
|
3115
|
+
}
|
|
3116
|
+
const evidenceRefs = options.evidence ?? [];
|
|
3117
|
+
if (evidenceRefs.length === 0) {
|
|
3118
|
+
throw new Error("Project integrate requires at least one --evidence.");
|
|
3119
|
+
}
|
|
3120
|
+
const integrated = integrateTeamProjectV1({
|
|
3121
|
+
workspaceRoot: root,
|
|
3122
|
+
gateId: requireOption(options, "gate"),
|
|
3123
|
+
occurredAt: requireOption(options, "at"),
|
|
3124
|
+
summary: requireOption(options, "summary"),
|
|
3125
|
+
evidenceRefs,
|
|
3126
|
+
});
|
|
3127
|
+
return options.json === true
|
|
3128
|
+
? integrated
|
|
3129
|
+
: withHumanOutput(integrated, formatTeamProjectIntegrationHuman(integrated));
|
|
3130
|
+
}
|
|
3131
|
+
if (new Set(["checkpoint", "capture"]).has(action)) {
|
|
2424
3132
|
return appendTeamProjectEventV1({
|
|
2425
3133
|
workspaceRoot: root,
|
|
2426
3134
|
event: readJson(realpathSync(requireOption(options, "request"))),
|
|
@@ -2439,15 +3147,22 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2439
3147
|
});
|
|
2440
3148
|
return options.json === true
|
|
2441
3149
|
? takeover
|
|
2442
|
-
: withHumanOutput(takeover,
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
3150
|
+
: withHumanOutput(takeover, formatTeamProjectTakeoverHumanV1(takeover));
|
|
3151
|
+
}
|
|
3152
|
+
if (action === "successor") {
|
|
3153
|
+
const successor = successorTeamProjectV1({
|
|
3154
|
+
workspaceRoot: root,
|
|
3155
|
+
transitionId: requireOption(options, "transition-id"),
|
|
3156
|
+
occurredAt: requireOption(options, "at"),
|
|
3157
|
+
definitionPath: requireOption(options, "definition"),
|
|
3158
|
+
reason: requireOption(options, "reason"),
|
|
3159
|
+
onDurableStep: runtimeHooks.onTeamProjectSuccessorStep,
|
|
3160
|
+
});
|
|
3161
|
+
return options.json === true
|
|
3162
|
+
? successor
|
|
3163
|
+
: withHumanOutput(successor, formatTeamProjectSuccessorHumanV1(successor));
|
|
2449
3164
|
}
|
|
2450
|
-
throw new Error("Usage: owlrunkit project <init|assign|checkpoint|handoff|decision|capture|status|takeover> [options]");
|
|
3165
|
+
throw new Error("Usage: owlrunkit project <init|assign|checkpoint|handoff|decision|verification|integrate|capture|status|takeover|successor> [options]");
|
|
2451
3166
|
}
|
|
2452
3167
|
if (command === "profiles") {
|
|
2453
3168
|
const root = requireOption(options, "workspace");
|
|
@@ -2463,13 +3178,25 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2463
3178
|
? applyDetectedProfilesV2({ workspaceRoot: root, detection })
|
|
2464
3179
|
: detection;
|
|
2465
3180
|
}
|
|
3181
|
+
if (action === "reconcile") {
|
|
3182
|
+
if (options.apply === true && options["dry-run"] === true) {
|
|
3183
|
+
throw new Error("profiles reconcile accepts either --apply or --dry-run, not both.");
|
|
3184
|
+
}
|
|
3185
|
+
if (options.apply !== true && options["dry-run"] !== true) {
|
|
3186
|
+
throw new Error("profiles reconcile requires --dry-run or --apply.");
|
|
3187
|
+
}
|
|
3188
|
+
return reconcileProfilesV2({
|
|
3189
|
+
workspaceRoot: root,
|
|
3190
|
+
apply: options.apply === true,
|
|
3191
|
+
});
|
|
3192
|
+
}
|
|
2466
3193
|
if (action === "validate") return validateProfiles({ workspaceRoot: root });
|
|
2467
3194
|
if (action === "impact") {
|
|
2468
3195
|
const changedPaths = options.changed ?? [];
|
|
2469
3196
|
if (changedPaths.length === 0) throw new Error("profiles impact requires --changed.");
|
|
2470
3197
|
return resolveProfilesImpact({ workspaceRoot: root, changedPaths });
|
|
2471
3198
|
}
|
|
2472
|
-
throw new Error("Usage: owlrunkit profiles <detect|validate|impact> [options]");
|
|
3199
|
+
throw new Error("Usage: owlrunkit profiles <detect|reconcile|validate|impact> [options]");
|
|
2473
3200
|
}
|
|
2474
3201
|
if (command === "lease") {
|
|
2475
3202
|
const root = workspace(options);
|
|
@@ -2612,7 +3339,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2612
3339
|
return withControlTransaction(root, () => closeout(options));
|
|
2613
3340
|
}
|
|
2614
3341
|
if (command === "finish") return finishExecution(options);
|
|
2615
|
-
throw new Error("Usage: owlrunkit <init|doctor|adopt|assurance|fleet|profiles|project|status|formal|candidate|deployment|core-successor|start|verify|repair|offline-export|offline-import|quick-verify|quick-attest|quick-metrics|finish|plan|inspect|lease|delivery|coverage-adopt|resume|verify-plan|resource-preflight|snapshot|visual-smoke|finalize|ready-for-commit|closeout> [options]");
|
|
3342
|
+
throw new Error("Usage: owlrunkit <init|doctor|adopt|mode|assurance|fleet|profiles|project|status|formal|candidate|deployment|core-successor|start|verify|repair|offline-export|offline-import|quick-verify|quick-attest|quick-metrics|finish|plan|inspect|lease|delivery|coverage-adopt|resume|verify-plan|resource-preflight|snapshot|visual-smoke|finalize|ready-for-commit|closeout> [options]");
|
|
2616
3343
|
} catch (error) {
|
|
2617
3344
|
return {
|
|
2618
3345
|
status: "invalid_input",
|