@intentius/chant 0.100.0 → 0.101.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/dist/build.d.ts +6 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/cli/build-options.d.ts +2 -0
- package/dist/cli/build-options.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +8 -0
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +22 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/lexicon.d.ts +24 -1
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/plan-digest.d.ts +26 -5
- package/dist/lifecycle/plan-digest.d.ts.map +1 -1
- package/dist/lint/config.d.ts +4 -4
- package/dist/op/activities/activity-contracts.d.ts +1 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/propose-upgrade.d.ts +2 -0
- package/dist/op/activities/propose-upgrade.d.ts.map +1 -1
- package/dist/op/index.d.ts +1 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/serializer.d.ts +8 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/telemetry-attribution.d.ts +77 -0
- package/dist/telemetry-attribution.d.ts.map +1 -0
- package/dist/workspace/agent-cli.d.ts +83 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -0
- package/dist/workspace/changes-cli.d.ts.map +1 -1
- package/dist/workspace/changes.d.ts +8 -1
- package/dist/workspace/changes.d.ts.map +1 -1
- package/dist/workspace/checks/links.d.ts +1 -0
- package/dist/workspace/checks/links.d.ts.map +1 -1
- package/dist/workspace/checks/live.d.ts +40 -0
- package/dist/workspace/checks/live.d.ts.map +1 -0
- package/dist/workspace/checks.d.ts +21 -2
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +63 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/decide.d.ts +1 -1
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/declaration.d.ts +32 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +138 -3
- package/dist/workspace/export-cli.d.ts +12 -0
- package/dist/workspace/export-cli.d.ts.map +1 -0
- package/dist/workspace/export.d.ts +145 -0
- package/dist/workspace/export.d.ts.map +1 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/import.d.ts +73 -0
- package/dist/workspace/import.d.ts.map +1 -0
- package/dist/workspace/kinds.d.ts +6 -2
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/lineage-adopt-cli.d.ts +15 -0
- package/dist/workspace/lineage-adopt-cli.d.ts.map +1 -0
- package/dist/workspace/lineage-adopt.d.ts +106 -0
- package/dist/workspace/lineage-adopt.d.ts.map +1 -0
- package/dist/workspace/lineage-check.d.ts +9 -2
- package/dist/workspace/lineage-check.d.ts.map +1 -1
- package/dist/workspace/lineage-cli.d.ts +6 -1
- package/dist/workspace/lineage-cli.d.ts.map +1 -1
- package/dist/workspace/lineage-hash-index.d.ts +110 -0
- package/dist/workspace/lineage-hash-index.d.ts.map +1 -0
- package/dist/workspace/lineage-init.d.ts +10 -0
- package/dist/workspace/lineage-init.d.ts.map +1 -1
- package/dist/workspace/lineage-lock.d.ts +147 -0
- package/dist/workspace/lineage-lock.d.ts.map +1 -1
- package/dist/workspace/lineage-migrations.d.ts +15 -3
- package/dist/workspace/lineage-migrations.d.ts.map +1 -1
- package/dist/workspace/lineage-provenance.d.ts +18 -0
- package/dist/workspace/lineage-provenance.d.ts.map +1 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts +2 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.d.ts +30 -1
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/lineage-versions.d.ts +116 -0
- package/dist/workspace/lineage-versions.d.ts.map +1 -0
- package/dist/workspace/links.d.ts +31 -5
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/ls-generated.d.ts +37 -0
- package/dist/workspace/ls-generated.d.ts.map +1 -0
- package/dist/workspace/ls.d.ts +4 -0
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/member-commands.d.ts.map +1 -1
- package/dist/workspace/nested-graph.d.ts +56 -0
- package/dist/workspace/nested-graph.d.ts.map +1 -0
- package/dist/workspace/nesting.d.ts +21 -0
- package/dist/workspace/nesting.d.ts.map +1 -0
- package/dist/workspace/pin-cli.d.ts +10 -0
- package/dist/workspace/pin-cli.d.ts.map +1 -0
- package/dist/workspace/pin-integrity.d.ts +51 -0
- package/dist/workspace/pin-integrity.d.ts.map +1 -0
- package/dist/workspace/reason-codes.d.ts +26 -2
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/record-sessions.d.ts +7 -11
- package/dist/workspace/record-sessions.d.ts.map +1 -1
- package/dist/workspace/records-cli.d.ts +30 -1
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +5 -2
- package/dist/workspace/records-close.d.ts.map +1 -1
- package/dist/workspace/records-write.d.ts +22 -4
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +43 -5
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/returns.d.ts +129 -0
- package/dist/workspace/returns.d.ts.map +1 -0
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/template-manifest.d.ts +11 -3
- package/dist/workspace/template-manifest.d.ts.map +1 -1
- package/dist/workspace/trust/attestor.d.ts +8 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -1
- package/dist/workspace/trust/dsse.d.ts +58 -0
- package/dist/workspace/trust/dsse.d.ts.map +1 -0
- package/dist/workspace/trust/evidence-cli.d.ts +66 -0
- package/dist/workspace/trust/evidence-cli.d.ts.map +1 -0
- package/dist/workspace/trust/evidence.d.ts +93 -0
- package/dist/workspace/trust/evidence.d.ts.map +1 -0
- package/dist/workspace/trust/policy.d.ts +54 -1
- package/dist/workspace/trust/policy.d.ts.map +1 -1
- package/dist/workspace/trust/provenance.d.ts +21 -1
- package/dist/workspace/trust/provenance.d.ts.map +1 -1
- package/dist/workspace/trust/rotation.d.ts +132 -0
- package/dist/workspace/trust/rotation.d.ts.map +1 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/signers-cli.d.ts +49 -0
- package/dist/workspace/trust/signers-cli.d.ts.map +1 -0
- package/dist/workspace/trust/ssh-commit.d.ts +12 -0
- package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
- package/dist/workspace/trust/test-repo.d.ts +13 -0
- package/dist/workspace/trust/test-repo.d.ts.map +1 -1
- package/dist/workspace/trust/verify.d.ts +15 -0
- package/dist/workspace/trust/verify.d.ts.map +1 -1
- package/dist/workspace/work-evidence.d.ts +1 -1
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/write-scope.d.ts +199 -0
- package/dist/workspace/write-scope.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/build.ts +8 -0
- package/src/cli/build-options.ts +4 -1
- package/src/cli/commands/build.ts +2 -0
- package/src/cli/commands/import-live.test.ts +69 -1
- package/src/cli/commands/import.ts +48 -22
- package/src/cli/handlers/fan-out.test.ts +6 -6
- package/src/cli/handlers/fan-out.ts +2 -1
- package/src/cli/handlers/graph.test.ts +42 -0
- package/src/cli/handlers/graph.ts +22 -0
- package/src/cli/handlers/operator.ts +1 -1
- package/src/cli/main.test.ts +32 -0
- package/src/cli/main.ts +103 -6
- package/src/cli/mcp/workspace-tools.test.ts +1 -1
- package/src/cli/mcp/workspace-tools.ts +33 -2
- package/src/cli/registry.ts +22 -0
- package/src/cli/serve-mcp-workspace.test.ts +1 -1
- package/src/codegen/release-wiring.test.ts +5 -1
- package/src/components/fan-out-output.test.ts +1 -1
- package/src/components/fan-out.test.ts +1 -1
- package/src/components/promote.test.ts +1 -1
- package/src/config.ts +12 -0
- package/src/content-digest.test.ts +2 -2
- package/src/lexicon.ts +25 -1
- package/src/lifecycle/gate-ledger.test.ts +14 -0
- package/src/lifecycle/gate-ledger.ts +2 -1
- package/src/lifecycle/plan-digest.test.ts +54 -3
- package/src/lifecycle/plan-digest.ts +38 -8
- package/src/op/activities/activity-contracts.ts +1 -0
- package/src/op/activities/propose-upgrade.ts +8 -5
- package/src/op/gate-approval.test.ts +17 -0
- package/src/op/gate.ts +3 -3
- package/src/op/index.ts +1 -1
- package/src/serializer.ts +9 -0
- package/src/telemetry-attribution.test.ts +91 -0
- package/src/telemetry-attribution.ts +145 -0
- package/src/workspace/agent-cli.ts +134 -0
- package/src/workspace/agent.schema.json +356 -0
- package/src/workspace/behold-kinds.test.ts +1 -1
- package/src/workspace/changes-cli.ts +5 -0
- package/src/workspace/changes.schema.json +179 -1
- package/src/workspace/changes.ts +58 -4
- package/src/workspace/check-live.test.ts +192 -0
- package/src/workspace/check.schema.json +64 -0
- package/src/workspace/checks/links.ts +23 -2
- package/src/workspace/checks/live.ts +113 -0
- package/src/workspace/checks.test.ts +2 -2
- package/src/workspace/checks.ts +20 -3
- package/src/workspace/compose-graph.test.ts +47 -0
- package/src/workspace/compose-graph.ts +120 -3
- package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +7 -1
- package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +5 -0
- package/src/workspace/declaration.schema.json +138 -3
- package/src/workspace/declaration.ts +106 -1
- package/src/workspace/declared-kinds.test.ts +33 -0
- package/src/workspace/evidence.schema.json +279 -0
- package/src/workspace/export-cli.ts +180 -0
- package/src/workspace/export-import.test.ts +282 -0
- package/src/workspace/export.ts +486 -0
- package/src/workspace/graph-cli.ts +47 -1
- package/src/workspace/graph-contract.test.ts +89 -4
- package/src/workspace/graph.schema.json +206 -1
- package/src/workspace/import.ts +325 -0
- package/src/workspace/kinds.test.ts +5 -5
- package/src/workspace/kinds.ts +25 -3
- package/src/workspace/lineage-adopt-cli.ts +103 -0
- package/src/workspace/lineage-adopt.test.ts +552 -0
- package/src/workspace/lineage-adopt.ts +452 -0
- package/src/workspace/lineage-check.ts +26 -5
- package/src/workspace/lineage-cli.ts +12 -2
- package/src/workspace/lineage-hash-index.ts +305 -0
- package/src/workspace/lineage-init.test.ts +9 -0
- package/src/workspace/lineage-init.ts +29 -9
- package/src/workspace/lineage-lock.ts +54 -0
- package/src/workspace/lineage-migrations.test.ts +27 -0
- package/src/workspace/lineage-migrations.ts +44 -14
- package/src/workspace/lineage-provenance.ts +40 -0
- package/src/workspace/lineage-upgrade-cli.ts +9 -5
- package/src/workspace/lineage-upgrade.test.ts +92 -1
- package/src/workspace/lineage-upgrade.ts +111 -16
- package/src/workspace/lineage-versions.ts +348 -0
- package/src/workspace/links.test.ts +121 -2
- package/src/workspace/links.ts +97 -6
- package/src/workspace/ls-contract.test.ts +84 -1
- package/src/workspace/ls-generated.ts +111 -0
- package/src/workspace/ls.schema.json +19 -0
- package/src/workspace/ls.ts +8 -1
- package/src/workspace/member-commands.ts +3 -1
- package/src/workspace/nested-graph.test.ts +176 -0
- package/src/workspace/nested-graph.ts +169 -0
- package/src/workspace/nesting.ts +37 -0
- package/src/workspace/pin-cli.test.ts +71 -0
- package/src/workspace/pin-cli.ts +57 -0
- package/src/workspace/pin-integrity.test.ts +121 -0
- package/src/workspace/pin-integrity.ts +104 -0
- package/src/workspace/points-write.schema.json +1 -0
- package/src/workspace/read-contract.test.ts +24 -0
- package/src/workspace/reason-codes.test.ts +10 -0
- package/src/workspace/reason-codes.ts +29 -2
- package/src/workspace/record-sessions.ts +12 -14
- package/src/workspace/records-amend.schema.json +4 -0
- package/src/workspace/records-cli.ts +93 -12
- package/src/workspace/records-close.schema.json +6 -2
- package/src/workspace/records-close.ts +10 -2
- package/src/workspace/records-formats.test.ts +13 -5
- package/src/workspace/records-new.schema.json +4 -0
- package/src/workspace/records-review.schema.json +4 -0
- package/src/workspace/records-sessions.test.ts +23 -6
- package/src/workspace/records-write.test.ts +65 -8
- package/src/workspace/records-write.ts +70 -6
- package/src/workspace/records.schema.json +55 -3
- package/src/workspace/records.ts +96 -5
- package/src/workspace/returns.ts +328 -0
- package/src/workspace/signers.schema.json +206 -0
- package/src/workspace/status-gates.ts +2 -1
- package/src/workspace/template-manifest.ts +22 -4
- package/src/workspace/trust/attestor.ts +15 -0
- package/src/workspace/trust/dsse.ts +134 -0
- package/src/workspace/trust/evidence-cli.ts +195 -0
- package/src/workspace/trust/evidence.test.ts +241 -0
- package/src/workspace/trust/evidence.ts +207 -0
- package/src/workspace/trust/policy.ts +110 -3
- package/src/workspace/trust/provenance.ts +41 -4
- package/src/workspace/trust/record-seal.test.ts +1 -1
- package/src/workspace/trust/rotation.test.ts +258 -0
- package/src/workspace/trust/rotation.ts +336 -0
- package/src/workspace/trust/seal.ts +11 -0
- package/src/workspace/trust/signers-cli.ts +178 -0
- package/src/workspace/trust/ssh-commit.ts +53 -4
- package/src/workspace/trust/test-repo.ts +18 -0
- package/src/workspace/trust/trust.test.ts +8 -2
- package/src/workspace/trust/verify-cli.ts +1 -0
- package/src/workspace/trust/verify.ts +22 -0
- package/src/workspace/work-evidence.schema.json +4 -0
- package/src/workspace/write-scope.test.ts +340 -0
- package/src/workspace/write-scope.ts +448 -0
|
@@ -36,6 +36,19 @@ export declare class TestRepo {
|
|
|
36
36
|
sshSign(key: Key, payload: Buffer, namespace: string): string;
|
|
37
37
|
cleanup(): void;
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Write `<signers>.rotation.json` for the signers file now in the working
|
|
41
|
+
* tree, as the next version after `previousText`, signed by `by` in the
|
|
42
|
+
* rotation namespace (#2553).
|
|
43
|
+
*/
|
|
44
|
+
export declare function writeRotation(repo: TestRepo, opts: {
|
|
45
|
+
previousText: string;
|
|
46
|
+
version: number;
|
|
47
|
+
threshold?: number;
|
|
48
|
+
by: Array<[string, Key]>;
|
|
49
|
+
namespace?: string;
|
|
50
|
+
signersPath?: string;
|
|
51
|
+
}): void;
|
|
39
52
|
/** A record kind reading `records/*.md`, and its schema, written into `repo`. */
|
|
40
53
|
export declare function writeRecordKind(repo: TestRepo): string;
|
|
41
54
|
export declare function note(id: string, body?: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-repo.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/test-repo.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"test-repo.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/test-repo.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,eAAO,MAAM,YAAY,SAA2E,CAAC;AAErG,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qBAAa,QAAQ;IACnB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,KAAK,EAAE,MAAM;IASzB,GAAG,CAAC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,MAAM,CAAC,UAAU;IAc1D,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAO,GAAG,MAAM;IAIjG,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG;IAOtB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAKvC,wFAAwF;IACxF,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,MAAM;IAO5E,IAAI,IAAI,MAAM;IAId;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM;IAgBvE,gEAAgE;IAChE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAO7D,OAAO,IAAI,IAAI;CAGhB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACtI,IAAI,CAON;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAqBtD;AAED,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,MAAM,CAElD"}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { type CommitAttestor, type ProvenanceLevel } from "./attestor.js";
|
|
15
15
|
import { type BaseSource, type RecordProvenance } from "./provenance.js";
|
|
16
16
|
import { type ExcludedSigner } from "./policy.js";
|
|
17
|
+
import { type RotationRefusalCode } from "./rotation.js";
|
|
17
18
|
export interface CommitVerdict extends RecordProvenance {
|
|
18
19
|
commit: string;
|
|
19
20
|
subject: string;
|
|
@@ -46,6 +47,20 @@ export interface ChangeReport {
|
|
|
46
47
|
/** Protected paths whose content differs between the merge base and head. */
|
|
47
48
|
protectedChanged: string[];
|
|
48
49
|
protectedWrites: ProtectedWrite[];
|
|
50
|
+
/**
|
|
51
|
+
* When the change edits the signer set (#2553): the version it proposes and
|
|
52
|
+
* who signed it, or, when the new set is refused, the version it had to
|
|
53
|
+
* follow and why.
|
|
54
|
+
*/
|
|
55
|
+
rotation: {
|
|
56
|
+
from: number;
|
|
57
|
+
to: number;
|
|
58
|
+
signedBy: string[];
|
|
59
|
+
} | {
|
|
60
|
+
from: number;
|
|
61
|
+
code: RotationRefusalCode;
|
|
62
|
+
reason: string;
|
|
63
|
+
} | null;
|
|
49
64
|
notes: string[];
|
|
50
65
|
failures: string[];
|
|
51
66
|
ok: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAA+C,KAAK,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACnH,OAAO,EAAiC,KAAK,cAAc,EAAoB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAA+C,KAAK,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACnH,OAAO,EAAiC,KAAK,cAAc,EAAoB,MAAM,UAAU,CAAC;AAChG,OAAO,EAAoD,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAExG,MAAM,WAAW,aAAc,SAAQ,gBAAgB;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE;QACN,MAAM,EAAE,OAAO,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,QAAQ,EAAE,cAAc,EAAE,CAAC;QAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,6EAA6E;IAC7E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC;;;;OAIG;IACH,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,mBAAmB,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAChI,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,EAAE,EAAE,OAAO,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;CACtC;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAUnG;AAQD,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,YAAY,CAoH9D"}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { type EvidenceResult, type WorkAcceptance } from "./work.js";
|
|
22
22
|
/** Why evidence was not attached. Closed. Nothing is written with any of them. */
|
|
23
|
-
export declare const WORK_EVIDENCE_ERROR_CODES: readonly ["kind-unreadable", "kind-invalid", "schema-unreadable", "schema-id-mismatch", "schema-invalid", "location-missing", "write-usage-invalid", "write-input-invalid", "record-not-found", "amend-id-immutable", "record-closed", "amend-supersede-instead", "record-sign-failed", "ratify-quorum-not-met", "record-unparseable", "record-schema-invalid", "record-id-duplicate", "record-supersedes-unknown", "record-supersedes-conflict", "record-remediates-unknown", "record-remediates-not-closed", "session-seal-mismatch", "session-verdict-unknown-record", "work-kind-missing", "work-kind-ambiguous", "work-item-unknown", "work-item-closed", "work-criterion-unknown", "work-acceptance-self-verified", "lease-held", "lease-not-held", "lease-token-mismatch", "not-a-git-repository"];
|
|
23
|
+
export declare const WORK_EVIDENCE_ERROR_CODES: readonly ["kind-unreadable", "kind-invalid", "schema-unreadable", "schema-id-mismatch", "schema-invalid", "location-missing", "write-usage-invalid", "write-input-invalid", "record-not-found", "amend-id-immutable", "record-closed", "amend-supersede-instead", "record-sign-failed", "ratify-quorum-not-met", "write-scope-member", "write-scope-kind", "agent-unknown", "record-unparseable", "record-schema-invalid", "record-id-duplicate", "record-supersedes-unknown", "record-supersedes-conflict", "record-remediates-unknown", "record-remediates-not-closed", "record-seal-mismatch", "session-seal-mismatch", "session-verdict-unknown-record", "work-kind-missing", "work-kind-ambiguous", "work-item-unknown", "work-item-closed", "work-criterion-unknown", "work-acceptance-self-verified", "lease-held", "lease-not-held", "lease-token-mismatch", "not-a-git-repository"];
|
|
24
24
|
export type WorkEvidenceErrorCode = (typeof WORK_EVIDENCE_ERROR_CODES)[number];
|
|
25
25
|
export interface AttachWorkEvidenceRequest {
|
|
26
26
|
/** Where the workspace is found, and what `path` and `kind` resolve against. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-evidence.d.ts","sourceRoot":"","sources":["../../src/workspace/work-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,EAAwD,KAAK,cAAc,EAAyB,KAAK,cAAc,EAAE,MAAM,QAAQ,CAAC;AAG/I,kFAAkF;AAClF,eAAO,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"work-evidence.d.ts","sourceRoot":"","sources":["../../src/workspace/work-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,EAAwD,KAAK,cAAc,EAAyB,KAAK,cAAc,EAAE,MAAM,QAAQ,CAAC;AAG/I,kFAAkF;AAClF,eAAO,MAAM,yBAAyB,81BAYI,CAAC;AAC3C,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/E,MAAM,WAAW,yBAAyB;IACxC,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,4DAA4D;AAC5D,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAEhD,kFAAkF;AAClF,eAAO,MAAM,8BAA8B,4FAA4F,CAAC;AAExI,UAAU,OAAO;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,sFAAsF;AACtF,MAAM,MAAM,oBAAoB,GAAG,OAAO,GACxC,CACI;IACE,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,wDAAwD;IACxD,UAAU,EAAE,cAAc,CAAC;CAC5B,GACD;IAAE,KAAK,EAAE;QAAE,IAAI,EAAE,qBAAqB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAC9D,CAAC;AAWJ,sGAAsG;AACtG,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,yBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA+DtG"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write scope per member and record kind, for each principal class, and the
|
|
3
|
+
* agent sessions bound to one member (#2524 D5, D20; #2548; ws-067).
|
|
4
|
+
*
|
|
5
|
+
* The declaration's `writeScope` block gives a restricted class the members
|
|
6
|
+
* whose files it may write and the record kinds it may write, with which
|
|
7
|
+
* verbs (`new`, `amend`, `review`, `close`). A class with no entry is not
|
|
8
|
+
* restricted. The declaration's `agents` list names agent sessions, each
|
|
9
|
+
* bound to one member: a session writes that member's files, and the records
|
|
10
|
+
* of kinds that member or the workspace declares, as `writeScope.agent`
|
|
11
|
+
* allows. An agent's members can't be widened.
|
|
12
|
+
*
|
|
13
|
+
* Two places apply it, both reading the scope from the base revision so a
|
|
14
|
+
* change can't widen its own scope (#2524 threat model):
|
|
15
|
+
*
|
|
16
|
+
* - The write paths: `chant workspace records new|amend|review|close` and the
|
|
17
|
+
* MCP record tools refuse a write outside the writer's scope with
|
|
18
|
+
* `write-scope-member` or `write-scope-kind`, and an unknown session with
|
|
19
|
+
* `agent-unknown`. The session comes from `CHANT_AGENT`.
|
|
20
|
+
* - The enforcement boundary: `chant workspace check --changes <range>`
|
|
21
|
+
* judges every commit in the range, by its `Chant-Agent` trailer, its
|
|
22
|
+
* attested principal, or its author, and reports each path written outside
|
|
23
|
+
* that writer's scope. Run in CI with an attestation policy, the principal
|
|
24
|
+
* is the signer the policy at base trusts; on a developer machine it is
|
|
25
|
+
* detection only (ws-002).
|
|
26
|
+
*
|
|
27
|
+
* A principal's class comes from the role grants in the trust policy at base,
|
|
28
|
+
* through {@link principalClass} alone (the agent, runner and service roles),
|
|
29
|
+
* or from naming an agent session. Claiming a session only ever narrows what
|
|
30
|
+
* a writer may do, so an unverified `CHANT_AGENT` or trailer is safe to honour.
|
|
31
|
+
*/
|
|
32
|
+
import { type AgentDeclaration, type ClassScope, type Declaration, type PrincipalClass, type WriteVerb } from "./declaration.js";
|
|
33
|
+
import { type TrustPolicy } from "./trust/policy.js";
|
|
34
|
+
/** The environment variable naming the agent session a write is made in. */
|
|
35
|
+
export declare const AGENT_ENV = "CHANT_AGENT";
|
|
36
|
+
/** The commit trailer naming the agent session a commit was made in. */
|
|
37
|
+
export declare const AGENT_TRAILER = "Chant-Agent";
|
|
38
|
+
/** Why a write is outside its writer's scope. Closed. */
|
|
39
|
+
export declare const WRITE_SCOPE_CODES: readonly ["write-scope-member", "write-scope-kind", "agent-unknown"];
|
|
40
|
+
export type WriteScopeCode = (typeof WRITE_SCOPE_CODES)[number];
|
|
41
|
+
/**
|
|
42
|
+
* The role grants a class is read from. Every read of roles for write scope
|
|
43
|
+
* goes through here, so where the grants live (`.chant/trust.json` today,
|
|
44
|
+
* possibly the declaration, #2547) is decided in one place: the policy.
|
|
45
|
+
*/
|
|
46
|
+
export declare function roleGrants(policy: TrustPolicy): Record<string, string[]>;
|
|
47
|
+
/** The class a principal is in: the first of agent, runner and service whose role it holds at base, or human. */
|
|
48
|
+
export declare function principalClass(policy: TrustPolicy, principal: string | null): PrincipalClass;
|
|
49
|
+
/** Who is writing, as the scope judges it. */
|
|
50
|
+
export interface Writer {
|
|
51
|
+
/** The principal named, or null when none is. */
|
|
52
|
+
principal: string | null;
|
|
53
|
+
class: PrincipalClass;
|
|
54
|
+
/** The agent session the writer is bound to, or null. */
|
|
55
|
+
agent: AgentDeclaration | null;
|
|
56
|
+
}
|
|
57
|
+
export declare class WriteScopeError extends Error {
|
|
58
|
+
readonly code: WriteScopeCode;
|
|
59
|
+
constructor(code: WriteScopeCode, message: string);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The writer: in the session `agent` names (refused with agent-unknown when
|
|
63
|
+
* the declaration declares none by that name), in the session that lists
|
|
64
|
+
* `principal`, or else in the class `principal`'s roles give it.
|
|
65
|
+
*/
|
|
66
|
+
export declare function resolveWriter(declaration: Declaration | null, policy: TrustPolicy, given: {
|
|
67
|
+
agent?: string | null;
|
|
68
|
+
principal?: string | null;
|
|
69
|
+
}): Writer;
|
|
70
|
+
/** The scope that applies to `writer`, or null when its class is not restricted. An agent is always restricted to its member. */
|
|
71
|
+
export declare function scopeOf(declaration: Declaration | null, writer: Writer): ClassScope | null;
|
|
72
|
+
export type ScopeVerdict = {
|
|
73
|
+
ok: true;
|
|
74
|
+
} | {
|
|
75
|
+
ok: false;
|
|
76
|
+
code: Exclude<WriteScopeCode, "agent-unknown">;
|
|
77
|
+
message: string;
|
|
78
|
+
};
|
|
79
|
+
/** The record kind a write goes to, as the scope reads it. */
|
|
80
|
+
export interface ScopedKind {
|
|
81
|
+
/** The kind file's `recordKind.name`. */
|
|
82
|
+
name: string;
|
|
83
|
+
/** The name the declaration gives it, or null. */
|
|
84
|
+
declaredName: string | null;
|
|
85
|
+
/** The member that declares the kind, or null for the workspace's own kinds. */
|
|
86
|
+
member: string | null;
|
|
87
|
+
/** True when the declaration names the kind; an undeclared kind belongs to the member holding its records. */
|
|
88
|
+
declared: boolean;
|
|
89
|
+
}
|
|
90
|
+
/** Whether `writer` may write a record of `kind` with `verb`. A delete is never in a restricted scope. */
|
|
91
|
+
export declare function judgeRecord(declaration: Declaration | null, writer: Writer, kind: ScopedKind, verb: WriteVerb | "delete"): ScopeVerdict;
|
|
92
|
+
/** Whether `writer` may write the file at `path`, from the workspace root. */
|
|
93
|
+
export declare function judgePath(declaration: Declaration | null, writer: Writer, path: string): ScopeVerdict;
|
|
94
|
+
/** The declaration and policy a write on this machine is judged by. */
|
|
95
|
+
export interface ScopeSource {
|
|
96
|
+
declaration: Declaration | null;
|
|
97
|
+
/** Where the declaration was read: the base revision, or the working tree when there is no base or no declaration at it. */
|
|
98
|
+
from: "base" | "working-tree" | null;
|
|
99
|
+
/** The workspace root on disk, or null without a declaration. */
|
|
100
|
+
rootOnDisk: string | null;
|
|
101
|
+
/** The workspace root from the git root, "." for the git root, or null without a declaration. */
|
|
102
|
+
root: string | null;
|
|
103
|
+
policy: TrustPolicy;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The scope for a write from `cwd`: the declaration and the trust policy at
|
|
107
|
+
* the base revision (`origin/HEAD`, `main` or `master`), so a write can't
|
|
108
|
+
* widen its own scope by editing its copy of the declaration. Without a base,
|
|
109
|
+
* or without a declaration at it, the working tree's declaration.
|
|
110
|
+
*/
|
|
111
|
+
export declare function scopeSource(cwd: string): ScopeSource;
|
|
112
|
+
/**
|
|
113
|
+
* The kind a write goes to, as {@link judgeRecord} reads it: the declared
|
|
114
|
+
* entry whose file is `kindFile`, or, for a kind the declaration does not
|
|
115
|
+
* name, the member holding `recordsDir`.
|
|
116
|
+
*/
|
|
117
|
+
export declare function scopedKind(source: ScopeSource, kindName: string, kindFile: string, recordsDir: string): ScopedKind;
|
|
118
|
+
/**
|
|
119
|
+
* Refuse a record write outside the writer's scope (#2548): throws a
|
|
120
|
+
* {@link WriteScopeError}. `agent` is the session the write names
|
|
121
|
+
* (`CHANT_AGENT`), and `principal` who the write names as its author.
|
|
122
|
+
*/
|
|
123
|
+
export declare function refuseRecordWrite(cwd: string, write: {
|
|
124
|
+
kindName: string;
|
|
125
|
+
kindFile: string;
|
|
126
|
+
recordsDir: string;
|
|
127
|
+
verb: WriteVerb;
|
|
128
|
+
agent?: string | null;
|
|
129
|
+
principal?: string | null;
|
|
130
|
+
}): void;
|
|
131
|
+
/** A commit as the scope check judged it. */
|
|
132
|
+
export interface ScopeCommit {
|
|
133
|
+
commit: string;
|
|
134
|
+
subject: string;
|
|
135
|
+
/** The attested principal, or the author's email when the commit is not attested. */
|
|
136
|
+
principal: string;
|
|
137
|
+
/** Whether the principal is a signer the policy at base attests, or only the author the commit claims. */
|
|
138
|
+
attested: boolean;
|
|
139
|
+
class: PrincipalClass;
|
|
140
|
+
/** The agent session, from the Chant-Agent trailer or the principal, or null. */
|
|
141
|
+
agent: string | null;
|
|
142
|
+
/** Paths in the workspace the commit writes. */
|
|
143
|
+
paths: number;
|
|
144
|
+
}
|
|
145
|
+
export interface ScopeFinding {
|
|
146
|
+
/** `finding:<code>:<commit>:<path>`, or `finding:agent-unknown:<commit>`. */
|
|
147
|
+
id: string;
|
|
148
|
+
code: WriteScopeCode;
|
|
149
|
+
commit: string;
|
|
150
|
+
/** From the workspace root, or null for a finding on the whole commit. */
|
|
151
|
+
path: string | null;
|
|
152
|
+
principal: string;
|
|
153
|
+
class: PrincipalClass;
|
|
154
|
+
agent: string | null;
|
|
155
|
+
/** For a record file: how it was written, as the records commands name it, or delete. */
|
|
156
|
+
verb: WriteVerb | "delete" | null;
|
|
157
|
+
message: string;
|
|
158
|
+
}
|
|
159
|
+
export interface ScopeReport {
|
|
160
|
+
/** The commit the declaration and the trust policy were read at. */
|
|
161
|
+
base: string;
|
|
162
|
+
/** The classes with a writeScope entry, and agent when any session is declared. */
|
|
163
|
+
restricted: PrincipalClass[];
|
|
164
|
+
agents: string[];
|
|
165
|
+
commits: ScopeCommit[];
|
|
166
|
+
findings: ScopeFinding[];
|
|
167
|
+
}
|
|
168
|
+
/** A record kind the check knows, to tell a record file from another path. */
|
|
169
|
+
export interface CheckKind {
|
|
170
|
+
scoped: ScopedKind;
|
|
171
|
+
/** The records directory, from the repository root. */
|
|
172
|
+
dir: string;
|
|
173
|
+
match: RegExp;
|
|
174
|
+
/** The reviews field, when the kind has one; the verdicts field of a session kind. */
|
|
175
|
+
reviewFields: string[];
|
|
176
|
+
/** The state field and closed states of a session kind, for telling a close. */
|
|
177
|
+
session: {
|
|
178
|
+
stateField: string;
|
|
179
|
+
closed: string[];
|
|
180
|
+
fills: string[];
|
|
181
|
+
} | null;
|
|
182
|
+
format: string;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Judge every commit in `base..head` against the write scope the declaration
|
|
186
|
+
* at `base` gives (#2548). Returns null when that declaration restricts no
|
|
187
|
+
* one: no writeScope block and no agent session. Merges are skipped; the
|
|
188
|
+
* commits they bring are judged instead.
|
|
189
|
+
*/
|
|
190
|
+
export declare function checkWriteScope(q: {
|
|
191
|
+
top: string;
|
|
192
|
+
base: string;
|
|
193
|
+
head: string;
|
|
194
|
+
/** The workspace root from the repository root, "" for the top. */
|
|
195
|
+
prefix: string;
|
|
196
|
+
declaration: Declaration;
|
|
197
|
+
kinds: CheckKind[];
|
|
198
|
+
}): Promise<ScopeReport | null>;
|
|
199
|
+
//# sourceMappingURL=write-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-scope.d.ts","sourceRoot":"","sources":["../../src/workspace/write-scope.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/build.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Declarable } from "./declarable";
|
|
2
2
|
import type { Serializer, SerializerResult } from "./serializer";
|
|
3
3
|
import type { OwnershipMarker } from "./ownership";
|
|
4
|
+
import type { TelemetryAttribution } from "./telemetry-attribution";
|
|
4
5
|
import type { BuildError, DiscoveryErrorType } from "./errors";
|
|
5
6
|
import type { IntrinsicDef, BuildRootContribution, BuildRootContributor } from "./lexicon";
|
|
6
7
|
import { getProvenance, type BuildParamProvenance } from "./provenance";
|
|
@@ -194,6 +195,12 @@ export interface BuildOptions {
|
|
|
194
195
|
*/
|
|
195
196
|
ownership?: OwnershipMarker;
|
|
196
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Telemetry attribution facts (#2558), passed to each serializer's
|
|
200
|
+
* {@link SerializeContext}. Resolved by the build command; unset at level 0.
|
|
201
|
+
*/
|
|
202
|
+
telemetry?: TelemetryAttribution;
|
|
203
|
+
|
|
197
204
|
/**
|
|
198
205
|
* The resolved project configuration, passed through to each serializer's
|
|
199
206
|
* {@link SerializeContext} so a dialect can read its lexicon-scoped settings.
|
|
@@ -876,6 +883,7 @@ async function buildFromDiscoveryResult(
|
|
|
876
883
|
const serialized = serializer.serialize(applyBound, lexiconLexiconOutputs, {
|
|
877
884
|
ownership: options?.ownership,
|
|
878
885
|
config: options?.config,
|
|
886
|
+
...(options?.telemetry ? { telemetry: options.telemetry } : {}),
|
|
879
887
|
...(receipts.size > 0 ? { receipts } : {}),
|
|
880
888
|
});
|
|
881
889
|
// Collect any non-fatal serializer diagnostics into the build warnings.
|
package/src/cli/build-options.ts
CHANGED
|
@@ -64,6 +64,8 @@ export interface ProjectBuildOptionsInput {
|
|
|
64
64
|
ownership?: OwnershipMarker;
|
|
65
65
|
/** This build's resolved build-time parameters (#1064). */
|
|
66
66
|
buildParams?: BuildParamProvenance[];
|
|
67
|
+
/** Telemetry attribution facts (#2558), from `resolveTelemetryAttribution`; unset at level 0. */
|
|
68
|
+
telemetry?: import("../telemetry-attribution").TelemetryAttribution;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
/**
|
|
@@ -75,7 +77,7 @@ export interface ProjectBuildOptionsInput {
|
|
|
75
77
|
* in this function, never at a call site.
|
|
76
78
|
*/
|
|
77
79
|
export function resolveProjectBuildOptions(input: ProjectBuildOptionsInput): BuildOptions {
|
|
78
|
-
const { config, configDir, plugins, modes, ownership, buildParams } = input;
|
|
80
|
+
const { config, configDir, plugins, modes, ownership, buildParams, telemetry } = input;
|
|
79
81
|
|
|
80
82
|
// #1039 — each loaded plugin's registered intrinsics (e.g. AWS's `Sub`), so
|
|
81
83
|
// a file using a registered intrinsic tagged template folds instead of
|
|
@@ -90,6 +92,7 @@ export function resolveProjectBuildOptions(input: ProjectBuildOptionsInput): Bui
|
|
|
90
92
|
|
|
91
93
|
return {
|
|
92
94
|
ownership,
|
|
95
|
+
...(telemetry ? { telemetry } : {}),
|
|
93
96
|
config: config as unknown as Record<string, unknown>,
|
|
94
97
|
fold: modes.fold,
|
|
95
98
|
sandbox: modes.sandbox,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
resolveKnowledgeDir,
|
|
9
9
|
} from "../../config";
|
|
10
10
|
import { resolveBuildModes, resolveProjectBuildOptions } from "../build-options";
|
|
11
|
+
import { resolveTelemetryAttribution } from "../../telemetry-attribution";
|
|
11
12
|
import { loadOkfBundle } from "../../okf-read";
|
|
12
13
|
import { unknownEnvError } from "../../env";
|
|
13
14
|
import type { OwnershipMarker } from "../../ownership";
|
|
@@ -320,6 +321,7 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
|
|
|
320
321
|
modes,
|
|
321
322
|
ownership,
|
|
322
323
|
buildParams: paramsResolution.provenance,
|
|
324
|
+
telemetry: await resolveTelemetryAttribution(configDir, config as unknown as Record<string, unknown>, env),
|
|
323
325
|
}),
|
|
324
326
|
);
|
|
325
327
|
|
|
@@ -6,7 +6,8 @@ import { join } from "node:path";
|
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import type { LexiconPlugin, ExportedTemplate, ResourceSelector } from "../../lexicon";
|
|
8
8
|
import type { TypeScriptGenerator } from "../../import/generator";
|
|
9
|
-
import type { TemplateIR } from "../../import/parser";
|
|
9
|
+
import type { TemplateIR, ParseContext } from "../../import/parser";
|
|
10
|
+
import type { EmbeddedContentImporter } from "../../import/embedded";
|
|
10
11
|
|
|
11
12
|
const generator: TypeScriptGenerator = {
|
|
12
13
|
generate(ir: TemplateIR) {
|
|
@@ -151,4 +152,71 @@ describe("liveImportFromPlugins (#114)", () => {
|
|
|
151
152
|
expect(result.success).toBe(true);
|
|
152
153
|
expect(seenStack).toBe("loom-backend");
|
|
153
154
|
});
|
|
155
|
+
|
|
156
|
+
// #2995: an export with `reparse` goes through the same embedded-content
|
|
157
|
+
// delegation as file import.
|
|
158
|
+
describe("embedded content (#2995)", () => {
|
|
159
|
+
const configText = "service:\n pipelines: {}\n";
|
|
160
|
+
|
|
161
|
+
function hostExporter(): LexiconPlugin {
|
|
162
|
+
const parse = (context?: ParseContext): TemplateIR => {
|
|
163
|
+
const ref = context?.embedded?.resolve({
|
|
164
|
+
host: "fake",
|
|
165
|
+
hostType: "Fake::ConfigMap",
|
|
166
|
+
location: "ConfigMap cfg data[\"config.yaml\"]",
|
|
167
|
+
directory: "cfg",
|
|
168
|
+
text: configText,
|
|
169
|
+
expectedOwner: { lexicon: "owner", what: "an owner config" },
|
|
170
|
+
});
|
|
171
|
+
return {
|
|
172
|
+
resources: [{ logicalId: "cfg", type: "Fake::ConfigMap", properties: { data: ref ?? configText } }],
|
|
173
|
+
parameters: [],
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
...fakeExporter("fake", { resources: [], parameters: [] }),
|
|
178
|
+
async exportResources(): Promise<ExportedTemplate> {
|
|
179
|
+
return { ...parse(), reparse: (context) => parse(context) };
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const importer: EmbeddedContentImporter = {
|
|
185
|
+
what: "an owner config",
|
|
186
|
+
matches: (c) => typeof c.document === "object" && c.document !== null && "service" in c.document,
|
|
187
|
+
import: () => ({
|
|
188
|
+
files: [{ path: "config.ts", content: "export const config = {};\n" }],
|
|
189
|
+
value: { bindings: [{ from: "config.ts", name: "config" }], shape: "single" },
|
|
190
|
+
}),
|
|
191
|
+
};
|
|
192
|
+
const owner: LexiconPlugin = {
|
|
193
|
+
name: "owner",
|
|
194
|
+
serializer: {} as never,
|
|
195
|
+
generate: async () => {},
|
|
196
|
+
validate: async () => {},
|
|
197
|
+
coverage: async () => {},
|
|
198
|
+
package: async () => {},
|
|
199
|
+
embeddedImporters: () => [importer],
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
test("a loaded owner imports the content and its modules are written beside the host's", async () => {
|
|
203
|
+
const result = await liveImportFromPlugins([hostExporter(), owner], { environment: "prod", output: outputDir, force: true });
|
|
204
|
+
expect(result.success).toBe(true);
|
|
205
|
+
expect(result.warnings).toEqual([]);
|
|
206
|
+
expect(result.generatedFiles).toEqual(["main.ts", "cfg/config.ts"]);
|
|
207
|
+
const main = await readFile(join(outputDir, "main.ts"), "utf-8");
|
|
208
|
+
expect(main).toContain('"$embedded"');
|
|
209
|
+
expect(main).toContain('"from":"cfg/config.ts"');
|
|
210
|
+
expect(await readFile(join(outputDir, "cfg/config.ts"), "utf-8")).toContain("export const config");
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("with no owner the content is kept as read, with a warning", async () => {
|
|
214
|
+
const result = await liveImportFromPlugins([hostExporter()], { environment: "prod", output: outputDir, force: true });
|
|
215
|
+
expect(result.success).toBe(true);
|
|
216
|
+
expect(result.generatedFiles).toEqual(["main.ts"]);
|
|
217
|
+
expect(result.warnings.join("\n")).toContain("no installed lexicon imports it");
|
|
218
|
+
const main = await readFile(join(outputDir, "main.ts"), "utf-8");
|
|
219
|
+
expect(main).toContain(JSON.stringify(configText));
|
|
220
|
+
});
|
|
221
|
+
});
|
|
154
222
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from "fs";
|
|
2
2
|
import { join, resolve, basename, dirname } from "path";
|
|
3
3
|
import { formatSuccess, formatWarning, formatError } from "../format";
|
|
4
|
-
import type { TemplateIR, ResourceIR, ParameterIR,
|
|
4
|
+
import type { TemplateIR, ResourceIR, ParameterIR, ParseContext } from "../../import/parser";
|
|
5
5
|
import type { GeneratedFile, TypeScriptGenerator } from "../../import/generator";
|
|
6
6
|
import { listInstalledLexicons, loadPlugin, loadPlugins, resolveProjectLexicons } from "../plugins";
|
|
7
|
-
import type { LexiconPlugin, ResourceSelector } from "../../lexicon";
|
|
7
|
+
import type { ExportedTemplate, LexiconPlugin, ResourceSelector } from "../../lexicon";
|
|
8
8
|
import { parseYAMLDocument, splitYAMLDocuments } from "../../yaml";
|
|
9
9
|
import { importLexiconPackage } from "../../lexicon-module";
|
|
10
10
|
import { EmbeddedImports, type EmbeddedContent, type RegisteredEmbeddedImporter } from "../../import/embedded";
|
|
@@ -427,14 +427,15 @@ export async function importFromContent(options: ContentImportOptions): Promise<
|
|
|
427
427
|
|
|
428
428
|
/**
|
|
429
429
|
* The importers for the content a host's parser offered (#2962): those of the
|
|
430
|
-
* project's lexicons, and of each installed
|
|
431
|
-
* recognizes one of the offered documents
|
|
430
|
+
* plugins already loaded, of the project's lexicons, and of each installed
|
|
431
|
+
* lexicon whose `detectTemplate` recognizes one of the offered documents
|
|
432
|
+
* (#2995 adds the loaded ones). The recognizing is done with the
|
|
432
433
|
* lexicon's light `/detect` module, so a lexicon is loaded in full only when
|
|
433
434
|
* it may own something; one that fails to load is skipped.
|
|
434
435
|
*/
|
|
435
436
|
async function embeddedImportersFor(
|
|
436
437
|
offered: readonly EmbeddedContent[],
|
|
437
|
-
|
|
438
|
+
loaded: readonly LexiconPlugin[],
|
|
438
439
|
projectDir: string,
|
|
439
440
|
): Promise<RegisteredEmbeddedImporter[]> {
|
|
440
441
|
const documents = offered.map((c) => c.document).filter((d) => typeof d === "object" && d !== null);
|
|
@@ -446,7 +447,8 @@ async function embeddedImportersFor(
|
|
|
446
447
|
} catch {
|
|
447
448
|
projectNames = [];
|
|
448
449
|
}
|
|
449
|
-
|
|
450
|
+
// Plugins already loaded (the host, or live import's exporters) are asked too.
|
|
451
|
+
const candidates: string[] = [...new Set([...loaded.map((p) => p.name), ...projectNames])];
|
|
450
452
|
for (const name of listInstalledLexicons(projectDir)) {
|
|
451
453
|
if (candidates.includes(name)) continue;
|
|
452
454
|
try {
|
|
@@ -471,7 +473,7 @@ async function embeddedImportersFor(
|
|
|
471
473
|
for (const name of candidates) {
|
|
472
474
|
let plugin: LexiconPlugin;
|
|
473
475
|
try {
|
|
474
|
-
plugin =
|
|
476
|
+
plugin = loaded.find((p) => p.name === name) ?? (await loadPlugin(name));
|
|
475
477
|
} catch {
|
|
476
478
|
continue;
|
|
477
479
|
}
|
|
@@ -488,22 +490,24 @@ async function embeddedImportersFor(
|
|
|
488
490
|
|
|
489
491
|
/**
|
|
490
492
|
* Parse, resolving embedded content (#2962). A first parse with a probe
|
|
491
|
-
* collects what the
|
|
492
|
-
* importers are loaded and
|
|
493
|
-
*
|
|
493
|
+
* collects what the parsers offer; when they offer anything, the owners'
|
|
494
|
+
* importers are loaded and each is parsed again with them, through one
|
|
495
|
+
* resolver so their directories stay distinct. A parse is a template
|
|
496
|
+
* parser over a file's content, or an export's `reparse` (#2995). Parsers
|
|
497
|
+
* that offer nothing are parsed once, and nothing is loaded. `loaded` are
|
|
498
|
+
* plugins already loaded, reused when one of them owns content.
|
|
494
499
|
*/
|
|
495
500
|
async function parseWithEmbedded(
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
content: string,
|
|
501
|
+
parses: ReadonlyArray<(context: ParseContext) => TemplateIR>,
|
|
502
|
+
loaded: readonly LexiconPlugin[],
|
|
499
503
|
projectDir: string,
|
|
500
|
-
): Promise<{
|
|
504
|
+
): Promise<{ irs: TemplateIR[]; embedded?: EmbeddedImports }> {
|
|
501
505
|
const probe = new EmbeddedImports([], { quiet: true });
|
|
502
|
-
const
|
|
503
|
-
if (probe.offered.length === 0) return {
|
|
504
|
-
const importers = await embeddedImportersFor(probe.offered,
|
|
506
|
+
const irs = parses.map((parse) => parse({ embedded: probe }));
|
|
507
|
+
if (probe.offered.length === 0) return { irs };
|
|
508
|
+
const importers = await embeddedImportersFor(probe.offered, loaded, projectDir);
|
|
505
509
|
const embedded = new EmbeddedImports(importers);
|
|
506
|
-
return {
|
|
510
|
+
return { irs: parses.map((parse) => parse({ embedded })), embedded };
|
|
507
511
|
}
|
|
508
512
|
|
|
509
513
|
/** The shared tail of every template import: parse → generate → write. */
|
|
@@ -535,7 +539,9 @@ async function parseAndWrite(
|
|
|
535
539
|
let embedded: EmbeddedImports | undefined;
|
|
536
540
|
try {
|
|
537
541
|
const parser = plugin.templateParser();
|
|
538
|
-
|
|
542
|
+
let irs: TemplateIR[];
|
|
543
|
+
({ irs, embedded } = await parseWithEmbedded([(context) => parser.parse(content, context)], [plugin], projectDir));
|
|
544
|
+
ir = irs[0];
|
|
539
545
|
} catch (err) {
|
|
540
546
|
return {
|
|
541
547
|
success: false,
|
|
@@ -701,6 +707,7 @@ export async function liveImportFromPlugins(
|
|
|
701
707
|
options: LiveImportOptions,
|
|
702
708
|
): Promise<ImportResult> {
|
|
703
709
|
const outputDir = resolve(options.output ?? "./infra/");
|
|
710
|
+
const projectDir = resolve(options.output ? dirname(options.output) : ".");
|
|
704
711
|
const warnings: string[] = [];
|
|
705
712
|
|
|
706
713
|
let exporters = plugins.filter((p) => p.exportResources && p.templateGenerator);
|
|
@@ -720,10 +727,10 @@ export async function liveImportFromPlugins(
|
|
|
720
727
|
}
|
|
721
728
|
|
|
722
729
|
// Collect IR from every exporter, tagging which lexicon produced output.
|
|
723
|
-
|
|
730
|
+
let irParts: ExportedTemplate[] = [];
|
|
724
731
|
let generatorLexicon: LexiconPlugin | undefined;
|
|
725
732
|
for (const plugin of exporters) {
|
|
726
|
-
let ir:
|
|
733
|
+
let ir: ExportedTemplate;
|
|
727
734
|
try {
|
|
728
735
|
ir = await plugin.exportResources!({
|
|
729
736
|
environment: options.environment,
|
|
@@ -754,6 +761,23 @@ export async function liveImportFromPlugins(
|
|
|
754
761
|
warnings.push("Multiple lexicons exported resources; generated with the first. Use --lexicon to target one.");
|
|
755
762
|
}
|
|
756
763
|
|
|
764
|
+
// Content embedded in exported resources goes to the lexicon that owns it,
|
|
765
|
+
// as in file import (#2995). An export without `reparse` keeps it as read.
|
|
766
|
+
let embedded: EmbeddedImports | undefined;
|
|
767
|
+
if (irParts.some((part) => part.reparse)) {
|
|
768
|
+
try {
|
|
769
|
+
const parses = irParts.map((part) => part.reparse ?? (() => part));
|
|
770
|
+
let irs: TemplateIR[];
|
|
771
|
+
({ irs, embedded } = await parseWithEmbedded(parses, plugins, projectDir));
|
|
772
|
+
irParts = irs;
|
|
773
|
+
} catch (err) {
|
|
774
|
+
warnings.push(
|
|
775
|
+
`Embedded content is kept as written, because resolving it failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
if (embedded) warnings.push(...embedded.warnings);
|
|
779
|
+
}
|
|
780
|
+
|
|
757
781
|
const ir = mergeIR(irParts);
|
|
758
782
|
const generator = generatorLexicon.templateGenerator!();
|
|
759
783
|
|
|
@@ -761,8 +785,10 @@ export async function liveImportFromPlugins(
|
|
|
761
785
|
mkdirSync(outputDir, { recursive: true });
|
|
762
786
|
}
|
|
763
787
|
|
|
764
|
-
const { files, warnings: layoutWarnings } = generateOrganizedFiles(ir, generator);
|
|
788
|
+
const { files: hostFiles, warnings: layoutWarnings } = generateOrganizedFiles(ir, generator);
|
|
765
789
|
warnings.push(...layoutWarnings);
|
|
790
|
+
// The owners' modules for embedded content, each in a directory of its own.
|
|
791
|
+
const files = [...hostFiles, ...(embedded?.files ?? [])];
|
|
766
792
|
const generatedFiles: string[] = [];
|
|
767
793
|
for (const file of files) {
|
|
768
794
|
const filePath = join(outputDir, file.path);
|