@deftai/directive-core 0.104.0 → 0.105.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/authz/classify.js +526 -42
- package/dist/check/cached-orchestrator.d.ts +1 -1
- package/dist/check/cached-orchestrator.js +2 -2
- package/dist/check/named-cause.d.ts +1 -1
- package/dist/check/named-cause.js +33 -3
- package/dist/codebase/default-extractor.d.ts +5 -0
- package/dist/codebase/default-extractor.js +7 -15
- package/dist/deposit/copy-tree.js +60 -0
- package/dist/deposit/python-free.js +26 -18
- package/dist/doctor/checks.d.ts +8 -0
- package/dist/doctor/checks.js +37 -25
- package/dist/doctor/doctor-state.d.ts +4 -0
- package/dist/doctor/doctor-state.js +7 -1
- package/dist/doctor/main.js +9 -19
- package/dist/doctor/types.d.ts +9 -0
- package/dist/fs/contained-write.d.ts +115 -1
- package/dist/fs/contained-write.js +241 -5
- package/dist/fs/mutation-ledger.d.ts +54 -0
- package/dist/fs/mutation-ledger.js +133 -0
- package/dist/fs/non-product-dirs.d.ts +79 -0
- package/dist/fs/non-product-dirs.js +96 -0
- package/dist/hooks/dispatcher.d.ts +3 -1
- package/dist/hooks/dispatcher.js +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/init-deposit/agent-hooks.js +17 -15
- package/dist/init-deposit/core-guard-pin-content.d.ts +7 -0
- package/dist/init-deposit/core-guard-pin-content.js +393 -0
- package/dist/init-deposit/gitignore.js +9 -0
- package/dist/init-deposit/hygiene.d.ts +47 -11
- package/dist/init-deposit/hygiene.js +172 -37
- package/dist/init-deposit/legacy-detect.js +6 -2
- package/dist/init-deposit/refresh.d.ts +21 -1
- package/dist/init-deposit/refresh.js +106 -9
- package/dist/init-deposit/scaffold.js +28 -279
- package/dist/init-deposit/slash-deposit.js +13 -7
- package/dist/init-deposit/xbrief-projections.d.ts +8 -1
- package/dist/init-deposit/xbrief-projections.js +24 -11
- package/dist/intake/clause-derivation.d.ts +38 -1
- package/dist/intake/clause-derivation.js +211 -9
- package/dist/intake/issue-ingest.d.ts +3 -1
- package/dist/intake/issue-ingest.js +35 -6
- package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
- package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
- package/dist/literal-acceptance/capture.d.ts +10 -0
- package/dist/literal-acceptance/capture.js +224 -75
- package/dist/literal-acceptance/evaluate.d.ts +29 -4
- package/dist/literal-acceptance/evaluate.js +70 -2
- package/dist/literal-acceptance/index.d.ts +3 -3
- package/dist/literal-acceptance/index.js +3 -3
- package/dist/literal-acceptance/safety.d.ts +41 -0
- package/dist/literal-acceptance/safety.js +126 -2
- package/dist/literal-acceptance/types.d.ts +8 -0
- package/dist/orphan-active/evaluate.d.ts +7 -1
- package/dist/orphan-active/evaluate.js +102 -23
- package/dist/platform/platform-capabilities.js +2 -3
- package/dist/policy/base-branch.d.ts +37 -0
- package/dist/policy/base-branch.js +114 -0
- package/dist/policy/branch-sync.d.ts +80 -0
- package/dist/policy/branch-sync.js +211 -0
- package/dist/policy/ceremony-dial-escalation.js +1 -0
- package/dist/policy/ceremony-dial.js +4 -14
- package/dist/policy/delivery-branch.d.ts +5 -3
- package/dist/policy/delivery-branch.js +7 -3
- package/dist/policy/file-size-thresholds.d.ts +24 -0
- package/dist/policy/file-size-thresholds.js +23 -0
- package/dist/policy/forge-outage-retry.d.ts +47 -0
- package/dist/policy/forge-outage-retry.js +157 -0
- package/dist/policy/index.d.ts +7 -0
- package/dist/policy/index.js +66 -7
- package/dist/policy/project-invariants.d.ts +50 -0
- package/dist/policy/project-invariants.js +205 -0
- package/dist/policy/sync-default.d.ts +129 -0
- package/dist/policy/sync-default.js +452 -0
- package/dist/policy/sync-max-files.d.ts +93 -0
- package/dist/policy/sync-max-files.js +192 -0
- package/dist/pr-monitor/absent-required.d.ts +11 -0
- package/dist/pr-monitor/absent-required.js +61 -0
- package/dist/pr-monitor/constants.d.ts +7 -0
- package/dist/pr-monitor/constants.js +7 -0
- package/dist/pr-monitor/index.d.ts +2 -1
- package/dist/pr-monitor/index.js +2 -1
- package/dist/pr-monitor/main.js +4 -0
- package/dist/pr-monitor/monitor.js +24 -1
- package/dist/pr-wait-mergeable/classify.js +6 -0
- package/dist/preflight/evaluate.d.ts +4 -0
- package/dist/preflight/evaluate.js +35 -1
- package/dist/preflight/index.d.ts +4 -0
- package/dist/preflight/index.js +2 -0
- package/dist/preflight/intended-placement.d.ts +62 -0
- package/dist/preflight/intended-placement.js +275 -0
- package/dist/preflight/project-invariants-gate.d.ts +29 -0
- package/dist/preflight/project-invariants-gate.js +82 -0
- package/dist/product-first-done-gate/acceptance-resolver.d.ts +128 -0
- package/dist/product-first-done-gate/acceptance-resolver.js +144 -0
- package/dist/product-first-done-gate/acceptance.d.ts +7 -4
- package/dist/product-first-done-gate/acceptance.js +79 -8
- package/dist/product-first-done-gate/empty-resolution.d.ts +4 -1
- package/dist/product-first-done-gate/empty-resolution.js +12 -1
- package/dist/product-first-done-gate/evaluate.d.ts +12 -0
- package/dist/product-first-done-gate/evaluate.js +254 -31
- package/dist/product-first-done-gate/index.d.ts +2 -0
- package/dist/product-first-done-gate/index.js +1 -0
- package/dist/release/build-dist.d.ts +101 -0
- package/dist/release/build-dist.js +428 -46
- package/dist/run-summary/emit.d.ts +16 -10
- package/dist/run-summary/emit.js +26 -15
- package/dist/run-summary/index.d.ts +3 -2
- package/dist/run-summary/index.js +2 -1
- package/dist/run-summary/session-id.d.ts +21 -0
- package/dist/run-summary/session-id.js +92 -0
- package/dist/run-summary/types.d.ts +29 -4
- package/dist/run-summary/types.js +1 -0
- package/dist/scope/acceptance-evidence.d.ts +19 -7
- package/dist/scope/acceptance-evidence.js +38 -11
- package/dist/scope/delivery-evidence.d.ts +3 -3
- package/dist/scope/delivery-evidence.js +22 -27
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/parent-lineage.js +7 -6
- package/dist/scope/project-invariant-coverage.d.ts +54 -0
- package/dist/scope/project-invariant-coverage.js +322 -0
- package/dist/scope/transition.js +1 -1
- package/dist/scope-provenance/compare-intent.d.ts +27 -0
- package/dist/scope-provenance/compare-intent.js +233 -0
- package/dist/scope-provenance/digest.d.ts +18 -1
- package/dist/scope-provenance/digest.js +16 -11
- package/dist/scope-provenance/evaluate.d.ts +5 -1
- package/dist/scope-provenance/evaluate.js +64 -4
- package/dist/scope-provenance/extract-intent.d.ts +43 -0
- package/dist/scope-provenance/extract-intent.js +262 -0
- package/dist/scope-provenance/index.d.ts +7 -1
- package/dist/scope-provenance/index.js +7 -1
- package/dist/scope-provenance/intent-digest.d.ts +12 -0
- package/dist/scope-provenance/intent-digest.js +33 -0
- package/dist/scope-provenance/intent-evaluate.d.ts +43 -0
- package/dist/scope-provenance/intent-evaluate.js +149 -0
- package/dist/scope-provenance/json-tokenizer.d.ts +19 -0
- package/dist/scope-provenance/json-tokenizer.js +225 -0
- package/dist/scope-provenance/known-machine.d.ts +38 -0
- package/dist/scope-provenance/known-machine.js +157 -0
- package/dist/scope-provenance/mint-artifacts.d.ts +102 -0
- package/dist/scope-provenance/mint-artifacts.js +425 -0
- package/dist/session/ac-pass-banking.d.ts +4 -36
- package/dist/session/ac-pass-banking.js +30 -77
- package/dist/session/ac-pass-reuse.d.ts +53 -0
- package/dist/session/ac-pass-reuse.js +95 -0
- package/dist/session/git.js +19 -4
- package/dist/session/index.d.ts +4 -0
- package/dist/session/index.js +4 -0
- package/dist/session/occupancy-stress-worker.d.ts +7 -0
- package/dist/session/occupancy-stress-worker.js +36 -0
- package/dist/session/occupancy.d.ts +97 -0
- package/dist/session/occupancy.js +422 -0
- package/dist/session/openclaw-soft-rebind-deposit.js +6 -6
- package/dist/session/product-state-hash.d.ts +26 -0
- package/dist/session/product-state-hash.js +683 -0
- package/dist/session/session-ready.d.ts +2 -0
- package/dist/session/session-ready.js +52 -30
- package/dist/session/session-start.d.ts +7 -0
- package/dist/session/session-start.js +71 -7
- package/dist/session/verify-ac-session-cache.d.ts +42 -0
- package/dist/session/verify-ac-session-cache.js +126 -0
- package/dist/session/verify-session-ritual.d.ts +5 -0
- package/dist/session/verify-session-ritual.js +9 -0
- package/dist/slash/openclaw-deposit.js +13 -9
- package/dist/slice/constants.d.ts +2 -2
- package/dist/slice/constants.js +2 -2
- package/dist/slice/existing.js +9 -3
- package/dist/slice/lock.d.ts +16 -1
- package/dist/slice/lock.js +137 -11
- package/dist/story-ready/evaluate.d.ts +2 -0
- package/dist/story-ready/evaluate.js +13 -0
- package/dist/swarm/complete-cohort.d.ts +3 -0
- package/dist/swarm/complete-cohort.js +59 -11
- package/dist/swarm/finalize-cohort.js +33 -2
- package/dist/swarm/launch.d.ts +22 -0
- package/dist/swarm/launch.js +155 -0
- package/dist/swarm/routing-set-cli.d.ts +11 -1
- package/dist/swarm/routing-set-cli.js +13 -3
- package/dist/swarm/routing-verify.d.ts +12 -0
- package/dist/swarm/routing-verify.js +59 -20
- package/dist/swarm/routing.d.ts +14 -0
- package/dist/swarm/routing.js +53 -3
- package/dist/telemetry-coverage/fake-trial.js +10 -0
- package/dist/telemetry-coverage/kinds.js +2 -0
- package/dist/triage/actions/index.js +4 -1
- package/dist/ts-check-lane/index.d.ts +3 -0
- package/dist/ts-check-lane/index.js +2 -0
- package/dist/ts-check-lane/progress-reporter.d.ts +17 -0
- package/dist/ts-check-lane/progress-reporter.js +38 -0
- package/dist/ts-check-lane/progress.d.ts +32 -0
- package/dist/ts-check-lane/progress.js +57 -0
- package/dist/ts-check-lane/run-lane.d.ts +3 -1
- package/dist/ts-check-lane/run-lane.js +8 -6
- package/dist/validate-content/validate-links.d.ts +8 -0
- package/dist/validate-content/validate-links.js +9 -15
- package/dist/value/feedback-file.js +12 -2
- package/dist/vbrief-build/index.d.ts +1 -0
- package/dist/vbrief-build/index.js +1 -0
- package/dist/vbrief-build/project-invariants-io.d.ts +16 -0
- package/dist/vbrief-build/project-invariants-io.js +41 -0
- package/dist/vbrief-reconcile/graph.js +18 -1
- package/dist/vbrief-reconcile/index.d.ts +1 -1
- package/dist/vbrief-reconcile/index.js +1 -1
- package/dist/vbrief-reconcile/types.d.ts +13 -0
- package/dist/vbrief-reconcile/umbrellas.d.ts +14 -0
- package/dist/vbrief-reconcile/umbrellas.js +261 -26
- package/dist/vbrief-validate/index.d.ts +1 -1
- package/dist/vbrief-validate/index.js +1 -1
- package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
- package/dist/vbrief-validate/plan-hooks.js +68 -0
- package/dist/verify-ac/evaluate.d.ts +7 -1
- package/dist/verify-ac/evaluate.js +34 -26
- package/dist/verify-ac/flag.d.ts +4 -0
- package/dist/verify-ac/flag.js +16 -0
- package/dist/verify-ac/index.d.ts +2 -2
- package/dist/verify-ac/index.js +2 -2
- package/dist/verify-source/contained-writes.js +2 -0
- package/dist/verify-source/verify-stubs.d.ts +15 -1
- package/dist/verify-source/verify-stubs.js +20 -16
- package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +5 -6
- package/dist/vitest-runner/win32-coverage-tmp-setup.js +5 -6
- package/dist/xbrief-migrate/migrate-project.js +2 -5
- package/package.json +3 -3
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One mint writes record + preimage + both digests (#3376 R7 / #3385).
|
|
3
|
+
* Dest publish is two-phase under a per-plan lock: both dests land as
|
|
4
|
+
* `.next` first, then dests are copied from that pair. A crash leaves
|
|
5
|
+
* `.next` and/or a bak journal; recover finishes the flip or restores
|
|
6
|
+
* the prior pair (or neither dest) without waiting for a remint.
|
|
7
|
+
* Caught write failures still restore or clear dests.
|
|
8
|
+
*/
|
|
9
|
+
import { type ApprovedScopeRecord, approvedScopeIntentPath, approvedScopeRecordPath } from "./digest.js";
|
|
10
|
+
import { type ExtractIntentOptions, type IntentPreimage } from "./extract-intent.js";
|
|
11
|
+
export { approvedScopeIntentPath, approvedScopeRecordPath };
|
|
12
|
+
export interface MintPublishDestInput {
|
|
13
|
+
readonly root: string;
|
|
14
|
+
readonly target: string;
|
|
15
|
+
readonly data: string;
|
|
16
|
+
}
|
|
17
|
+
export interface MintRestoreDestInput {
|
|
18
|
+
readonly root: string;
|
|
19
|
+
readonly target: string;
|
|
20
|
+
readonly snapshot: string | null;
|
|
21
|
+
}
|
|
22
|
+
export interface MintRemoveDestInput {
|
|
23
|
+
readonly root: string;
|
|
24
|
+
readonly target: string;
|
|
25
|
+
}
|
|
26
|
+
export declare class MintPairRollbackError extends Error {
|
|
27
|
+
readonly writeError: unknown;
|
|
28
|
+
readonly restoreError: unknown;
|
|
29
|
+
readonly clearError: unknown | undefined;
|
|
30
|
+
constructor(writeError: unknown, restoreError: unknown, clearError?: unknown);
|
|
31
|
+
}
|
|
32
|
+
export interface MintArtifactsInput {
|
|
33
|
+
readonly xbriefRelPath: string;
|
|
34
|
+
readonly payload: unknown;
|
|
35
|
+
readonly rawText: string;
|
|
36
|
+
readonly projectRoot: string;
|
|
37
|
+
readonly humanApproval?: ApprovedScopeRecord["humanApproval"];
|
|
38
|
+
readonly approvedAt?: string;
|
|
39
|
+
readonly extract?: ExtractIntentOptions;
|
|
40
|
+
/**
|
|
41
|
+
* Test-only dest publish after both temp payloads exist.
|
|
42
|
+
* Production uses containedWrite replace.
|
|
43
|
+
*/
|
|
44
|
+
readonly publishDest?: (input: MintPublishDestInput) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Test-only dest restore after a dest-publish failure.
|
|
47
|
+
* Production restores via containedWrite replace / rmSync.
|
|
48
|
+
*/
|
|
49
|
+
readonly restoreDest?: (input: MintRestoreDestInput) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Test-only dest remove during rollback cleanup.
|
|
52
|
+
* Production uses rmSync.
|
|
53
|
+
*/
|
|
54
|
+
readonly removeDest?: (input: MintRemoveDestInput) => void;
|
|
55
|
+
/** Test-only lock wait. Production waits 30s. */
|
|
56
|
+
readonly lockWaitMs?: number;
|
|
57
|
+
}
|
|
58
|
+
export interface MintArtifactsResult {
|
|
59
|
+
readonly record: ApprovedScopeRecord;
|
|
60
|
+
readonly preimage: IntentPreimage;
|
|
61
|
+
readonly recordPath: string;
|
|
62
|
+
readonly intentPath: string;
|
|
63
|
+
}
|
|
64
|
+
export declare function approvedScopePairLockPath(dir: string, recordPath: string): string;
|
|
65
|
+
export declare function approvedScopePairJournalPaths(dir: string, intentPath: string, recordPath: string): {
|
|
66
|
+
readonly publishing: string;
|
|
67
|
+
readonly intentBak: string;
|
|
68
|
+
readonly recordBak: string;
|
|
69
|
+
};
|
|
70
|
+
export declare function approvedScopePairNextPaths(dir: string, intentPath: string, recordPath: string): {
|
|
71
|
+
readonly intentNext: string;
|
|
72
|
+
readonly recordNext: string;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Finish a staged dest flip from `.next`, or restore the bak pair / clear dests.
|
|
76
|
+
* Does not wait for a remint.
|
|
77
|
+
*/
|
|
78
|
+
export declare function recoverIncompleteApprovedScopePair(input: {
|
|
79
|
+
readonly projectRoot: string;
|
|
80
|
+
readonly intentPath: string;
|
|
81
|
+
readonly recordPath: string;
|
|
82
|
+
}): boolean;
|
|
83
|
+
/** Recover every incomplete pair under `.deft/approved-scope/`. */
|
|
84
|
+
export declare function recoverApprovedScopePairs(projectRoot: string): number;
|
|
85
|
+
/**
|
|
86
|
+
* Write record + preimage as one fail-closed pair.
|
|
87
|
+
* Phase 1 writes both dests to `.next`. Phase 2 copies dests from that pair.
|
|
88
|
+
* Recover finishes the flip or restores the bak pair without a remint.
|
|
89
|
+
*/
|
|
90
|
+
export declare function writeApprovedScopePair(input: {
|
|
91
|
+
readonly projectRoot: string;
|
|
92
|
+
readonly intentPath: string;
|
|
93
|
+
readonly recordPath: string;
|
|
94
|
+
readonly intentData: string;
|
|
95
|
+
readonly recordData: string;
|
|
96
|
+
readonly publishDest?: (input: MintPublishDestInput) => void;
|
|
97
|
+
readonly restoreDest?: (input: MintRestoreDestInput) => void;
|
|
98
|
+
readonly removeDest?: (input: MintRemoveDestInput) => void;
|
|
99
|
+
readonly lockWaitMs?: number;
|
|
100
|
+
}): void;
|
|
101
|
+
export declare function mintApprovedScopeArtifacts(input: MintArtifactsInput): MintArtifactsResult;
|
|
102
|
+
//# sourceMappingURL=mint-artifacts.d.ts.map
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One mint writes record + preimage + both digests (#3376 R7 / #3385).
|
|
3
|
+
* Dest publish is two-phase under a per-plan lock: both dests land as
|
|
4
|
+
* `.next` first, then dests are copied from that pair. A crash leaves
|
|
5
|
+
* `.next` and/or a bak journal; recover finishes the flip or restores
|
|
6
|
+
* the prior pair (or neither dest) without waiting for a remint.
|
|
7
|
+
* Caught write failures still restore or clear dests.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync } from "node:fs";
|
|
10
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
11
|
+
import { ContainedWriteError, ContainedWriteErrorCode, containedRemove, containedWrite, } from "../fs/contained-write.js";
|
|
12
|
+
import { approvedScopeDir, approvedScopeIntentPath, approvedScopeRecordPath, buildApprovedScopeRecord, } from "./digest.js";
|
|
13
|
+
import { extractIntentFromRaw, } from "./extract-intent.js";
|
|
14
|
+
import { computeIntentDigest, INTENT_DIGEST_ALGO } from "./intent-digest.js";
|
|
15
|
+
export { approvedScopeIntentPath, approvedScopeRecordPath };
|
|
16
|
+
export class MintPairRollbackError extends Error {
|
|
17
|
+
writeError;
|
|
18
|
+
restoreError;
|
|
19
|
+
clearError;
|
|
20
|
+
constructor(writeError, restoreError, clearError) {
|
|
21
|
+
const writeMsg = errorMessage(writeError);
|
|
22
|
+
const restoreMsg = errorMessage(restoreError);
|
|
23
|
+
const clearSuffix = clearError === undefined
|
|
24
|
+
? "; leftover dests were cleared"
|
|
25
|
+
: `; leftover dests could not be cleared (${errorMessage(clearError)})`;
|
|
26
|
+
super(`Mint dest publish failed (${writeMsg}); rollback also failed (${restoreMsg})${clearSuffix}. Do not commit a partial approved-scope pair.`);
|
|
27
|
+
this.name = "MintPairRollbackError";
|
|
28
|
+
this.writeError = writeError;
|
|
29
|
+
this.restoreError = restoreError;
|
|
30
|
+
this.clearError = clearError;
|
|
31
|
+
this.cause = writeError;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function errorMessage(err) {
|
|
35
|
+
return err instanceof Error ? err.message : String(err);
|
|
36
|
+
}
|
|
37
|
+
function snapshotText(path) {
|
|
38
|
+
if (!existsSync(path))
|
|
39
|
+
return null;
|
|
40
|
+
return readFileSync(path, "utf8");
|
|
41
|
+
}
|
|
42
|
+
function restoreText(root, path, snapshot) {
|
|
43
|
+
rmSync(path, { force: true, recursive: true });
|
|
44
|
+
if (snapshot === null)
|
|
45
|
+
return;
|
|
46
|
+
containedWrite({
|
|
47
|
+
root,
|
|
48
|
+
target: path,
|
|
49
|
+
data: snapshot,
|
|
50
|
+
mode: "replace",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function writeTempPayload(root, target, data) {
|
|
54
|
+
containedWrite({
|
|
55
|
+
root,
|
|
56
|
+
target,
|
|
57
|
+
data,
|
|
58
|
+
mode: "create",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function restoreDestDefault(input) {
|
|
62
|
+
restoreText(input.root, input.target, input.snapshot);
|
|
63
|
+
}
|
|
64
|
+
function removeDestDefault(input) {
|
|
65
|
+
rmSync(input.target, { force: true });
|
|
66
|
+
}
|
|
67
|
+
function pairStem(recordPath) {
|
|
68
|
+
return basename(recordPath).replace(/\.json$/i, "");
|
|
69
|
+
}
|
|
70
|
+
export function approvedScopePairLockPath(dir, recordPath) {
|
|
71
|
+
return join(dir, `.${pairStem(recordPath)}.pair.lock.tmp`);
|
|
72
|
+
}
|
|
73
|
+
export function approvedScopePairJournalPaths(dir, intentPath, recordPath) {
|
|
74
|
+
return {
|
|
75
|
+
publishing: join(dir, `.${pairStem(recordPath)}.publishing.bak`),
|
|
76
|
+
intentBak: join(dir, `${basename(intentPath)}.bak`),
|
|
77
|
+
recordBak: join(dir, `${basename(recordPath)}.bak`),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function approvedScopePairNextPaths(dir, intentPath, recordPath) {
|
|
81
|
+
return {
|
|
82
|
+
intentNext: join(dir, `${basename(intentPath)}.next.tmp`),
|
|
83
|
+
recordNext: join(dir, `${basename(recordPath)}.next.tmp`),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function publishFromNext(root, next, dest) {
|
|
87
|
+
if (!existsSync(next)) {
|
|
88
|
+
throw new Error(`mint pair next payload missing: ${basename(next)}`);
|
|
89
|
+
}
|
|
90
|
+
containedWrite({
|
|
91
|
+
root,
|
|
92
|
+
target: dest,
|
|
93
|
+
data: readFileSync(next, "utf8"),
|
|
94
|
+
mode: "replace",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function writeBak(root, src, bak) {
|
|
98
|
+
if (!existsSync(src)) {
|
|
99
|
+
rmSync(bak, { force: true });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
containedWrite({
|
|
103
|
+
root,
|
|
104
|
+
target: bak,
|
|
105
|
+
data: readFileSync(src, "utf8"),
|
|
106
|
+
mode: "replace",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function clearJournal(paths) {
|
|
110
|
+
rmSync(paths.publishing, { force: true });
|
|
111
|
+
rmSync(paths.intentBak, { force: true });
|
|
112
|
+
rmSync(paths.recordBak, { force: true });
|
|
113
|
+
}
|
|
114
|
+
function pairStemFromPublishingName(name) {
|
|
115
|
+
const match = name.match(/^\.(.+)\.publishing\.bak$/i);
|
|
116
|
+
return match?.[1] ?? null;
|
|
117
|
+
}
|
|
118
|
+
function pairStemFromNextName(name) {
|
|
119
|
+
if (!name.endsWith(".next.tmp"))
|
|
120
|
+
return null;
|
|
121
|
+
const base = name.slice(0, -".next.tmp".length);
|
|
122
|
+
if (base.endsWith(".intent.json"))
|
|
123
|
+
return base.slice(0, -".intent.json".length);
|
|
124
|
+
if (base.endsWith(".json"))
|
|
125
|
+
return base.slice(0, -".json".length);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Finish a staged dest flip from `.next`, or restore the bak pair / clear dests.
|
|
130
|
+
* Does not wait for a remint.
|
|
131
|
+
*/
|
|
132
|
+
export function recoverIncompleteApprovedScopePair(input) {
|
|
133
|
+
const root = resolve(input.projectRoot);
|
|
134
|
+
const dir = approvedScopeDir(input.projectRoot);
|
|
135
|
+
const journal = approvedScopePairJournalPaths(dir, input.intentPath, input.recordPath);
|
|
136
|
+
const next = approvedScopePairNextPaths(dir, input.intentPath, input.recordPath);
|
|
137
|
+
const intentNext = snapshotText(next.intentNext);
|
|
138
|
+
const recordNext = snapshotText(next.recordNext);
|
|
139
|
+
if (intentNext !== null && recordNext !== null) {
|
|
140
|
+
restoreText(root, input.intentPath, intentNext);
|
|
141
|
+
restoreText(root, input.recordPath, recordNext);
|
|
142
|
+
rmSync(next.intentNext, { force: true });
|
|
143
|
+
rmSync(next.recordNext, { force: true });
|
|
144
|
+
clearJournal(journal);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
if (!existsSync(journal.publishing)) {
|
|
148
|
+
const leftover = intentNext !== null || recordNext !== null;
|
|
149
|
+
rmSync(next.intentNext, { force: true });
|
|
150
|
+
rmSync(next.recordNext, { force: true });
|
|
151
|
+
return leftover;
|
|
152
|
+
}
|
|
153
|
+
const intentBak = snapshotText(journal.intentBak);
|
|
154
|
+
const recordBak = snapshotText(journal.recordBak);
|
|
155
|
+
if (intentBak !== null || recordBak !== null) {
|
|
156
|
+
restoreText(root, input.intentPath, intentBak);
|
|
157
|
+
restoreText(root, input.recordPath, recordBak);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
rmSync(input.intentPath, { force: true });
|
|
161
|
+
rmSync(input.recordPath, { force: true });
|
|
162
|
+
}
|
|
163
|
+
rmSync(next.intentNext, { force: true });
|
|
164
|
+
rmSync(next.recordNext, { force: true });
|
|
165
|
+
clearJournal(journal);
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
/** Recover every incomplete pair under `.deft/approved-scope/`. */
|
|
169
|
+
export function recoverApprovedScopePairs(projectRoot) {
|
|
170
|
+
const dir = approvedScopeDir(projectRoot);
|
|
171
|
+
if (!existsSync(dir))
|
|
172
|
+
return 0;
|
|
173
|
+
const stems = new Set();
|
|
174
|
+
for (const name of readdirSync(dir)) {
|
|
175
|
+
const fromPub = pairStemFromPublishingName(name);
|
|
176
|
+
if (fromPub !== null)
|
|
177
|
+
stems.add(fromPub);
|
|
178
|
+
const fromNext = pairStemFromNextName(name);
|
|
179
|
+
if (fromNext !== null)
|
|
180
|
+
stems.add(fromNext);
|
|
181
|
+
}
|
|
182
|
+
let recovered = 0;
|
|
183
|
+
for (const stem of stems) {
|
|
184
|
+
const did = recoverIncompleteApprovedScopePair({
|
|
185
|
+
projectRoot,
|
|
186
|
+
intentPath: join(dir, `${stem}.intent.json`),
|
|
187
|
+
recordPath: join(dir, `${stem}.json`),
|
|
188
|
+
});
|
|
189
|
+
if (did)
|
|
190
|
+
recovered += 1;
|
|
191
|
+
}
|
|
192
|
+
return recovered;
|
|
193
|
+
}
|
|
194
|
+
function ownerPidAlive(lockPath) {
|
|
195
|
+
try {
|
|
196
|
+
const owner = Number(readFileSync(lockPath, "utf8").trim());
|
|
197
|
+
if (!Number.isInteger(owner) || owner <= 0)
|
|
198
|
+
return true;
|
|
199
|
+
process.kill(owner, 0);
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
const code = err.code;
|
|
204
|
+
return code !== "ESRCH";
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function reclaimDeadPairLock(lockPath) {
|
|
208
|
+
const stale = `${lockPath}.stale`;
|
|
209
|
+
try {
|
|
210
|
+
renameSync(lockPath, stale);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
rmSync(stale, { force: true });
|
|
216
|
+
}
|
|
217
|
+
function isCreateExistsError(err) {
|
|
218
|
+
return err instanceof ContainedWriteError && err.code === ContainedWriteErrorCode.EXISTS;
|
|
219
|
+
}
|
|
220
|
+
function withPairLock(root, lockPath, waitMs, fn) {
|
|
221
|
+
mkdirSync(dirname(lockPath), { recursive: true });
|
|
222
|
+
const deadline = Date.now() + waitMs;
|
|
223
|
+
let held = false;
|
|
224
|
+
while (!held) {
|
|
225
|
+
try {
|
|
226
|
+
containedWrite({
|
|
227
|
+
root,
|
|
228
|
+
target: lockPath,
|
|
229
|
+
data: `${process.pid}\n`,
|
|
230
|
+
mode: "create",
|
|
231
|
+
mutation: false,
|
|
232
|
+
});
|
|
233
|
+
held = true;
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
if (!isCreateExistsError(err))
|
|
237
|
+
throw err;
|
|
238
|
+
if (!ownerPidAlive(lockPath)) {
|
|
239
|
+
reclaimDeadPairLock(lockPath);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (Date.now() > deadline) {
|
|
243
|
+
throw new Error(`timed out acquiring mint pair lock for ${basename(lockPath)}`);
|
|
244
|
+
}
|
|
245
|
+
const spinEnd = Date.now() + 20;
|
|
246
|
+
while (Date.now() < spinEnd) {
|
|
247
|
+
/* spin */
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
return fn();
|
|
253
|
+
}
|
|
254
|
+
finally {
|
|
255
|
+
try {
|
|
256
|
+
containedRemove({ root, target: lockPath, mutation: false });
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
rmSync(lockPath, { force: true });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function restorePair(restore, dests) {
|
|
264
|
+
const failures = [];
|
|
265
|
+
for (const dest of dests) {
|
|
266
|
+
try {
|
|
267
|
+
restore(dest);
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
failures.push(`${basename(dest.target)}: ${errorMessage(err)}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (failures.length > 0) {
|
|
274
|
+
throw new Error(failures.join("; "));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function clearDestPair(input) {
|
|
278
|
+
const dests = [
|
|
279
|
+
{ root: input.root, target: input.intentPath, snapshot: input.prevIntent },
|
|
280
|
+
{ root: input.root, target: input.recordPath, snapshot: input.prevRecord },
|
|
281
|
+
];
|
|
282
|
+
const removed = [];
|
|
283
|
+
const failures = [];
|
|
284
|
+
for (const dest of dests) {
|
|
285
|
+
try {
|
|
286
|
+
input.remove({ root: dest.root, target: dest.target });
|
|
287
|
+
removed.push(dest);
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
failures.push(`${basename(dest.target)}: ${errorMessage(err)}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (failures.length === 0)
|
|
294
|
+
return;
|
|
295
|
+
const putBackFailures = [];
|
|
296
|
+
for (const dest of removed) {
|
|
297
|
+
try {
|
|
298
|
+
restoreDestDefault(dest);
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
putBackFailures.push(`${basename(dest.target)}: ${errorMessage(err)}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const putBackSuffix = putBackFailures.length > 0
|
|
305
|
+
? `; removed dests could not be put back (${putBackFailures.join("; ")})`
|
|
306
|
+
: "";
|
|
307
|
+
throw new Error(`${failures.join("; ")}${putBackSuffix}`);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Write record + preimage as one fail-closed pair.
|
|
311
|
+
* Phase 1 writes both dests to `.next`. Phase 2 copies dests from that pair.
|
|
312
|
+
* Recover finishes the flip or restores the bak pair without a remint.
|
|
313
|
+
*/
|
|
314
|
+
export function writeApprovedScopePair(input) {
|
|
315
|
+
const root = resolve(input.projectRoot);
|
|
316
|
+
const dir = approvedScopeDir(input.projectRoot);
|
|
317
|
+
mkdirSync(dir, { recursive: true });
|
|
318
|
+
const lockPath = approvedScopePairLockPath(dir, input.recordPath);
|
|
319
|
+
const journal = approvedScopePairJournalPaths(dir, input.intentPath, input.recordPath);
|
|
320
|
+
const restore = input.restoreDest ?? restoreDestDefault;
|
|
321
|
+
const remove = input.removeDest ?? removeDestDefault;
|
|
322
|
+
const customPublish = input.publishDest;
|
|
323
|
+
const next = approvedScopePairNextPaths(dir, input.intentPath, input.recordPath);
|
|
324
|
+
withPairLock(root, lockPath, input.lockWaitMs ?? 30_000, () => {
|
|
325
|
+
recoverIncompleteApprovedScopePair({
|
|
326
|
+
projectRoot: input.projectRoot,
|
|
327
|
+
intentPath: input.intentPath,
|
|
328
|
+
recordPath: input.recordPath,
|
|
329
|
+
});
|
|
330
|
+
const prevIntent = snapshotText(input.intentPath);
|
|
331
|
+
const prevRecord = snapshotText(input.recordPath);
|
|
332
|
+
const dests = [
|
|
333
|
+
{ root, target: input.intentPath, snapshot: prevIntent },
|
|
334
|
+
{ root, target: input.recordPath, snapshot: prevRecord },
|
|
335
|
+
];
|
|
336
|
+
let destPublished = false;
|
|
337
|
+
try {
|
|
338
|
+
writeTempPayload(root, next.intentNext, input.intentData);
|
|
339
|
+
writeTempPayload(root, next.recordNext, input.recordData);
|
|
340
|
+
writeBak(root, input.intentPath, journal.intentBak);
|
|
341
|
+
writeBak(root, input.recordPath, journal.recordBak);
|
|
342
|
+
containedWrite({
|
|
343
|
+
root,
|
|
344
|
+
target: journal.publishing,
|
|
345
|
+
data: "publishing\n",
|
|
346
|
+
mode: "replace",
|
|
347
|
+
});
|
|
348
|
+
destPublished = true;
|
|
349
|
+
if (customPublish) {
|
|
350
|
+
customPublish({ root, target: input.intentPath, data: input.intentData });
|
|
351
|
+
customPublish({ root, target: input.recordPath, data: input.recordData });
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
publishFromNext(root, next.intentNext, input.intentPath);
|
|
355
|
+
publishFromNext(root, next.recordNext, input.recordPath);
|
|
356
|
+
}
|
|
357
|
+
clearJournal(journal);
|
|
358
|
+
}
|
|
359
|
+
catch (err) {
|
|
360
|
+
if (destPublished) {
|
|
361
|
+
try {
|
|
362
|
+
restorePair(restore, dests);
|
|
363
|
+
clearJournal(journal);
|
|
364
|
+
}
|
|
365
|
+
catch (restoreErr) {
|
|
366
|
+
try {
|
|
367
|
+
clearDestPair({
|
|
368
|
+
root,
|
|
369
|
+
intentPath: input.intentPath,
|
|
370
|
+
recordPath: input.recordPath,
|
|
371
|
+
prevIntent,
|
|
372
|
+
prevRecord,
|
|
373
|
+
remove,
|
|
374
|
+
});
|
|
375
|
+
clearJournal(journal);
|
|
376
|
+
}
|
|
377
|
+
catch (clearErr) {
|
|
378
|
+
throw new MintPairRollbackError(err, restoreErr, clearErr);
|
|
379
|
+
}
|
|
380
|
+
throw new MintPairRollbackError(err, restoreErr);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
throw err;
|
|
384
|
+
}
|
|
385
|
+
finally {
|
|
386
|
+
rmSync(next.intentNext, { force: true });
|
|
387
|
+
rmSync(next.recordNext, { force: true });
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
export function mintApprovedScopeArtifacts(input) {
|
|
392
|
+
const extracted = extractIntentFromRaw(input.rawText, {
|
|
393
|
+
projectRoot: input.projectRoot,
|
|
394
|
+
...input.extract,
|
|
395
|
+
});
|
|
396
|
+
if (!extracted.ok) {
|
|
397
|
+
throw new Error(extracted.error);
|
|
398
|
+
}
|
|
399
|
+
const intentDigest = computeIntentDigest(extracted.preimage);
|
|
400
|
+
const record = {
|
|
401
|
+
...buildApprovedScopeRecord({
|
|
402
|
+
xbriefRelPath: input.xbriefRelPath,
|
|
403
|
+
payload: input.payload,
|
|
404
|
+
approvedAt: input.approvedAt,
|
|
405
|
+
humanApproval: input.humanApproval,
|
|
406
|
+
}),
|
|
407
|
+
intentDigest,
|
|
408
|
+
digestAlgo: INTENT_DIGEST_ALGO,
|
|
409
|
+
};
|
|
410
|
+
const intentPath = approvedScopeIntentPath(input.projectRoot, record.planId);
|
|
411
|
+
const recordPath = approvedScopeRecordPath(input.projectRoot, record.planId);
|
|
412
|
+
writeApprovedScopePair({
|
|
413
|
+
projectRoot: input.projectRoot,
|
|
414
|
+
intentPath,
|
|
415
|
+
recordPath,
|
|
416
|
+
intentData: `${JSON.stringify(extracted.preimage, null, 2)}\n`,
|
|
417
|
+
recordData: `${JSON.stringify(record, null, 2)}\n`,
|
|
418
|
+
publishDest: input.publishDest,
|
|
419
|
+
restoreDest: input.restoreDest,
|
|
420
|
+
removeDest: input.removeDest,
|
|
421
|
+
lockWaitMs: input.lockWaitMs,
|
|
422
|
+
});
|
|
423
|
+
return { record, preimage: extracted.preimage, recordPath, intentPath };
|
|
424
|
+
}
|
|
425
|
+
//# sourceMappingURL=mint-artifacts.js.map
|
|
@@ -38,6 +38,8 @@ export interface AcPassBankRecord {
|
|
|
38
38
|
readonly scopeId: string;
|
|
39
39
|
readonly bankedAt: string;
|
|
40
40
|
readonly headSha: string | null;
|
|
41
|
+
/** Product+acceptance digest; missing/empty is stale for #3387 reuse. */
|
|
42
|
+
readonly productStateHash?: string | null;
|
|
41
43
|
readonly remainingTurns: number | null;
|
|
42
44
|
readonly remainingBudget: number | null;
|
|
43
45
|
readonly maxTurns: number | null;
|
|
@@ -75,6 +77,7 @@ export interface BankAcPassInput {
|
|
|
75
77
|
readonly surplus: SurplusEvaluation;
|
|
76
78
|
readonly nextAction: Exclude<AcPassNextAction, "still_open">;
|
|
77
79
|
readonly headSha?: string | null;
|
|
80
|
+
readonly productStateHash?: string | null;
|
|
78
81
|
readonly now?: string;
|
|
79
82
|
readonly environ?: Readonly<Record<string, string | undefined>>;
|
|
80
83
|
}
|
|
@@ -130,42 +133,6 @@ export declare function readAcPassBank(projectRoot: string, scopeId: string): Ac
|
|
|
130
133
|
* Append a post-bank finding to an existing bank record (report/chase/fix).
|
|
131
134
|
*/
|
|
132
135
|
export declare function recordPostBankFinding(projectRoot: string, scopeId: string, finding: PostBankFinding): AcPassBankRecord | null;
|
|
133
|
-
export interface BankEventPayload {
|
|
134
|
-
readonly type: "ac_pass_bank" | "ac_pass_post_bank_finding" | "ac_pass_deepening_skipped";
|
|
135
|
-
readonly schemaVersion: number;
|
|
136
|
-
readonly scopeId?: string;
|
|
137
|
-
readonly bankedAt?: string;
|
|
138
|
-
readonly nextAction?: string;
|
|
139
|
-
readonly hadSurplus?: boolean;
|
|
140
|
-
readonly surplusThreshold?: number;
|
|
141
|
-
readonly remainingFraction?: number | null;
|
|
142
|
-
readonly remainingTurns?: number | null;
|
|
143
|
-
readonly remainingBudget?: number | null;
|
|
144
|
-
readonly maxTurns?: number | null;
|
|
145
|
-
readonly maxBudget?: number | null;
|
|
146
|
-
readonly headSha?: string | null;
|
|
147
|
-
readonly path?: string;
|
|
148
|
-
readonly finding?: PostBankFinding;
|
|
149
|
-
readonly note?: string;
|
|
150
|
-
readonly [key: string]: unknown;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Format one JSONL bank-event line for run-summary telemetry (#3285 / #3282).
|
|
154
|
-
*/
|
|
155
|
-
export declare function formatBankEventLine(event: BankEventPayload): string;
|
|
156
|
-
/**
|
|
157
|
-
* Append bank event to DEFT_RUN_SUMMARY_PATH when set.
|
|
158
|
-
* Unset = silent. `-` = stdout. Failures warn once to stderr (fail-open).
|
|
159
|
-
*/
|
|
160
|
-
export declare function appendBankEventToRunSummary(input: {
|
|
161
|
-
readonly environ?: Readonly<Record<string, string | undefined>>;
|
|
162
|
-
readonly event: BankEventPayload;
|
|
163
|
-
readonly writeLine?: (path: string, line: string) => void;
|
|
164
|
-
readonly warn?: (message: string) => void;
|
|
165
|
-
}): {
|
|
166
|
-
written: boolean;
|
|
167
|
-
path: string | null;
|
|
168
|
-
};
|
|
169
136
|
/**
|
|
170
137
|
* Simulated run used by the surplus-insufficient acceptance test (#3285):
|
|
171
138
|
* AC passes → bank → extra checks would exceed budget → ship + report finding.
|
|
@@ -205,6 +172,7 @@ export interface MaybeBankOnAcPassInput {
|
|
|
205
172
|
*/
|
|
206
173
|
readonly executableRuns: number;
|
|
207
174
|
readonly quiet?: boolean;
|
|
175
|
+
readonly productStateHash?: string | null;
|
|
208
176
|
}
|
|
209
177
|
export interface MaybeBankOnAcPassResult {
|
|
210
178
|
readonly banked: boolean;
|