@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
|
@@ -15,6 +15,7 @@ import { execFileSync } from "node:child_process";
|
|
|
15
15
|
import { join } from "node:path";
|
|
16
16
|
import { cacheFetchAll } from "../cache/fetch.js";
|
|
17
17
|
import { formatFrameworkCommand } from "../render/framework-commands.js";
|
|
18
|
+
import { applyWorktreeOccupancy, } from "./occupancy.js";
|
|
18
19
|
import { runSessionStart, } from "./session-start.js";
|
|
19
20
|
import { inspectSessionRitual, verifySessionRitual, } from "./verify-session-ritual.js";
|
|
20
21
|
export const SESSION_READY_FAST_PATH = "fast";
|
|
@@ -95,6 +96,54 @@ export function runSessionReady(projectRoot, options = {}) {
|
|
|
95
96
|
const start = options.runStart ?? runSessionStart;
|
|
96
97
|
const fetchAll = options.fetchAll ?? cacheFetchAll;
|
|
97
98
|
const inferRepo = options.inferRepo ?? ((root) => inferSessionReadyRepo(root, env));
|
|
99
|
+
const applyOccupancy = options.applyOccupancy ?? applyWorktreeOccupancy;
|
|
100
|
+
const occupancyInput = (write) => ({
|
|
101
|
+
env,
|
|
102
|
+
now,
|
|
103
|
+
steal: options.sessionStartOptions?.steal,
|
|
104
|
+
confirm: options.sessionStartOptions?.confirm,
|
|
105
|
+
occupant: options.sessionStartOptions?.occupant,
|
|
106
|
+
newSessionId: options.sessionStartOptions?.newSessionId,
|
|
107
|
+
intent: options.sessionStartOptions?.occupancyIntent ?? "mutation",
|
|
108
|
+
write,
|
|
109
|
+
});
|
|
110
|
+
const previewOccupancy = applyOccupancy(projectRoot, occupancyInput(false));
|
|
111
|
+
if (previewOccupancy.code !== 0) {
|
|
112
|
+
const message = previewOccupancy.message;
|
|
113
|
+
lines.push(message);
|
|
114
|
+
return {
|
|
115
|
+
code: previewOccupancy.code,
|
|
116
|
+
message,
|
|
117
|
+
path: SESSION_READY_FAILED,
|
|
118
|
+
lines,
|
|
119
|
+
steps,
|
|
120
|
+
duration_ms: elapsedMs(started),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const claimOnSuccess = () => applyOccupancy(projectRoot, occupancyInput(true));
|
|
124
|
+
const finishReady = (path, message) => {
|
|
125
|
+
const claimed = claimOnSuccess();
|
|
126
|
+
if (claimed.code !== 0) {
|
|
127
|
+
lines.push(claimed.message);
|
|
128
|
+
return {
|
|
129
|
+
code: claimed.code,
|
|
130
|
+
message: claimed.message,
|
|
131
|
+
path: SESSION_READY_FAILED,
|
|
132
|
+
lines,
|
|
133
|
+
steps,
|
|
134
|
+
duration_ms: elapsedMs(started),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
lines.push(message);
|
|
138
|
+
return {
|
|
139
|
+
code: 0,
|
|
140
|
+
message,
|
|
141
|
+
path,
|
|
142
|
+
lines,
|
|
143
|
+
steps,
|
|
144
|
+
duration_ms: elapsedMs(started),
|
|
145
|
+
};
|
|
146
|
+
};
|
|
98
147
|
const verifyOpts = {
|
|
99
148
|
tier: "gated",
|
|
100
149
|
posture: "mutation",
|
|
@@ -127,16 +176,7 @@ export function runSessionReady(projectRoot, options = {}) {
|
|
|
127
176
|
duration_ms: elapsedMs(started),
|
|
128
177
|
};
|
|
129
178
|
}
|
|
130
|
-
|
|
131
|
-
lines.push(message);
|
|
132
|
-
return {
|
|
133
|
-
code: 0,
|
|
134
|
-
message,
|
|
135
|
-
path: SESSION_READY_FAST_PATH,
|
|
136
|
-
lines,
|
|
137
|
-
steps,
|
|
138
|
-
duration_ms: elapsedMs(started),
|
|
139
|
-
};
|
|
179
|
+
return finishReady(SESSION_READY_FAST_PATH, "OK session ready (gated ritual already fresh).");
|
|
140
180
|
}
|
|
141
181
|
// --- Ensure quick-tier ritual state when missing / stale / drifted ---
|
|
142
182
|
const quickInspect = inspect(projectRoot, {
|
|
@@ -175,16 +215,7 @@ export function runSessionReady(projectRoot, options = {}) {
|
|
|
175
215
|
steps.push("verify:session-ritual:gated");
|
|
176
216
|
let verifyResult = verify(projectRoot, verifyOpts);
|
|
177
217
|
if (isGatedVerifyActuallyReady(verifyResult)) {
|
|
178
|
-
|
|
179
|
-
lines.push(message);
|
|
180
|
-
return {
|
|
181
|
-
code: 0,
|
|
182
|
-
message,
|
|
183
|
-
path: SESSION_READY_VERIFIED,
|
|
184
|
-
lines,
|
|
185
|
-
steps,
|
|
186
|
-
duration_ms: elapsedMs(started),
|
|
187
|
-
};
|
|
218
|
+
return finishReady(SESSION_READY_VERIFIED, "OK session ready (gated ritual verified).");
|
|
188
219
|
}
|
|
189
220
|
if (verifyResult.code === 0 && verifyResult.bypassed) {
|
|
190
221
|
const message = bypassedReadyFailure(verifyResult);
|
|
@@ -241,16 +272,7 @@ export function runSessionReady(projectRoot, options = {}) {
|
|
|
241
272
|
steps.push("verify:session-ritual:gated:retry");
|
|
242
273
|
verifyResult = verify(projectRoot, { ...verifyOpts, forceGatedSteps: [] });
|
|
243
274
|
if (isGatedVerifyActuallyReady(verifyResult)) {
|
|
244
|
-
|
|
245
|
-
lines.push(message);
|
|
246
|
-
return {
|
|
247
|
-
code: 0,
|
|
248
|
-
message,
|
|
249
|
-
path: SESSION_READY_RECOVERED,
|
|
250
|
-
lines,
|
|
251
|
-
steps,
|
|
252
|
-
duration_ms: elapsedMs(started),
|
|
253
|
-
};
|
|
275
|
+
return finishReady(SESSION_READY_RECOVERED, "OK session ready (recovered via cache refresh).");
|
|
254
276
|
}
|
|
255
277
|
if (verifyResult.code === 0 && verifyResult.bypassed) {
|
|
256
278
|
const message = bypassedReadyFailure(verifyResult);
|
|
@@ -6,6 +6,7 @@ import { type ProbeScmReadinessOptions, type ScmReadinessReport } from "../scm/r
|
|
|
6
6
|
import { type ResolveUserMdResult } from "../user-config/resolve-user-md.js";
|
|
7
7
|
import { type DetectHardEffortBudgetInput } from "./effort-budget.js";
|
|
8
8
|
import type { GitRunner } from "./git.js";
|
|
9
|
+
import { type ApplyOccupancyInput, type OccupancyDecision } from "./occupancy.js";
|
|
9
10
|
import { type OrientationBundle, type RunOrientationOptions } from "./orientation-compression.js";
|
|
10
11
|
import { type ReleaseAvailabilityProbeOptions } from "./release-availability.js";
|
|
11
12
|
import { type RitualState, ritualStatePath } from "./ritual-sentinel.js";
|
|
@@ -63,6 +64,12 @@ export interface SessionStartOptions {
|
|
|
63
64
|
readonly writeHistory?: boolean;
|
|
64
65
|
readonly runGit?: GitRunner;
|
|
65
66
|
readonly newSessionId?: () => string;
|
|
67
|
+
/** #3433: steal the worktree occupancy lease. Requires confirm + occupant. */
|
|
68
|
+
readonly steal?: boolean;
|
|
69
|
+
readonly confirm?: boolean;
|
|
70
|
+
readonly occupant?: string;
|
|
71
|
+
readonly occupancyIntent?: ApplyOccupancyInput["intent"];
|
|
72
|
+
readonly applyOccupancy?: (projectRoot: string, input: ApplyOccupancyInput) => OccupancyDecision;
|
|
66
73
|
readonly runTriageWelcome?: (projectRoot: string, options: {
|
|
67
74
|
writeHistory: boolean;
|
|
68
75
|
now: Date;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import { runningInsideDeftRepo } from "../doctor/paths.js";
|
|
3
2
|
import { emitSessionEvalReadback } from "../eval/readback.js";
|
|
4
3
|
import { bindSessionGeneration } from "../freshness/bind.js";
|
|
@@ -26,6 +25,7 @@ import { verifyRequiredTools } from "../verify-env/verify-tools.js";
|
|
|
26
25
|
import { ceremonyDialEvidenceToDict, collectCeremonyDialConsumerEvidence, formatCeremonyDialEvidenceLine, mergeCeremonyDialInputsWithConsumerEvidence, } from "./ceremony-dial-evidence.js";
|
|
27
26
|
import { effortBudgetToDict, maybeFormatEffortBudgetLines, resolveProductionHostEffortDescriptor, } from "./effort-budget.js";
|
|
28
27
|
import { defaultGitRunner, gitHead, gitIsAncestor, worktreePath } from "./git.js";
|
|
28
|
+
import { applyWorktreeOccupancy, } from "./occupancy.js";
|
|
29
29
|
import { runOrientationCompression, } from "./orientation-compression.js";
|
|
30
30
|
import { emitSessionStartProcessCost } from "./process-cost.js";
|
|
31
31
|
import { probeSessionReleaseAvailability, } from "./release-availability.js";
|
|
@@ -433,6 +433,46 @@ function resolveEffortBudget(options) {
|
|
|
433
433
|
};
|
|
434
434
|
}
|
|
435
435
|
}
|
|
436
|
+
function occupancyInput(options, now, write) {
|
|
437
|
+
return {
|
|
438
|
+
env: options.env,
|
|
439
|
+
now,
|
|
440
|
+
newSessionId: options.newSessionId,
|
|
441
|
+
steal: options.steal,
|
|
442
|
+
confirm: options.confirm,
|
|
443
|
+
occupant: options.occupant,
|
|
444
|
+
intent: options.occupancyIntent ?? "mutation",
|
|
445
|
+
write,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
function runOccupancy(projectRoot, options, now, write) {
|
|
449
|
+
const apply = options.applyOccupancy ?? applyWorktreeOccupancy;
|
|
450
|
+
return apply(projectRoot, occupancyInput(options, now, write));
|
|
451
|
+
}
|
|
452
|
+
function occupancyDeniedResult(occupancy, environment) {
|
|
453
|
+
return {
|
|
454
|
+
code: occupancy.code,
|
|
455
|
+
payload: {
|
|
456
|
+
ready: false,
|
|
457
|
+
exit_code: occupancy.code,
|
|
458
|
+
posture: MUTATION_POSTURE,
|
|
459
|
+
occupancy: {
|
|
460
|
+
action: occupancy.action,
|
|
461
|
+
session_id: occupancy.sessionId,
|
|
462
|
+
occupant_id: occupancy.record?.sessionId ?? null,
|
|
463
|
+
},
|
|
464
|
+
environment: environmentContextToDict(environment),
|
|
465
|
+
message: occupancy.message,
|
|
466
|
+
},
|
|
467
|
+
lines: occupancy.message.split("\n"),
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
function persistOccupancyOrDeny(projectRoot, options, now, environment) {
|
|
471
|
+
const occupancy = runOccupancy(projectRoot, options, now, true);
|
|
472
|
+
if (occupancy.code !== 0)
|
|
473
|
+
return occupancyDeniedResult(occupancy, environment);
|
|
474
|
+
return occupancy;
|
|
475
|
+
}
|
|
436
476
|
function runReadOnlySessionStart(projectRoot, options, instant, environment) {
|
|
437
477
|
const lines = [];
|
|
438
478
|
const resolveUserMd = options.resolveUserMd ?? ((root) => resolveUserMdPath({ projectRoot: root }));
|
|
@@ -509,6 +549,10 @@ function runSessionRearm(projectRoot, options, instant, environment) {
|
|
|
509
549
|
lines: [formatEnvironmentContext(environment), message],
|
|
510
550
|
};
|
|
511
551
|
}
|
|
552
|
+
const plannedOccupancy = runOccupancy(projectRoot, options, instant, options.steal === true);
|
|
553
|
+
if (plannedOccupancy.code !== 0) {
|
|
554
|
+
return occupancyDeniedResult(plannedOccupancy, environment);
|
|
555
|
+
}
|
|
512
556
|
const resolveUserMd = options.resolveUserMd ?? ((root) => resolveUserMdPath({ projectRoot: root }));
|
|
513
557
|
const userMd = resolveUserMd(projectRoot);
|
|
514
558
|
const safePath = userMd.path.replace(/\r?\n/g, " ");
|
|
@@ -606,7 +650,12 @@ function runSessionRearm(projectRoot, options, instant, environment) {
|
|
|
606
650
|
};
|
|
607
651
|
const gatedSteps = restampSteps(eligibility.state.gatedSteps, instant);
|
|
608
652
|
const writeStarted = performance.now();
|
|
609
|
-
const
|
|
653
|
+
const persistedOccupancy = persistOccupancyOrDeny(projectRoot, options, instant, environment);
|
|
654
|
+
if ("payload" in persistedOccupancy) {
|
|
655
|
+
return persistedOccupancy;
|
|
656
|
+
}
|
|
657
|
+
// #3433: keep DEFT_SESSION_ID / occupant id. Do not mint a new UUID on re-arm.
|
|
658
|
+
const rearmSessionId = persistedOccupancy.sessionId;
|
|
610
659
|
// Fresh payload (no rearm_needed / compact_resume_at) clears compact markers (#2992).
|
|
611
660
|
const writePayload = {
|
|
612
661
|
...newRitualStatePayload({
|
|
@@ -714,6 +763,10 @@ function runSessionRearm(projectRoot, options, instant, environment) {
|
|
|
714
763
|
scm: scmReadinessToDict(scm),
|
|
715
764
|
host_content_surface: hostContentSurfaceToDict(hostSurface.report),
|
|
716
765
|
effort_budget: effortBudgetToDict(effortBudget.budget),
|
|
766
|
+
occupancy: {
|
|
767
|
+
action: persistedOccupancy.action,
|
|
768
|
+
session_id: rearmSessionId,
|
|
769
|
+
},
|
|
717
770
|
message: code === 0 ? "session ritual re-armed" : "session ritual re-arm failed",
|
|
718
771
|
},
|
|
719
772
|
lines,
|
|
@@ -847,6 +900,10 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
847
900
|
lines: [formatEnvironmentContext(environment), payload.message],
|
|
848
901
|
};
|
|
849
902
|
}
|
|
903
|
+
const plannedOccupancy = runOccupancy(projectRoot, options, instant, options.steal === true);
|
|
904
|
+
if (plannedOccupancy.code !== 0) {
|
|
905
|
+
return occupancyDeniedResult(plannedOccupancy, environment);
|
|
906
|
+
}
|
|
850
907
|
const quickSteps = recordDeferredSteps(QUICK_STEPS, effectiveDeferrals, instant);
|
|
851
908
|
const gatedSteps = recordDeferredSteps(GATED_STEPS, effectiveDeferrals, instant);
|
|
852
909
|
const lines = [];
|
|
@@ -1214,7 +1271,11 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
1214
1271
|
lines.push(consentPrompt.trimEnd());
|
|
1215
1272
|
}
|
|
1216
1273
|
const writeStarted = performance.now();
|
|
1217
|
-
const
|
|
1274
|
+
const persistedOccupancy = persistOccupancyOrDeny(projectRoot, options, instant, environment);
|
|
1275
|
+
if ("payload" in persistedOccupancy) {
|
|
1276
|
+
return persistedOccupancy;
|
|
1277
|
+
}
|
|
1278
|
+
const coldSessionId = persistedOccupancy.sessionId;
|
|
1218
1279
|
const dialDict = {
|
|
1219
1280
|
...ceremonyDialToDict(ceremonyDialSelection),
|
|
1220
1281
|
start_tier: ceremonyDialSelection.depth,
|
|
@@ -1298,10 +1359,9 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
1298
1359
|
}
|
|
1299
1360
|
: {}),
|
|
1300
1361
|
});
|
|
1301
|
-
// #
|
|
1302
|
-
//
|
|
1303
|
-
//
|
|
1304
|
-
// else this session:start CLI invocation (1).
|
|
1362
|
+
// #3399: emit a denominator only when a host/harness value is known.
|
|
1363
|
+
// Prefer DEFT_TOTAL_TOOL_TURNS (harness_actual), then DEFT_MAX_TURNS /
|
|
1364
|
+
// host maxTurns (host_planned). Unset → no event; share is unevaluable.
|
|
1305
1365
|
emitter.emitSessionToolTurnDenominator(effortBudget.budget.maxTurns);
|
|
1306
1366
|
// #3319: evaluate escalate-on-evidence only when #3274 is live. A pin
|
|
1307
1367
|
// emits nothing so never-evaluated stays distinguishable from declined.
|
|
@@ -1386,6 +1446,10 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
1386
1446
|
scm: scmReadinessToDict(scm),
|
|
1387
1447
|
host_content_surface: hostContentSurfaceToDict(hostSurface.report),
|
|
1388
1448
|
effort_budget: effortBudgetToDict(effortBudget.budget),
|
|
1449
|
+
occupancy: {
|
|
1450
|
+
action: persistedOccupancy.action,
|
|
1451
|
+
session_id: coldSessionId,
|
|
1452
|
+
},
|
|
1389
1453
|
message: code === 0 ? "session ritual recorded" : "session ritual failed",
|
|
1390
1454
|
};
|
|
1391
1455
|
// #2994: local process-cost event (best-effort; never blocks ceremony).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Same-session verify:ac result cache (#3387).
|
|
3
|
+
*
|
|
4
|
+
* Disk-backed so check composition (spawned verify:ac) can serve from_cache
|
|
5
|
+
* after a green run in the same session when plan + product hash still match.
|
|
6
|
+
*/
|
|
7
|
+
export declare const VERIFY_AC_SESSION_CACHE_DIR = ".deft/verify-ac-session-cache";
|
|
8
|
+
export declare const AC_SERVED_FROM: readonly ["bank", "cache", "executed"];
|
|
9
|
+
export type AcServedFrom = (typeof AC_SERVED_FROM)[number];
|
|
10
|
+
export interface CachedVerifyAcSnapshot {
|
|
11
|
+
readonly ok: boolean;
|
|
12
|
+
readonly code: 0 | 1 | 2;
|
|
13
|
+
readonly message: string;
|
|
14
|
+
readonly commands: readonly unknown[];
|
|
15
|
+
readonly runs: readonly unknown[];
|
|
16
|
+
readonly rejected?: readonly unknown[];
|
|
17
|
+
readonly sourceRung: string;
|
|
18
|
+
readonly noneStated: boolean;
|
|
19
|
+
readonly acceptance: unknown;
|
|
20
|
+
readonly resolution: string;
|
|
21
|
+
readonly resolvedCommandCount: number;
|
|
22
|
+
}
|
|
23
|
+
export interface VerifyAcSessionCacheRecord {
|
|
24
|
+
readonly sessionId: string;
|
|
25
|
+
readonly scopeId: string;
|
|
26
|
+
readonly productStateHash: string;
|
|
27
|
+
readonly cachedAt: string;
|
|
28
|
+
readonly snapshot: CachedVerifyAcSnapshot;
|
|
29
|
+
}
|
|
30
|
+
export declare function verifyAcSessionCacheDir(projectRoot: string): string;
|
|
31
|
+
export declare function verifyAcSessionCachePath(projectRoot: string, sessionId: string, scopeId: string): string;
|
|
32
|
+
export declare function resolveVerifyAcSessionId(env?: Readonly<Record<string, string | undefined>>, explicit?: string | null): string | null;
|
|
33
|
+
export declare function readVerifyAcSessionCache(projectRoot: string, sessionId: string, scopeId: string): VerifyAcSessionCacheRecord | null;
|
|
34
|
+
export declare function writeVerifyAcSessionCache(input: {
|
|
35
|
+
readonly projectRoot: string;
|
|
36
|
+
readonly sessionId: string;
|
|
37
|
+
readonly scopeId: string;
|
|
38
|
+
readonly productStateHash: string;
|
|
39
|
+
readonly snapshot: CachedVerifyAcSnapshot;
|
|
40
|
+
readonly now?: string;
|
|
41
|
+
}): VerifyAcSessionCacheRecord;
|
|
42
|
+
//# sourceMappingURL=verify-ac-session-cache.d.ts.map
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Same-session verify:ac result cache (#3387).
|
|
3
|
+
*
|
|
4
|
+
* Disk-backed so check composition (spawned verify:ac) can serve from_cache
|
|
5
|
+
* after a green run in the same session when plan + product hash still match.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
8
|
+
import { join, resolve } from "node:path";
|
|
9
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
10
|
+
import { sanitizeScopeIdForFilename } from "./ac-pass-banking.js";
|
|
11
|
+
export const VERIFY_AC_SESSION_CACHE_DIR = ".deft/verify-ac-session-cache";
|
|
12
|
+
export const AC_SERVED_FROM = ["bank", "cache", "executed"];
|
|
13
|
+
function asRecord(value) {
|
|
14
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
export function verifyAcSessionCacheDir(projectRoot) {
|
|
20
|
+
return join(resolve(projectRoot), ...VERIFY_AC_SESSION_CACHE_DIR.split("/"));
|
|
21
|
+
}
|
|
22
|
+
export function verifyAcSessionCachePath(projectRoot, sessionId, scopeId) {
|
|
23
|
+
const safeSession = sanitizeScopeIdForFilename(sessionId);
|
|
24
|
+
const safeScope = sanitizeScopeIdForFilename(scopeId);
|
|
25
|
+
return join(verifyAcSessionCacheDir(projectRoot), `${safeSession}-${safeScope}.json`);
|
|
26
|
+
}
|
|
27
|
+
export function resolveVerifyAcSessionId(env, explicit) {
|
|
28
|
+
const injected = explicit?.trim() ?? "";
|
|
29
|
+
if (injected.length > 0)
|
|
30
|
+
return injected;
|
|
31
|
+
const fromEnv = typeof env?.DEFT_SESSION_ID === "string" ? env.DEFT_SESSION_ID.trim() : "";
|
|
32
|
+
return fromEnv.length > 0 ? fromEnv : null;
|
|
33
|
+
}
|
|
34
|
+
function parseSnapshot(raw) {
|
|
35
|
+
const rec = asRecord(raw);
|
|
36
|
+
if (rec === null)
|
|
37
|
+
return null;
|
|
38
|
+
if (typeof rec.ok !== "boolean")
|
|
39
|
+
return null;
|
|
40
|
+
if (rec.code !== 0 && rec.code !== 1 && rec.code !== 2)
|
|
41
|
+
return null;
|
|
42
|
+
if (typeof rec.message !== "string")
|
|
43
|
+
return null;
|
|
44
|
+
if (!Array.isArray(rec.commands) || !Array.isArray(rec.runs))
|
|
45
|
+
return null;
|
|
46
|
+
if (typeof rec.sourceRung !== "string")
|
|
47
|
+
return null;
|
|
48
|
+
if (typeof rec.noneStated !== "boolean")
|
|
49
|
+
return null;
|
|
50
|
+
if (typeof rec.resolution !== "string")
|
|
51
|
+
return null;
|
|
52
|
+
if (typeof rec.resolvedCommandCount !== "number")
|
|
53
|
+
return null;
|
|
54
|
+
return {
|
|
55
|
+
ok: rec.ok,
|
|
56
|
+
code: rec.code,
|
|
57
|
+
message: rec.message,
|
|
58
|
+
commands: rec.commands,
|
|
59
|
+
runs: rec.runs,
|
|
60
|
+
rejected: Array.isArray(rec.rejected) ? rec.rejected : undefined,
|
|
61
|
+
sourceRung: rec.sourceRung,
|
|
62
|
+
noneStated: rec.noneStated,
|
|
63
|
+
acceptance: rec.acceptance,
|
|
64
|
+
resolution: rec.resolution,
|
|
65
|
+
resolvedCommandCount: rec.resolvedCommandCount,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export function readVerifyAcSessionCache(projectRoot, sessionId, scopeId) {
|
|
69
|
+
const path = verifyAcSessionCachePath(projectRoot, sessionId, scopeId);
|
|
70
|
+
if (!existsSync(path))
|
|
71
|
+
return null;
|
|
72
|
+
let text;
|
|
73
|
+
try {
|
|
74
|
+
text = readFileSync(path, { encoding: "utf8" });
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const parsed = JSON.parse(text);
|
|
81
|
+
const rec = asRecord(parsed);
|
|
82
|
+
if (rec === null)
|
|
83
|
+
return null;
|
|
84
|
+
if (rec.sessionId !== sessionId || rec.scopeId !== scopeId)
|
|
85
|
+
return null;
|
|
86
|
+
if (typeof rec.productStateHash !== "string" || rec.productStateHash.length === 0) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const snapshot = parseSnapshot(rec.snapshot);
|
|
90
|
+
if (snapshot === null || snapshot.ok !== true)
|
|
91
|
+
return null;
|
|
92
|
+
return {
|
|
93
|
+
sessionId,
|
|
94
|
+
scopeId,
|
|
95
|
+
productStateHash: rec.productStateHash,
|
|
96
|
+
cachedAt: typeof rec.cachedAt === "string" ? rec.cachedAt : "",
|
|
97
|
+
snapshot,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export function writeVerifyAcSessionCache(input) {
|
|
105
|
+
const root = resolve(input.projectRoot);
|
|
106
|
+
const path = verifyAcSessionCachePath(root, input.sessionId, input.scopeId);
|
|
107
|
+
const dir = verifyAcSessionCacheDir(root);
|
|
108
|
+
if (!existsSync(dir))
|
|
109
|
+
mkdirSync(dir, { recursive: true });
|
|
110
|
+
const record = {
|
|
111
|
+
sessionId: input.sessionId,
|
|
112
|
+
scopeId: input.scopeId,
|
|
113
|
+
productStateHash: input.productStateHash,
|
|
114
|
+
cachedAt: input.now ?? new Date().toISOString().replace(/\.\d{3}Z$/, "Z"),
|
|
115
|
+
snapshot: input.snapshot,
|
|
116
|
+
};
|
|
117
|
+
containedWrite({
|
|
118
|
+
root,
|
|
119
|
+
target: path,
|
|
120
|
+
data: `${JSON.stringify(record, null, 2)}\n`,
|
|
121
|
+
mode: "replace",
|
|
122
|
+
mkdir: true,
|
|
123
|
+
});
|
|
124
|
+
return record;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=verify-ac-session-cache.js.map
|
|
@@ -28,6 +28,11 @@ export type RitualRunner = (command: readonly string[], projectRoot: string) =>
|
|
|
28
28
|
};
|
|
29
29
|
/** Human recovery line after a failed ritual probe (#2992 / #2993). */
|
|
30
30
|
export declare function formatRitualRecoveryInstruction(tier?: SessionCeremonyTier): string;
|
|
31
|
+
/**
|
|
32
|
+
* Sanctioned audited defer copy for gated `cache_fresh` failure (#3506 / #3507).
|
|
33
|
+
* The gated argv is always `["verify:cache-fresh"]`, so this is unconditional.
|
|
34
|
+
*/
|
|
35
|
+
export declare function formatCacheFreshDeferSoftPath(): string;
|
|
31
36
|
export interface VerifySessionRitualOptions {
|
|
32
37
|
readonly tier?: "quick" | "gated";
|
|
33
38
|
readonly now?: Date;
|
|
@@ -50,6 +50,14 @@ export function formatRitualRecoveryInstruction(tier = "cold") {
|
|
|
50
50
|
return (`Recovery: run ${ready} ` +
|
|
51
51
|
`(one-shot: session:start + gated ritual + cache recovery as needed).`);
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Sanctioned audited defer copy for gated `cache_fresh` failure (#3506 / #3507).
|
|
55
|
+
* The gated argv is always `["verify:cache-fresh"]`, so this is unconditional.
|
|
56
|
+
*/
|
|
57
|
+
export function formatCacheFreshDeferSoftPath() {
|
|
58
|
+
const cmd = formatFrameworkCommand(["session:start", "--", "--defer", "cache_fresh=<reason>"]);
|
|
59
|
+
return `Soft path (audited): \`${cmd}\`.`;
|
|
60
|
+
}
|
|
53
61
|
function runGatedStep(projectRoot, payload, stepName, runner, now) {
|
|
54
62
|
const command = [...GATED_ENTRYPOINT_COMMANDS[stepName]];
|
|
55
63
|
const { code, stdout, stderr } = runner(command, projectRoot);
|
|
@@ -465,6 +473,7 @@ export function emitVerifyJson(result) {
|
|
|
465
473
|
would_fail_code: result.wouldFailCode,
|
|
466
474
|
posture: result.posture,
|
|
467
475
|
ritual_state_required: result.ritualStateRequired,
|
|
476
|
+
recovery_tier: result.recoveryTier ?? null,
|
|
468
477
|
});
|
|
469
478
|
}
|
|
470
479
|
export function emitBypassWarning(result) {
|
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
*
|
|
11
11
|
* ⊗ Fake project `.openclaw/commands/` file emitter.
|
|
12
12
|
*/
|
|
13
|
-
import { existsSync, lstatSync, mkdirSync, readFileSync,
|
|
13
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, statSync } from "node:fs";
|
|
14
14
|
import { homedir } from "node:os";
|
|
15
15
|
import { join, resolve } from "node:path";
|
|
16
16
|
import { detectOpenClaw, isEscapingSkillSymlink, listInScopeSkillsDirs, } from "../doctor/openclaw-skills.js";
|
|
17
|
-
import { containedWrite } from "../fs/contained-write.js";
|
|
17
|
+
import { containedMkdir, containedRemove, containedRename, containedWrite, } from "../fs/contained-write.js";
|
|
18
|
+
import { isPortRecordMode } from "../fs/mutation-ledger.js";
|
|
18
19
|
import { readPlanPolicy } from "../policy/plan-extensions.js";
|
|
19
20
|
import { loadProjectDefinition } from "../policy/resolve.js";
|
|
20
21
|
import { generateOpenClawSkillArtifacts, isManagedOpenClawL2Skill, listOpenClawManagedSkillSlugs, } from "./openclaw-adapter.js";
|
|
@@ -122,7 +123,7 @@ function writeSkillArtifact(skillsDir, artifact) {
|
|
|
122
123
|
return "preserved";
|
|
123
124
|
}
|
|
124
125
|
}
|
|
125
|
-
|
|
126
|
+
containedMkdir({ root: skillsDir, target: skillDir });
|
|
126
127
|
// Re-check after mkdir: concurrent symlink plant is fail-closed.
|
|
127
128
|
if (skillDirLstatKind(skillDir) === "symlink" && isEscapingSkillSymlink(skillsDir, skillDir)) {
|
|
128
129
|
return "preserved";
|
|
@@ -137,11 +138,11 @@ function writeSkillArtifact(skillsDir, artifact) {
|
|
|
137
138
|
data: artifact.skillMarkdown,
|
|
138
139
|
mode: "replace",
|
|
139
140
|
});
|
|
140
|
-
|
|
141
|
+
containedRename({ root: skillsDir, from: tmp, to: skillFile, mutation: false });
|
|
141
142
|
}
|
|
142
143
|
catch (err) {
|
|
143
144
|
try {
|
|
144
|
-
|
|
145
|
+
containedRemove({ root: skillsDir, target: tmp, mutation: false });
|
|
145
146
|
}
|
|
146
147
|
catch {
|
|
147
148
|
/* best-effort */
|
|
@@ -172,8 +173,9 @@ function stripManagedSkills(skillsDir) {
|
|
|
172
173
|
if (!isManagedOpenClawL2Skill(raw))
|
|
173
174
|
continue;
|
|
174
175
|
try {
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
if (containedRemove({ root: skillsDir, target: skillDir, recursive: true }).removed) {
|
|
177
|
+
removed.push(skillDir);
|
|
178
|
+
}
|
|
177
179
|
}
|
|
178
180
|
catch {
|
|
179
181
|
/* best-effort */
|
|
@@ -221,7 +223,8 @@ export function depositOpenClawL2ProductCommands(options = {}) {
|
|
|
221
223
|
const preservedCustomPaths = [];
|
|
222
224
|
if (!policy) {
|
|
223
225
|
for (const skillsDir of skillsDirs) {
|
|
224
|
-
|
|
226
|
+
if (!isPortRecordMode())
|
|
227
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
225
228
|
removedPaths.push(...stripManagedSkills(skillsDir));
|
|
226
229
|
}
|
|
227
230
|
if (removedPaths.length > 0) {
|
|
@@ -242,7 +245,8 @@ export function depositOpenClawL2ProductCommands(options = {}) {
|
|
|
242
245
|
}
|
|
243
246
|
const artifacts = generateOpenClawSkillArtifacts();
|
|
244
247
|
for (const skillsDir of skillsDirs) {
|
|
245
|
-
|
|
248
|
+
if (!isPortRecordMode())
|
|
249
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
246
250
|
for (const artifact of artifacts) {
|
|
247
251
|
const outcome = writeSkillArtifact(skillsDir, artifact);
|
|
248
252
|
const abs = join(skillsDir, artifact.slug);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** Default slices log path relative to project root. */
|
|
2
|
-
export declare const DEFAULT_SLICES_LOG_REL_PATH = "
|
|
1
|
+
/** Default slices log path relative to an xbrief-layout project root (#1703). */
|
|
2
|
+
export declare const DEFAULT_SLICES_LOG_REL_PATH = "xbrief/.triage-cache/slices.jsonl";
|
|
3
3
|
export declare const ENV_PROJECT_ROOT = "DEFT_PROJECT_ROOT";
|
|
4
4
|
export declare const ENV_PROJECT_REPO = "DEFT_PROJECT_REPO";
|
|
5
5
|
export declare const DEFAULT_ACTOR = "manual:operator";
|
package/dist/slice/constants.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** Default slices log path relative to project root. */
|
|
2
|
-
export const DEFAULT_SLICES_LOG_REL_PATH = "
|
|
1
|
+
/** Default slices log path relative to an xbrief-layout project root (#1703). */
|
|
2
|
+
export const DEFAULT_SLICES_LOG_REL_PATH = "xbrief/.triage-cache/slices.jsonl";
|
|
3
3
|
export const ENV_PROJECT_ROOT = "DEFT_PROJECT_ROOT";
|
|
4
4
|
export const ENV_PROJECT_REPO = "DEFT_PROJECT_REPO";
|
|
5
5
|
export const DEFAULT_ACTOR = "manual:operator";
|
package/dist/slice/existing.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ContainedWriteError } from "../fs/contained-write.js";
|
|
2
2
|
import { call as scmCall } from "../scm/call.js";
|
|
3
3
|
import { pyRepr } from "../scm/py-format.js";
|
|
4
|
+
import { triageCacheRelPath } from "../triage/cache-path.js";
|
|
4
5
|
import { DEFAULT_ACTOR, DEFAULT_EXPECTED_CLOSE_SIGNAL, DEFAULT_ROLE, WAVE_FLAG_RE, } from "./constants.js";
|
|
5
6
|
import { IssueValidationError, SliceRecordError } from "./errors.js";
|
|
6
7
|
import { pythonJsonPretty } from "./json.js";
|
|
@@ -171,6 +172,10 @@ export function summariseWaves(waveMap, totalChildren) {
|
|
|
171
172
|
.map((waveN) => `wave-${waveN}=${placedByWave.get(waveN)}`);
|
|
172
173
|
return `${parts.length} wave(s): ${parts.join(", ")}`;
|
|
173
174
|
}
|
|
175
|
+
/** Layout-aware display path for the slices log actually read or written (#3386). */
|
|
176
|
+
function slicesLogDisplayPath(projectRoot) {
|
|
177
|
+
return triageCacheRelPath(projectRoot, "slices.jsonl");
|
|
178
|
+
}
|
|
174
179
|
function duplicateMessage(umbrella, duplicate) {
|
|
175
180
|
return (`slice:record-existing: umbrella #${umbrella} already has a matching record (slice_id=${String(duplicate.slice_id)}, ` +
|
|
176
181
|
`actor=${String(duplicate.actor)}). Re-run with --force to write a second record.`);
|
|
@@ -295,7 +300,7 @@ export function runRecordExisting(args, waveMap, deps = {}) {
|
|
|
295
300
|
const waveSummary = summariseWaves(waveMap, children.length);
|
|
296
301
|
return {
|
|
297
302
|
exitCode: 0,
|
|
298
|
-
stdout: `Wrote
|
|
303
|
+
stdout: `Wrote ${slicesLogDisplayPath(resolved.projectRoot)} entry for umbrella ` +
|
|
299
304
|
`#${args.umbrella} (${children.length} children, ${waveSummary}). ` +
|
|
300
305
|
`slice_id=${outcome.sliceId}\n`,
|
|
301
306
|
stderr: "",
|
|
@@ -320,6 +325,7 @@ export function runList(args) {
|
|
|
320
325
|
if (resolved.exitCode !== 0) {
|
|
321
326
|
return { exitCode: 2, stdout: "", stderr: `${formatMissingRootError()}\n` };
|
|
322
327
|
}
|
|
328
|
+
const logDisplay = slicesLogDisplayPath(resolved.projectRoot);
|
|
323
329
|
const records = readAll({ path: slicesPath(resolved.projectRoot) });
|
|
324
330
|
if (args.asJson) {
|
|
325
331
|
return { exitCode: 0, stdout: `${pythonJsonPretty(records)}\n`, stderr: "" };
|
|
@@ -327,11 +333,11 @@ export function runList(args) {
|
|
|
327
333
|
if (records.length === 0) {
|
|
328
334
|
return {
|
|
329
335
|
exitCode: 0,
|
|
330
|
-
stdout:
|
|
336
|
+
stdout: `slice:list: no records found in ${logDisplay} (file absent or empty).\n`,
|
|
331
337
|
stderr: "",
|
|
332
338
|
};
|
|
333
339
|
}
|
|
334
|
-
const lines = [`slice:list: ${records.length} record(s) in
|
|
340
|
+
const lines = [`slice:list: ${records.length} record(s) in ${logDisplay}`];
|
|
335
341
|
for (const record of records) {
|
|
336
342
|
const umbrella = record.umbrella ?? "?";
|
|
337
343
|
const actor = record.actor ?? "?";
|
package/dist/slice/lock.d.ts
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
|
+
/** 10× occupancy heartbeat TTL. Off-Linux PID reuse / stalled holder reclaim. */
|
|
2
|
+
export declare const STALE_LOCK_HARD_CAP_MS: number;
|
|
1
3
|
export interface LockDeps {
|
|
2
4
|
readonly sleepMs?: (ms: number) => void;
|
|
3
5
|
readonly now?: () => number;
|
|
4
6
|
}
|
|
7
|
+
export interface HeldLock {
|
|
8
|
+
readonly lockPath: string;
|
|
9
|
+
readonly pid: number;
|
|
10
|
+
readonly token: string;
|
|
11
|
+
readonly acquiredAt: number;
|
|
12
|
+
}
|
|
13
|
+
export interface LockRecord {
|
|
14
|
+
readonly pid: number | null;
|
|
15
|
+
readonly token: string;
|
|
16
|
+
readonly acquiredAt: number | null;
|
|
17
|
+
}
|
|
18
|
+
export declare function parseLockRecord(lockPath: string): LockRecord;
|
|
19
|
+
export declare function assertAppendLockOwned(held: HeldLock): void;
|
|
5
20
|
/** Serialise appenders across threads AND processes (sidecar lock file). */
|
|
6
|
-
export declare function withAppendLock<T>(logPath: string, fn: () => T, deps?: LockDeps): T;
|
|
21
|
+
export declare function withAppendLock<T>(logPath: string, fn: (held: HeldLock) => T, deps?: LockDeps): T;
|
|
7
22
|
/** Public alias mirroring Python append_lock. */
|
|
8
23
|
export declare const appendLock: typeof withAppendLock;
|
|
9
24
|
//# sourceMappingURL=lock.d.ts.map
|