owlrunkit 0.16.1 → 0.17.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 +32 -0
- package/README.md +48 -9
- package/docs/architecture/OWLCODA_RUNKIT_017_AGENT_NATIVE_PRODUCT_DEFINITION.md +154 -0
- package/integrations/codex/skills/owlcoda-runkit/SKILL.md +59 -14
- package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
- package/package.json +1 -1
- 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 +12 -2
- package/scripts/runkit-contract/formal-workflow.mjs +201 -0
- package/scripts/runkit-contract/lifecycle-orchestration.mjs +7 -2
- package/scripts/runkit-contract/project-cli-resolver.mjs +3 -0
- package/scripts/runkit-contract/runkit-cli.mjs +99 -8
- package/scripts/runkit-contract/schemas/team-project-definition-v1.schema.json +108 -0
- package/scripts/runkit-contract/schemas/team-project-event-v1.schema.json +99 -0
- package/scripts/runkit-contract/schemas/team-project-status-v1.schema.json +50 -0
- package/scripts/runkit-contract/schemas/verification-envelope-v1.schema.json +102 -0
- package/scripts/runkit-contract/sync-release-identity.mjs +224 -0
- package/scripts/runkit-contract/team-project.mjs +1008 -0
- package/scripts/runkit-contract/templates/team-project-definition.json +30 -0
- package/scripts/runkit-contract/templates/team-project-event.json +9 -0
- package/scripts/runkit-contract/templates/verification-envelope.json +28 -0
- package/scripts/runkit-contract/verification-envelope-check.mjs +45 -0
- package/scripts/runkit-contract/verification-envelope.mjs +846 -0
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
realpathSync,
|
|
7
7
|
} from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
9
10
|
|
|
10
11
|
import {
|
|
11
12
|
acceptedCloseoutVerificationIssues,
|
|
@@ -33,6 +34,16 @@ import {
|
|
|
33
34
|
} from "./source-candidate.mjs";
|
|
34
35
|
import { validateReceiptLineage } from "./receipt-lineage.mjs";
|
|
35
36
|
import { verificationContextFingerprint } from "./verification-context.mjs";
|
|
37
|
+
import {
|
|
38
|
+
runVerificationEnvelopeV1,
|
|
39
|
+
validateVerificationEnvelopeV1,
|
|
40
|
+
verifyVerificationEnvelopeReceiptV1,
|
|
41
|
+
} from "./verification-envelope.mjs";
|
|
42
|
+
|
|
43
|
+
const VERIFICATION_ENVELOPE_CHECKER = fileURLToPath(new URL(
|
|
44
|
+
"./verification-envelope-check.mjs",
|
|
45
|
+
import.meta.url,
|
|
46
|
+
));
|
|
36
47
|
|
|
37
48
|
const FORBIDDEN_EXTERNAL_TOOLS = new Set([
|
|
38
49
|
"curl",
|
|
@@ -623,6 +634,184 @@ export function recordFormalCheckV1(options) {
|
|
|
623
634
|
);
|
|
624
635
|
}
|
|
625
636
|
|
|
637
|
+
async function recordFormalEnvelopeCheckWithinControlTransaction({
|
|
638
|
+
workspaceRoot,
|
|
639
|
+
runId,
|
|
640
|
+
workItemId,
|
|
641
|
+
checkId,
|
|
642
|
+
envelope,
|
|
643
|
+
hooks = {},
|
|
644
|
+
}) {
|
|
645
|
+
safeIdentifier(checkId, "checkId");
|
|
646
|
+
const root = realpathSync(workspaceRoot);
|
|
647
|
+
const { executionRoot, pinGate } = loadActiveExecution(root, runId);
|
|
648
|
+
if (pinGate.status !== "valid") return { ...pinGate, authorizationGranted: false };
|
|
649
|
+
const validatedEnvelope = validateVerificationEnvelopeV1({
|
|
650
|
+
workspaceRoot: root,
|
|
651
|
+
envelope,
|
|
652
|
+
});
|
|
653
|
+
const receiptPath = path.join(checkRoot(executionRoot), `${checkId}.json`);
|
|
654
|
+
const candidateResult = resumeOrFreezeCandidate({
|
|
655
|
+
workspaceRoot: root,
|
|
656
|
+
executionRoot,
|
|
657
|
+
runId,
|
|
658
|
+
workItemId,
|
|
659
|
+
checkId,
|
|
660
|
+
});
|
|
661
|
+
const candidate = candidateResult.candidate;
|
|
662
|
+
if (candidate.status !== "source_candidate_frozen") return candidate;
|
|
663
|
+
hooks.afterCandidatePersist?.();
|
|
664
|
+
const candidateDocument = readJson(path.join(root, candidate.candidatePath));
|
|
665
|
+
const envelopePath = path.join(
|
|
666
|
+
executionRoot,
|
|
667
|
+
"formal-envelopes",
|
|
668
|
+
`${checkId}.json`,
|
|
669
|
+
);
|
|
670
|
+
const envelopeResult = writeOrResumeExactJson(
|
|
671
|
+
envelopePath,
|
|
672
|
+
validatedEnvelope.envelope,
|
|
673
|
+
"Formal Verification Envelope",
|
|
674
|
+
);
|
|
675
|
+
const envelopeArtifactRoot = path.join(
|
|
676
|
+
executionRoot,
|
|
677
|
+
"verification-envelopes",
|
|
678
|
+
checkId,
|
|
679
|
+
);
|
|
680
|
+
const envelopeReceipt = await runVerificationEnvelopeV1({
|
|
681
|
+
workspaceRoot: root,
|
|
682
|
+
envelope: envelopeResult.value,
|
|
683
|
+
artifactRoot: envelopeArtifactRoot,
|
|
684
|
+
});
|
|
685
|
+
hooks.afterEnvelopePersist?.();
|
|
686
|
+
const commandArgv = [
|
|
687
|
+
realpathSync(process.execPath),
|
|
688
|
+
VERIFICATION_ENVELOPE_CHECKER,
|
|
689
|
+
"--workspace",
|
|
690
|
+
root,
|
|
691
|
+
"--receipt",
|
|
692
|
+
envelopeReceipt.receiptPath,
|
|
693
|
+
];
|
|
694
|
+
const verificationCommandPolicy = {
|
|
695
|
+
schemaVersion: "OwlCodaRunKitFormalVerificationCommandPolicyV1",
|
|
696
|
+
mode: "verification_envelope_v1",
|
|
697
|
+
riskClassification: "enforced_verification_envelope",
|
|
698
|
+
profileCommandIds: [],
|
|
699
|
+
executable: commandArgv[0],
|
|
700
|
+
argv: commandArgv.slice(1),
|
|
701
|
+
envelopeSha256: validatedEnvelope.envelopeSha256,
|
|
702
|
+
envelopeReceiptSha256: envelopeReceipt.receiptSha256,
|
|
703
|
+
authorizationGranted: false,
|
|
704
|
+
};
|
|
705
|
+
const context = derivedVerificationContext(root);
|
|
706
|
+
const request = {
|
|
707
|
+
schemaVersion: "OwlCodaRunKitSnapshotRequestV1",
|
|
708
|
+
snapshotId: `${checkId}-snapshot`,
|
|
709
|
+
mode: "project",
|
|
710
|
+
targetRoot: root,
|
|
711
|
+
cwd: ".",
|
|
712
|
+
executable: verificationCommandPolicy.executable,
|
|
713
|
+
argv: verificationCommandPolicy.argv,
|
|
714
|
+
launcherVersion: "owlrunkit-formal-envelope-v1",
|
|
715
|
+
toolVersions: structuredClone(context.toolchains),
|
|
716
|
+
selectedPaths: candidateDocument.sourceManifest.entries
|
|
717
|
+
.filter((entry) => entry.operation !== "deleted")
|
|
718
|
+
.map((entry) => entry.path)
|
|
719
|
+
.sort(),
|
|
720
|
+
statusMode: "porcelain-v1-z-untracked-all-runkit-excluded",
|
|
721
|
+
verificationContext: context,
|
|
722
|
+
};
|
|
723
|
+
const requestPath = path.join(
|
|
724
|
+
executionRoot,
|
|
725
|
+
"formal-check-requests",
|
|
726
|
+
`${checkId}.json`,
|
|
727
|
+
);
|
|
728
|
+
const requestResult = writeOrResumeExactJson(
|
|
729
|
+
requestPath,
|
|
730
|
+
request,
|
|
731
|
+
"Formal check request",
|
|
732
|
+
);
|
|
733
|
+
hooks.afterRequestPersist?.();
|
|
734
|
+
const snapshotResult = resumeSnapshot({
|
|
735
|
+
workspaceRoot: root,
|
|
736
|
+
executionRoot,
|
|
737
|
+
runId,
|
|
738
|
+
request: requestResult.value,
|
|
739
|
+
candidateDocument,
|
|
740
|
+
});
|
|
741
|
+
const snapshot = snapshotResult.snapshot;
|
|
742
|
+
hooks.afterSnapshotPersist?.();
|
|
743
|
+
const savedSnapshot = readJson(path.join(root, snapshot.snapshotPath));
|
|
744
|
+
const existingReceipt = existsSync(receiptPath)
|
|
745
|
+
? readRegularJson(receiptPath, "Formal check receipt")
|
|
746
|
+
: null;
|
|
747
|
+
const sequence = existingReceipt?.sequence
|
|
748
|
+
?? readChecks(executionRoot).length + 1;
|
|
749
|
+
const status = snapshot.status === "snapshot_passed"
|
|
750
|
+
&& envelopeReceipt.formalEligible
|
|
751
|
+
? "formal_check_passed"
|
|
752
|
+
: "formal_check_failed";
|
|
753
|
+
const receipt = {
|
|
754
|
+
schemaVersion: "OwlCodaRunKitFormalCheckV1",
|
|
755
|
+
runId,
|
|
756
|
+
checkId,
|
|
757
|
+
sequence,
|
|
758
|
+
status,
|
|
759
|
+
candidatePath: candidate.candidatePath,
|
|
760
|
+
candidateSha256: candidate.candidateSha256,
|
|
761
|
+
payloadSha256: candidate.payloadSha256,
|
|
762
|
+
sourceFingerprint: candidate.sourceFingerprint,
|
|
763
|
+
verificationContext: context,
|
|
764
|
+
verificationContextFingerprint: verificationContextFingerprint(context),
|
|
765
|
+
snapshotRequestPath: relativeToWorkspace(root, requestPath),
|
|
766
|
+
snapshotPath: snapshot.snapshotPath,
|
|
767
|
+
commandExitCode: savedSnapshot.command.exitCode,
|
|
768
|
+
verificationCommandPolicy: {
|
|
769
|
+
schemaVersion: verificationCommandPolicy.schemaVersion,
|
|
770
|
+
mode: verificationCommandPolicy.mode,
|
|
771
|
+
riskClassification: verificationCommandPolicy.riskClassification,
|
|
772
|
+
profileCommandIds: verificationCommandPolicy.profileCommandIds,
|
|
773
|
+
envelopeSha256: verificationCommandPolicy.envelopeSha256,
|
|
774
|
+
envelopeReceiptSha256: verificationCommandPolicy.envelopeReceiptSha256,
|
|
775
|
+
authorizationGranted: false,
|
|
776
|
+
},
|
|
777
|
+
envelopePath: relativeToWorkspace(root, envelopePath),
|
|
778
|
+
envelopeSha256: validatedEnvelope.envelopeSha256,
|
|
779
|
+
envelopeReceiptPath: relativeToWorkspace(root, envelopeReceipt.receiptPath),
|
|
780
|
+
envelopeReceiptSha256: envelopeReceipt.receiptSha256,
|
|
781
|
+
envelopeFormalEligible: envelopeReceipt.formalEligible,
|
|
782
|
+
finalized: false,
|
|
783
|
+
authorizationGranted: false,
|
|
784
|
+
};
|
|
785
|
+
const receiptResult = writeOrResumeExactJson(
|
|
786
|
+
receiptPath,
|
|
787
|
+
receipt,
|
|
788
|
+
"Formal check receipt",
|
|
789
|
+
);
|
|
790
|
+
hooks.afterReceiptPersist?.();
|
|
791
|
+
return {
|
|
792
|
+
...receiptResult.value,
|
|
793
|
+
exitCode: status === "formal_check_passed" ? 0 : 2,
|
|
794
|
+
checkReceiptPath: relativeToWorkspace(root, receiptPath),
|
|
795
|
+
resumed: candidateResult.resumed
|
|
796
|
+
|| envelopeResult.resumed
|
|
797
|
+
|| envelopeReceipt.resumed
|
|
798
|
+
|| requestResult.resumed
|
|
799
|
+
|| snapshotResult.resumed
|
|
800
|
+
|| receiptResult.resumed,
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
export function recordFormalEnvelopeCheckV1(options) {
|
|
805
|
+
const workspaceRoot = realpathSync(options.workspaceRoot);
|
|
806
|
+
return withControlTransaction(
|
|
807
|
+
workspaceRoot,
|
|
808
|
+
() => recordFormalEnvelopeCheckWithinControlTransaction({
|
|
809
|
+
...options,
|
|
810
|
+
workspaceRoot,
|
|
811
|
+
}),
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
|
|
626
815
|
function finalizeFormalChecksWithinControlTransaction({
|
|
627
816
|
workspaceRoot,
|
|
628
817
|
runId,
|
|
@@ -651,6 +840,18 @@ function finalizeFormalChecksWithinControlTransaction({
|
|
|
651
840
|
if (latest.status !== "formal_check_passed" || selected.length === 0) {
|
|
652
841
|
throw new Error("Formal finish requires the latest source to have a passed check.");
|
|
653
842
|
}
|
|
843
|
+
for (const check of selected) {
|
|
844
|
+
if (!check.envelopeReceiptPath) continue;
|
|
845
|
+
const verifiedEnvelope = verifyVerificationEnvelopeReceiptV1({
|
|
846
|
+
workspaceRoot: root,
|
|
847
|
+
receiptPath: path.join(root, check.envelopeReceiptPath),
|
|
848
|
+
});
|
|
849
|
+
if (!verifiedEnvelope.formalEligible
|
|
850
|
+
|| verifiedEnvelope.receiptSha256 !== check.envelopeReceiptSha256
|
|
851
|
+
|| verifiedEnvelope.envelopeSha256 !== check.envelopeSha256) {
|
|
852
|
+
throw new Error(`Formal finish requires a valid Formal-eligible envelope receipt: ${check.checkId}.`);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
654
855
|
const request = {
|
|
655
856
|
schemaVersion: "OwlCodaRunKitFinalizeRequestV1",
|
|
656
857
|
receiptId: `${finalizeId}-receipt`,
|
|
@@ -486,6 +486,7 @@ export function activeAcceptedGate({ workspaceRoot, runId }) {
|
|
|
486
486
|
}
|
|
487
487
|
}
|
|
488
488
|
const distinctMatchingPackets = collapseByteIdenticalDeliveryCandidates(matchingPackets);
|
|
489
|
+
const declaredSourceArtifact = validated.active.receipt.sourceArtifact;
|
|
489
490
|
let matchingCandidate = null;
|
|
490
491
|
if (distinctMatchingPackets.length === 0) {
|
|
491
492
|
const candidateRoot = path.join(executionRoot, "source-candidates");
|
|
@@ -524,7 +525,12 @@ export function activeAcceptedGate({ workspaceRoot, runId }) {
|
|
|
524
525
|
candidates.map(({ candidate }) => candidate.sourceManifest.sha256),
|
|
525
526
|
);
|
|
526
527
|
if (manifestFingerprints.size === 1) {
|
|
527
|
-
|
|
528
|
+
matchingCandidate = candidates.find(({ candidatePath }) => (
|
|
529
|
+
declaredSourceArtifact?.kind === "source_candidate_v2"
|
|
530
|
+
&& declaredSourceArtifact.path
|
|
531
|
+
=== relativeToWorkspace(workspaceRoot, candidatePath)
|
|
532
|
+
&& declaredSourceArtifact.sha256 === sha256(readFileSync(candidatePath))
|
|
533
|
+
)) ?? candidates[0];
|
|
528
534
|
}
|
|
529
535
|
}
|
|
530
536
|
if (
|
|
@@ -537,7 +543,6 @@ export function activeAcceptedGate({ workspaceRoot, runId }) {
|
|
|
537
543
|
throw new Error("Accepted finish requires one fresh source binding matching the active verification gate; source drift remains unresolved.");
|
|
538
544
|
}
|
|
539
545
|
const [matchingPacket] = distinctMatchingPackets;
|
|
540
|
-
const declaredSourceArtifact = validated.active.receipt.sourceArtifact;
|
|
541
546
|
if (declaredSourceArtifact !== undefined) {
|
|
542
547
|
const selectedPath = matchingCandidate === null
|
|
543
548
|
? matchingPacket.packetPath
|
|
@@ -18,6 +18,9 @@ const OFFICIAL_CLI_ENTRYPOINT =
|
|
|
18
18
|
const EXACT_VERSION = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/;
|
|
19
19
|
const SHA256_REF = /^sha256:[a-f0-9]{64}$/;
|
|
20
20
|
const TRUSTED_PRIOR_CORE_IDENTITIES = new Map([
|
|
21
|
+
["0.17.0", new Set([
|
|
22
|
+
"sha256:0c0c52e7f6299bdd3d3ea49005c8ceef0b28831d60af25d77da65a4e4de714c9",
|
|
23
|
+
])],
|
|
21
24
|
["0.16.0", new Set([
|
|
22
25
|
"sha256:320fb1d97b4459d1a14b0b67807dcf2bc6b03970492cb9fb2c6245b17912c81e",
|
|
23
26
|
])],
|
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
import {
|
|
66
66
|
finalizeFormalChecksV1,
|
|
67
67
|
recordFormalCheckV1,
|
|
68
|
+
recordFormalEnvelopeCheckV1,
|
|
68
69
|
resumeCompletedFormalFinishV1,
|
|
69
70
|
validateLegacyVerificationSideEffectsV1,
|
|
70
71
|
} from "./formal-workflow.mjs";
|
|
@@ -135,6 +136,13 @@ import {
|
|
|
135
136
|
runRegistryAdoption,
|
|
136
137
|
} from "./registry-adoption.mjs";
|
|
137
138
|
import { OFFICIAL_NPM_REGISTRY } from "./registry-adoption-gate.mjs";
|
|
139
|
+
import {
|
|
140
|
+
appendTeamProjectEventV1,
|
|
141
|
+
buildTeamProjectTakeoverV1,
|
|
142
|
+
formatTeamProjectStatusHumanV1,
|
|
143
|
+
initializeTeamProjectV1,
|
|
144
|
+
readTeamProjectStatusV1,
|
|
145
|
+
} from "./team-project.mjs";
|
|
138
146
|
|
|
139
147
|
const TOP_LEVEL_HELP = `OwlRunKit ${CORE_VERSION}
|
|
140
148
|
|
|
@@ -170,16 +178,16 @@ Fleet and status
|
|
|
170
178
|
owlrunkit fleet rollback-registry --receipt <file> --rollback-receipt <file>
|
|
171
179
|
owlrunkit fleet discover; owlrunkit status --workspace .
|
|
172
180
|
|
|
181
|
+
Agent team projects
|
|
182
|
+
owlrunkit project <init|assign|checkpoint|handoff|decision|capture|status|takeover> [options]
|
|
183
|
+
Durable Agent work, dependencies, decisions, gates, progress, and handoffs.
|
|
173
184
|
Core successor
|
|
174
185
|
owlrunkit core-successor <plan|apply|resume> --workspace . [...]
|
|
175
186
|
|
|
176
187
|
Other onboarding commands:
|
|
177
|
-
owlrunkit profiles validate --workspace .
|
|
178
|
-
owlrunkit profiles impact --workspace . --changed <path>
|
|
188
|
+
owlrunkit profiles validate --workspace .; owlrunkit profiles impact --workspace . --changed <path>
|
|
179
189
|
owlrunkit inspect --workspace . --json
|
|
180
|
-
|
|
181
|
-
Quick receipts cannot become Formal acceptance.
|
|
182
|
-
Formal accepted does not grant Git or release authority.
|
|
190
|
+
Formal accepted does not grant Git or release authority; Quick cannot become Formal.
|
|
183
191
|
`;
|
|
184
192
|
|
|
185
193
|
const COMMAND_HELP = Object.freeze({
|
|
@@ -255,7 +263,12 @@ Creates the execution and exact writer lease.
|
|
|
255
263
|
`,
|
|
256
264
|
"formal check": `Usage:
|
|
257
265
|
owlrunkit formal check --workspace <directory> --run-id <id>
|
|
258
|
-
--work-item <id> --check-id <id> --
|
|
266
|
+
--work-item <id> --check-id <id> --envelope <verification-envelope.json>
|
|
267
|
+
owlrunkit formal check --workspace <directory> --run-id <id>
|
|
268
|
+
--work-item <id> --check-id <id> --cwd <directory> -- <built-in-command> [args...]
|
|
269
|
+
|
|
270
|
+
Verification Envelopes admit real project commands only when file, network,
|
|
271
|
+
process, environment, output, timeout, and cleanup constraints are enforced.
|
|
259
272
|
`,
|
|
260
273
|
"formal finish": `Usage:
|
|
261
274
|
owlrunkit formal finish --workspace <directory> --run-id <id>
|
|
@@ -324,6 +337,24 @@ profile, preflight, lineage, and result. --request is an advanced legacy path.
|
|
|
324
337
|
|
|
325
338
|
Shows completed milestones, current state, remaining gates, and the next allowed
|
|
326
339
|
action without granting any authority.
|
|
340
|
+
`,
|
|
341
|
+
project: `Usage:
|
|
342
|
+
owlrunkit project init --workspace <directory> --definition <project.json>
|
|
343
|
+
owlrunkit project <assign|checkpoint|handoff|decision|capture> --workspace <directory> --request <event.json>
|
|
344
|
+
owlrunkit project status --workspace <directory> [--json]
|
|
345
|
+
owlrunkit project takeover --workspace <directory> --agent <id> [--json]
|
|
346
|
+
|
|
347
|
+
Project status is derived from durable work items, Agent assignments,
|
|
348
|
+
dependencies, decisions, checkpoints, integration gates, and evidence refs.
|
|
349
|
+
No self-reported percentage is accepted.
|
|
350
|
+
`,
|
|
351
|
+
"project status": `Usage:
|
|
352
|
+
owlrunkit project status --workspace <directory> [--json]
|
|
353
|
+
`,
|
|
354
|
+
"project takeover": `Usage:
|
|
355
|
+
owlrunkit project takeover --workspace <directory> --agent <id> [--json]
|
|
356
|
+
|
|
357
|
+
Builds a read-only blank-session recovery packet for one Agent.
|
|
327
358
|
`,
|
|
328
359
|
});
|
|
329
360
|
|
|
@@ -1589,6 +1620,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
1589
1620
|
"formal",
|
|
1590
1621
|
"lease",
|
|
1591
1622
|
"profiles",
|
|
1623
|
+
"project",
|
|
1592
1624
|
]).has(command);
|
|
1593
1625
|
const [action, ...nestedOptions] = nested ? optionValues : [null, ...optionValues];
|
|
1594
1626
|
const helpRequested = optionValues.includes("--help")
|
|
@@ -1623,6 +1655,8 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
1623
1655
|
? ["json", "verbose", "history"]
|
|
1624
1656
|
: command === "init"
|
|
1625
1657
|
? ["json"]
|
|
1658
|
+
: command === "project" && new Set(["status", "takeover"]).has(action)
|
|
1659
|
+
? ["json"]
|
|
1626
1660
|
: command === "doctor" || command === "adopt" || command === "status"
|
|
1627
1661
|
? ["json"]
|
|
1628
1662
|
: command === "profiles"
|
|
@@ -2230,10 +2264,30 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2230
2264
|
});
|
|
2231
2265
|
}
|
|
2232
2266
|
if (action === "check") {
|
|
2267
|
+
const workItemId = options["work-item"] ?? options["from-lease"] ?? "delivery";
|
|
2268
|
+
if (
|
|
2269
|
+
options["work-item"] !== undefined
|
|
2270
|
+
&& options["from-lease"] !== undefined
|
|
2271
|
+
&& options["work-item"] !== options["from-lease"]
|
|
2272
|
+
) {
|
|
2273
|
+
throw new Error("formal check work-item and legacy from-lease must match.");
|
|
2274
|
+
}
|
|
2275
|
+
if (options.envelope !== undefined) {
|
|
2276
|
+
if (commandArgv.length > 0) {
|
|
2277
|
+
throw new Error("formal check accepts either --envelope or an exact built-in command, not both.");
|
|
2278
|
+
}
|
|
2279
|
+
return await recordFormalEnvelopeCheckV1({
|
|
2280
|
+
workspaceRoot: workspace(options),
|
|
2281
|
+
runId: safeRunId(requireOption(options, "run-id")),
|
|
2282
|
+
workItemId,
|
|
2283
|
+
checkId: requireOption(options, "check-id"),
|
|
2284
|
+
envelope: readJson(realpathSync(requireOption(options, "envelope"))),
|
|
2285
|
+
});
|
|
2286
|
+
}
|
|
2233
2287
|
return recordFormalCheckV1({
|
|
2234
2288
|
workspaceRoot: workspace(options),
|
|
2235
2289
|
runId: safeRunId(requireOption(options, "run-id")),
|
|
2236
|
-
workItemId
|
|
2290
|
+
workItemId,
|
|
2237
2291
|
checkId: requireOption(options, "check-id"),
|
|
2238
2292
|
cwd: options.cwd ?? ".",
|
|
2239
2293
|
commandArgv,
|
|
@@ -2350,6 +2404,43 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2350
2404
|
].join("\n"),
|
|
2351
2405
|
);
|
|
2352
2406
|
}
|
|
2407
|
+
if (command === "project") {
|
|
2408
|
+
const root = requireOption(options, "workspace");
|
|
2409
|
+
if (action === "init") {
|
|
2410
|
+
return initializeTeamProjectV1({
|
|
2411
|
+
workspaceRoot: root,
|
|
2412
|
+
definition: readJson(realpathSync(requireOption(options, "definition"))),
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2415
|
+
if (new Set(["assign", "checkpoint", "handoff", "decision", "capture"]).has(action)) {
|
|
2416
|
+
return appendTeamProjectEventV1({
|
|
2417
|
+
workspaceRoot: root,
|
|
2418
|
+
event: readJson(realpathSync(requireOption(options, "request"))),
|
|
2419
|
+
});
|
|
2420
|
+
}
|
|
2421
|
+
if (action === "status") {
|
|
2422
|
+
const status = readTeamProjectStatusV1({ workspaceRoot: root });
|
|
2423
|
+
return options.json === true
|
|
2424
|
+
? status
|
|
2425
|
+
: withHumanOutput(status, formatTeamProjectStatusHumanV1(status));
|
|
2426
|
+
}
|
|
2427
|
+
if (action === "takeover") {
|
|
2428
|
+
const takeover = buildTeamProjectTakeoverV1({
|
|
2429
|
+
workspaceRoot: root,
|
|
2430
|
+
agentId: requireOption(options, "agent"),
|
|
2431
|
+
});
|
|
2432
|
+
return options.json === true
|
|
2433
|
+
? takeover
|
|
2434
|
+
: withHumanOutput(takeover, [
|
|
2435
|
+
`${takeover.projectId}: ${takeover.objective}`,
|
|
2436
|
+
`Agent: ${takeover.agentId}`,
|
|
2437
|
+
`Responsibility: ${takeover.currentResponsibility?.workItemId ?? "none"}`,
|
|
2438
|
+
`Next: ${takeover.nextAction ?? "none"}`,
|
|
2439
|
+
"",
|
|
2440
|
+
].join("\n"));
|
|
2441
|
+
}
|
|
2442
|
+
throw new Error("Usage: owlrunkit project <init|assign|checkpoint|handoff|decision|capture|status|takeover> [options]");
|
|
2443
|
+
}
|
|
2353
2444
|
if (command === "profiles") {
|
|
2354
2445
|
const root = requireOption(options, "workspace");
|
|
2355
2446
|
if (action === "detect") {
|
|
@@ -2513,7 +2604,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
|
|
|
2513
2604
|
return withControlTransaction(root, () => closeout(options));
|
|
2514
2605
|
}
|
|
2515
2606
|
if (command === "finish") return finishExecution(options);
|
|
2516
|
-
throw new Error("Usage: owlrunkit <init|doctor|adopt|assurance|fleet|profiles|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]");
|
|
2607
|
+
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]");
|
|
2517
2608
|
} catch (error) {
|
|
2518
2609
|
return {
|
|
2519
2610
|
status: "invalid_input",
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://owlcoda.com/schemas/runkit/team-project-definition-v1.schema.json",
|
|
4
|
+
"title": "OwlCoda RunKit Team Project Definition V1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion", "projectId", "objective", "milestones", "workstreams", "workItems", "integrationGates"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schemaVersion": { "const": "OwlCodaRunKitTeamProjectDefinitionV1" },
|
|
10
|
+
"projectId": { "$ref": "#/$defs/id" },
|
|
11
|
+
"objective": { "type": "string", "minLength": 1 },
|
|
12
|
+
"milestones": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"items": { "$ref": "#/$defs/milestone" }
|
|
15
|
+
},
|
|
16
|
+
"workstreams": {
|
|
17
|
+
"type": "array",
|
|
18
|
+
"items": { "$ref": "#/$defs/workstream" }
|
|
19
|
+
},
|
|
20
|
+
"workItems": {
|
|
21
|
+
"type": "array",
|
|
22
|
+
"minItems": 1,
|
|
23
|
+
"items": { "$ref": "#/$defs/workItem" }
|
|
24
|
+
},
|
|
25
|
+
"integrationGates": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": { "$ref": "#/$defs/integrationGate" }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"$defs": {
|
|
31
|
+
"id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$" },
|
|
32
|
+
"strings": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
|
|
33
|
+
"milestone": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"additionalProperties": false,
|
|
36
|
+
"required": ["id", "title"],
|
|
37
|
+
"properties": {
|
|
38
|
+
"id": { "$ref": "#/$defs/id" },
|
|
39
|
+
"title": { "type": "string", "minLength": 1 }
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"workstream": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"additionalProperties": false,
|
|
45
|
+
"required": ["id", "title", "milestoneId"],
|
|
46
|
+
"properties": {
|
|
47
|
+
"id": { "$ref": "#/$defs/id" },
|
|
48
|
+
"title": { "type": "string", "minLength": 1 },
|
|
49
|
+
"milestoneId": { "$ref": "#/$defs/id" }
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"workItem": {
|
|
53
|
+
"type": "object",
|
|
54
|
+
"additionalProperties": false,
|
|
55
|
+
"required": ["id", "title", "milestoneId", "workstreamId", "dependencies", "ownedPaths"],
|
|
56
|
+
"properties": {
|
|
57
|
+
"id": { "$ref": "#/$defs/id" },
|
|
58
|
+
"title": { "type": "string", "minLength": 1 },
|
|
59
|
+
"milestoneId": { "$ref": "#/$defs/id" },
|
|
60
|
+
"workstreamId": { "$ref": "#/$defs/id" },
|
|
61
|
+
"dependencies": { "$ref": "#/$defs/strings" },
|
|
62
|
+
"ownedPaths": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
|
|
63
|
+
"measurable": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"additionalProperties": false,
|
|
66
|
+
"required": ["unit", "total"],
|
|
67
|
+
"properties": {
|
|
68
|
+
"unit": { "type": "string", "minLength": 1 },
|
|
69
|
+
"total": { "type": "integer", "minimum": 1 }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"integrationGate": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"additionalProperties": false,
|
|
77
|
+
"required": ["id", "title", "requiredWorkItemIds", "requiredDecisionIds"],
|
|
78
|
+
"properties": {
|
|
79
|
+
"id": { "$ref": "#/$defs/id" },
|
|
80
|
+
"title": { "type": "string", "minLength": 1 },
|
|
81
|
+
"requiredWorkItemIds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/id" } },
|
|
82
|
+
"requiredDecisionIds": { "$ref": "#/$defs/strings" }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"examples": [{
|
|
87
|
+
"schemaVersion": "OwlCodaRunKitTeamProjectDefinitionV1",
|
|
88
|
+
"projectId": "release-017",
|
|
89
|
+
"objective": "Ship OwlRunKit 0.17",
|
|
90
|
+
"milestones": [{ "id": "m1", "title": "Product" }],
|
|
91
|
+
"workstreams": [{ "id": "runtime", "title": "Runtime", "milestoneId": "m1" }],
|
|
92
|
+
"workItems": [{
|
|
93
|
+
"id": "engine",
|
|
94
|
+
"title": "Implement the engine",
|
|
95
|
+
"milestoneId": "m1",
|
|
96
|
+
"workstreamId": "runtime",
|
|
97
|
+
"dependencies": [],
|
|
98
|
+
"ownedPaths": ["scripts/runkit-contract/**"],
|
|
99
|
+
"measurable": { "unit": "acceptance_tests", "total": 4 }
|
|
100
|
+
}],
|
|
101
|
+
"integrationGates": [{
|
|
102
|
+
"id": "ready",
|
|
103
|
+
"title": "Ready",
|
|
104
|
+
"requiredWorkItemIds": ["engine"],
|
|
105
|
+
"requiredDecisionIds": []
|
|
106
|
+
}]
|
|
107
|
+
}]
|
|
108
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://owlcoda.com/schemas/runkit/team-project-event-v1.schema.json",
|
|
4
|
+
"title": "OwlCoda RunKit Team Project Event V1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion", "eventId", "type", "occurredAt"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schemaVersion": { "const": "OwlCodaRunKitTeamProjectEventV1" },
|
|
10
|
+
"eventId": { "$ref": "#/$defs/id" },
|
|
11
|
+
"type": { "enum": ["agent_assigned", "checkpoint_recorded", "handoff_recorded", "decision_opened", "decision_resolved", "integration_gate_passed", "data_candidate_recorded"] },
|
|
12
|
+
"occurredAt": { "type": "string", "minLength": 24 },
|
|
13
|
+
"assignmentId": { "$ref": "#/$defs/id" },
|
|
14
|
+
"supersedesAssignmentId": { "$ref": "#/$defs/id" },
|
|
15
|
+
"workItemId": { "$ref": "#/$defs/id" },
|
|
16
|
+
"agentId": { "$ref": "#/$defs/id" },
|
|
17
|
+
"executionRunId": { "$ref": "#/$defs/id" },
|
|
18
|
+
"executionWorkItemId": { "$ref": "#/$defs/id" },
|
|
19
|
+
"state": { "enum": ["active", "waiting_dependency", "waiting_decision", "verifying", "ready_to_integrate", "completed", "failed"] },
|
|
20
|
+
"summary": { "type": "string", "minLength": 1 },
|
|
21
|
+
"completedUnits": { "type": "integer", "minimum": 0 },
|
|
22
|
+
"evidenceRefs": { "$ref": "#/$defs/strings" },
|
|
23
|
+
"blockerRefs": { "$ref": "#/$defs/strings" },
|
|
24
|
+
"decisionRefs": { "$ref": "#/$defs/strings" },
|
|
25
|
+
"nextAction": { "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] },
|
|
26
|
+
"sourceFingerprint": { "type": "string", "pattern": "^(sha256:)?[a-f0-9]{64}$" },
|
|
27
|
+
"fromAgentId": { "$ref": "#/$defs/id" },
|
|
28
|
+
"toAgentId": { "$ref": "#/$defs/id" },
|
|
29
|
+
"decisionId": { "$ref": "#/$defs/id" },
|
|
30
|
+
"title": { "type": "string", "minLength": 1 },
|
|
31
|
+
"question": { "type": "string", "minLength": 1 },
|
|
32
|
+
"ownerAgentId": { "$ref": "#/$defs/id" },
|
|
33
|
+
"blockingWorkItemIds": { "$ref": "#/$defs/strings" },
|
|
34
|
+
"options": { "$ref": "#/$defs/strings" },
|
|
35
|
+
"resolution": { "type": "string", "minLength": 1 },
|
|
36
|
+
"rationale": { "type": "string", "minLength": 1 },
|
|
37
|
+
"gateId": { "$ref": "#/$defs/id" },
|
|
38
|
+
"candidateId": { "$ref": "#/$defs/id" },
|
|
39
|
+
"sourceRef": { "type": "string", "minLength": 1 },
|
|
40
|
+
"rights": { "type": "string", "minLength": 1 },
|
|
41
|
+
"inputRef": { "type": "string", "minLength": 1 },
|
|
42
|
+
"outputRef": { "type": "string", "minLength": 1 },
|
|
43
|
+
"decisionRef": { "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] },
|
|
44
|
+
"verificationRefs": { "$ref": "#/$defs/strings" },
|
|
45
|
+
"outcomeRef": { "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] },
|
|
46
|
+
"version": { "type": "string", "minLength": 1 }
|
|
47
|
+
},
|
|
48
|
+
"allOf": [
|
|
49
|
+
{
|
|
50
|
+
"if": { "properties": { "type": { "const": "agent_assigned" } }, "required": ["type"] },
|
|
51
|
+
"then": {
|
|
52
|
+
"required": ["assignmentId", "workItemId", "agentId"],
|
|
53
|
+
"dependentRequired": {
|
|
54
|
+
"executionRunId": ["executionWorkItemId"],
|
|
55
|
+
"executionWorkItemId": ["executionRunId"]
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"if": { "properties": { "type": { "const": "checkpoint_recorded" } }, "required": ["type"] },
|
|
61
|
+
"then": { "required": ["assignmentId", "workItemId", "state", "summary", "evidenceRefs", "blockerRefs", "decisionRefs", "nextAction"] }
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"if": { "properties": { "type": { "const": "handoff_recorded" } }, "required": ["type"] },
|
|
65
|
+
"then": { "required": ["assignmentId", "workItemId", "fromAgentId", "toAgentId", "summary", "evidenceRefs", "nextAction"] }
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"if": { "properties": { "type": { "const": "decision_opened" } }, "required": ["type"] },
|
|
69
|
+
"then": { "required": ["decisionId", "title", "question", "ownerAgentId", "blockingWorkItemIds", "options"] }
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"if": { "properties": { "type": { "const": "decision_resolved" } }, "required": ["type"] },
|
|
73
|
+
"then": { "required": ["decisionId", "resolution", "rationale", "evidenceRefs"] }
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"if": { "properties": { "type": { "const": "integration_gate_passed" } }, "required": ["type"] },
|
|
77
|
+
"then": { "required": ["gateId", "summary", "evidenceRefs"] }
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"if": { "properties": { "type": { "const": "data_candidate_recorded" } }, "required": ["type"] },
|
|
81
|
+
"then": { "required": ["candidateId", "sourceRef", "rights", "inputRef", "outputRef", "decisionRef", "verificationRefs", "outcomeRef", "version"] }
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"$defs": {
|
|
85
|
+
"id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$" },
|
|
86
|
+
"strings": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }
|
|
87
|
+
},
|
|
88
|
+
"examples": [{
|
|
89
|
+
"schemaVersion": "OwlCodaRunKitTeamProjectEventV1",
|
|
90
|
+
"eventId": "event-001",
|
|
91
|
+
"type": "agent_assigned",
|
|
92
|
+
"occurredAt": "2026-08-08T00:00:00.000Z",
|
|
93
|
+
"assignmentId": "assignment-001",
|
|
94
|
+
"workItemId": "engine",
|
|
95
|
+
"agentId": "agent-runtime",
|
|
96
|
+
"executionRunId": "formal-engine-001",
|
|
97
|
+
"executionWorkItemId": "delivery"
|
|
98
|
+
}]
|
|
99
|
+
}
|