@deftai/directive-core 0.88.0 → 0.90.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/actions.d.ts +55 -0
- package/dist/authz/actions.js +125 -0
- package/dist/authz/classify.d.ts +23 -0
- package/dist/authz/classify.js +217 -0
- package/dist/authz/closed-verb.d.ts +42 -0
- package/dist/authz/closed-verb.js +279 -0
- package/dist/authz/evaluate.d.ts +41 -0
- package/dist/authz/evaluate.js +298 -0
- package/dist/authz/index.d.ts +15 -0
- package/dist/authz/index.js +15 -0
- package/dist/authz/origin.d.ts +28 -0
- package/dist/authz/origin.js +64 -0
- package/dist/authz/paths.d.ts +6 -0
- package/dist/authz/paths.js +19 -0
- package/dist/authz/store.d.ts +40 -0
- package/dist/authz/store.js +317 -0
- package/dist/authz/templates.d.ts +139 -0
- package/dist/authz/templates.js +241 -0
- package/dist/authz/types.d.ts +111 -0
- package/dist/authz/types.js +41 -0
- package/dist/authz/verb-classification.d.ts +44 -0
- package/dist/authz/verb-classification.js +237 -0
- package/dist/branch/evaluate.js +6 -1
- package/dist/cache/fetch.js +10 -5
- package/dist/cache/io.d.ts +9 -2
- package/dist/cache/io.js +30 -10
- package/dist/cache/task-cache/store.js +11 -7
- package/dist/capacity/backfill.js +10 -4
- package/dist/category-b-namespace/index.js +10 -4
- package/dist/codebase/default-extractor.js +3 -0
- package/dist/codebase/map.js +11 -4
- package/dist/doctor/constants.d.ts +1 -1
- package/dist/doctor/constants.js +2 -0
- package/dist/doctor/doctor-state.js +28 -4
- package/dist/doctor/flags.js +21 -1
- package/dist/doctor/index.d.ts +1 -0
- package/dist/doctor/index.js +1 -0
- package/dist/doctor/main.d.ts +10 -0
- package/dist/doctor/main.js +182 -0
- package/dist/doctor/openclaw-skills.d.ts +109 -0
- package/dist/doctor/openclaw-skills.js +463 -0
- package/dist/doctor/types.d.ts +22 -0
- package/dist/escalation/actions.d.ts +63 -0
- package/dist/escalation/actions.js +137 -0
- package/dist/escalation/index.d.ts +8 -0
- package/dist/escalation/index.js +8 -0
- package/dist/escalation/paths.d.ts +3 -0
- package/dist/escalation/paths.js +10 -0
- package/dist/escalation/store.d.ts +17 -0
- package/dist/escalation/store.js +172 -0
- package/dist/escalation/types.d.ts +73 -0
- package/dist/escalation/types.js +43 -0
- package/dist/eval/crud-telemetry.js +30 -10
- package/dist/eval/health.js +22 -7
- package/dist/eval/readback.js +11 -10
- package/dist/eval/run.js +32 -16
- package/dist/events/attribution-enrichment.js +10 -4
- package/dist/finish-loop/directive-finish-loop.d.ts +37 -0
- package/dist/finish-loop/directive-finish-loop.js +239 -0
- package/dist/finish-loop/grant-gate.d.ts +31 -0
- package/dist/finish-loop/grant-gate.js +169 -0
- package/dist/finish-loop/index.d.ts +11 -0
- package/dist/finish-loop/index.js +11 -0
- package/dist/finish-loop/main.d.ts +35 -0
- package/dist/finish-loop/main.js +365 -0
- package/dist/finish-loop/pr-finish-loop.d.ts +34 -0
- package/dist/finish-loop/pr-finish-loop.js +217 -0
- package/dist/finish-loop/progress.d.ts +17 -0
- package/dist/finish-loop/progress.js +45 -0
- package/dist/finish-loop/queue.d.ts +16 -0
- package/dist/finish-loop/queue.js +65 -0
- package/dist/finish-loop/types.d.ts +52 -0
- package/dist/finish-loop/types.js +10 -0
- package/dist/fs/contained-write.d.ts +101 -0
- package/dist/fs/contained-write.js +281 -0
- package/dist/hooks/classify/classify.d.ts +10 -0
- package/dist/hooks/classify/classify.js +37 -0
- package/dist/hooks/classify/index.d.ts +14 -0
- package/dist/hooks/classify/index.js +13 -0
- package/dist/hooks/classify/paths.d.ts +22 -0
- package/dist/hooks/classify/paths.js +72 -0
- package/dist/hooks/classify/payload.d.ts +16 -0
- package/dist/hooks/classify/payload.js +45 -0
- package/dist/hooks/classify/stdin.d.ts +12 -0
- package/dist/hooks/classify/stdin.js +63 -0
- package/dist/hooks/classify/tool-name.d.ts +18 -0
- package/dist/hooks/classify/tool-name.js +85 -0
- package/dist/hooks/classify/types.d.ts +41 -0
- package/dist/hooks/classify/types.js +7 -0
- package/dist/hooks/dispatcher.d.ts +21 -18
- package/dist/hooks/dispatcher.js +232 -168
- package/dist/hooks/fixtures/cases.d.ts +44 -0
- package/dist/hooks/fixtures/cases.js +595 -0
- package/dist/hooks/fixtures/index.d.ts +2 -0
- package/dist/hooks/fixtures/index.js +2 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +2 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/init-deposit/agent-hooks.js +27 -8
- package/dist/init-deposit/gitignore.js +11 -3
- package/dist/init-deposit/headless-manifest.js +12 -4
- package/dist/init-deposit/migrate.d.ts +1 -1
- package/dist/init-deposit/migrate.js +13 -3
- package/dist/init-deposit/prettierignore.js +10 -3
- package/dist/init-deposit/scaffold.js +35 -26
- package/dist/init-deposit/xbrief-projections.js +11 -4
- package/dist/intake/candidates-log.js +46 -35
- package/dist/intake/github-body-cli.d.ts +6 -0
- package/dist/intake/github-body-cli.js +17 -0
- package/dist/intake/github-body.d.ts +46 -3
- package/dist/intake/github-body.js +191 -20
- package/dist/intake/issue-emit.d.ts +1 -0
- package/dist/intake/issue-emit.js +41 -23
- package/dist/lifecycle/event-detect.js +12 -4
- package/dist/lifecycle/events.js +31 -20
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- package/dist/lifecycle/lifecycle-hygiene.js +9 -3
- package/dist/lifecycle/stats.d.ts +53 -0
- package/dist/lifecycle/stats.js +286 -0
- package/dist/packs/pack-render.js +19 -6
- package/dist/plan-sequence/store.js +11 -4
- package/dist/policy/hotfix-criteria.d.ts +79 -0
- package/dist/policy/hotfix-criteria.js +197 -0
- package/dist/policy/index.d.ts +4 -0
- package/dist/policy/index.js +31 -1
- package/dist/policy/intent-ceiling.d.ts +79 -0
- package/dist/policy/intent-ceiling.js +181 -0
- package/dist/policy/no-deft-directive.js +10 -3
- package/dist/policy/org-force-on-migration.js +9 -5
- package/dist/policy/require-human-merge.d.ts +75 -0
- package/dist/policy/require-human-merge.js +324 -0
- package/dist/policy/resolve.js +17 -6
- package/dist/policy/runtime-authority.d.ts +15 -2
- package/dist/policy/runtime-authority.js +23 -3
- package/dist/policy/write-fence.d.ts +78 -0
- package/dist/policy/write-fence.js +164 -0
- package/dist/pr-wait-mergeable/cascade.d.ts +10 -0
- package/dist/pr-wait-mergeable/cascade.js +28 -0
- package/dist/preflight/evaluate.js +10 -0
- package/dist/product-signal/consent.js +21 -5
- package/dist/product-signal/submit.js +22 -12
- package/dist/release/build-dist-runner.js +5 -2
- package/dist/release/build-dist.d.ts +19 -1
- package/dist/release/build-dist.js +50 -2
- package/dist/release/native-steps.js +7 -2
- package/dist/release/spawn.js +13 -0
- package/dist/release-e2e/git-ops.d.ts +7 -0
- package/dist/release-e2e/git-ops.js +35 -2
- package/dist/release-publish/pipeline.d.ts +13 -0
- package/dist/release-publish/pipeline.js +46 -1
- package/dist/scope/audit-log.js +19 -24
- package/dist/scope/decompose.js +10 -5
- package/dist/scope/decomposed-refs.js +18 -3
- package/dist/scope/demote.js +9 -2
- package/dist/scope/undo.js +9 -2
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.js +2 -0
- package/dist/session/process-cost-constants.d.ts +9 -0
- package/dist/session/process-cost-constants.js +11 -0
- package/dist/session/process-cost.d.ts +53 -0
- package/dist/session/process-cost.js +82 -0
- package/dist/session/release-availability.js +26 -6
- package/dist/session/ritual-sentinel.d.ts +5 -0
- package/dist/session/ritual-sentinel.js +31 -13
- package/dist/session/session-ready.d.ts +67 -0
- package/dist/session/session-ready.js +264 -0
- package/dist/session/session-start.d.ts +56 -1
- package/dist/session/session-start.js +384 -23
- package/dist/session/verify-session-ritual.d.ts +8 -0
- package/dist/session/verify-session-ritual.js +95 -35
- package/dist/staleness-tickler/state.js +26 -6
- package/dist/swarm/launch.js +13 -3
- package/dist/swarm/routing.js +9 -3
- package/dist/task-surface/index.js +24 -9
- package/dist/tool-events/classify.d.ts +20 -0
- package/dist/tool-events/classify.js +634 -0
- package/dist/tool-events/index.d.ts +10 -0
- package/dist/tool-events/index.js +10 -0
- package/dist/tool-events/summarize.d.ts +34 -0
- package/dist/tool-events/summarize.js +93 -0
- package/dist/tool-events/types.d.ts +52 -0
- package/dist/tool-events/types.js +13 -0
- package/dist/triage/bootstrap/gitignore.js +53 -10
- package/dist/triage/cache-path.js +10 -3
- package/dist/triage/welcome/summary.js +11 -4
- package/dist/triage/welcome/writers.js +45 -16
- package/dist/validate-content/validate-links.js +5 -0
- package/dist/value/readback.js +11 -6
- package/dist/vbrief-activate/activate.js +12 -4
- package/dist/vbrief-build/project-definition-io.js +14 -6
- package/dist/verify-source/contained-writes.d.ts +59 -0
- package/dist/verify-source/contained-writes.js +272 -0
- package/dist/verify-source/index.d.ts +1 -0
- package/dist/verify-source/index.js +1 -0
- package/dist/verify-source/openclaw-tier1.js +14 -1
- package/dist/verify-source/verify-stubs.js +3 -0
- package/dist/xbrief-migrate/migrate-project.js +26 -12
- package/dist/xbrief-migrate/transforms.d.ts +4 -2
- package/dist/xbrief-migrate/transforms.js +37 -14
- package/package.json +19 -3
|
@@ -4,8 +4,8 @@ import { defaultGitRunner, gitHead, gitIsAncestor, worktreePath } from "./git.js
|
|
|
4
4
|
import { pythonJsonDump } from "./json.js";
|
|
5
5
|
import { ENV_SESSION_POSTURE, readOnlyPostureMessage, resolveSessionPosture, ritualStateIsPostureAuthority, } from "./posture.js";
|
|
6
6
|
import { defaultRitualRunner } from "./ritual-entrypoint.js";
|
|
7
|
-
import { readRitualState, ritualStatePath, ritualStep, writeRitualState, } from "./ritual-sentinel.js";
|
|
8
|
-
import { GATED_STEPS, QUICK_STEPS } from "./session-start.js";
|
|
7
|
+
import { readRitualState, ritualStateMarksRearmNeeded, ritualStatePath, ritualStep, writeRitualState, } from "./ritual-sentinel.js";
|
|
8
|
+
import { formatSessionStartRecoveryCommand, GATED_STEPS, QUICK_STEPS, } from "./session-start.js";
|
|
9
9
|
import { resolveSessionRitualStalenessHours } from "./staleness.js";
|
|
10
10
|
export { formatCacheFetchAllRecoveryCommand, recoveryHintForStaleFailure, } from "./cache-recovery.js";
|
|
11
11
|
export const ENV_SKIP = "DEFT_SESSION_RITUAL_SKIP";
|
|
@@ -25,9 +25,10 @@ function stepPasses(step) {
|
|
|
25
25
|
return step.ok === true;
|
|
26
26
|
}
|
|
27
27
|
function failedStepMessage(tierName, stepName, step) {
|
|
28
|
+
const coldCmd = formatSessionStartRecoveryCommand("cold");
|
|
28
29
|
if (step === null || step === undefined) {
|
|
29
30
|
return (`session ritual ${tierName} step '${stepName}' is missing. ` +
|
|
30
|
-
`Run \`${
|
|
31
|
+
`Run \`${coldCmd}\` before implementation dispatch.`);
|
|
31
32
|
}
|
|
32
33
|
if (typeof step === "object" &&
|
|
33
34
|
step !== null &&
|
|
@@ -38,6 +39,19 @@ function failedStepMessage(tierName, stepName, step) {
|
|
|
38
39
|
const suffix = typeof message === "string" && message.length > 0 ? `: ${message}` : "";
|
|
39
40
|
return `session ritual ${tierName} step '${stepName}' failed${suffix}`;
|
|
40
41
|
}
|
|
42
|
+
/** Human recovery line after a failed ritual probe (#2992 / #2993). */
|
|
43
|
+
export function formatRitualRecoveryInstruction(tier = "cold") {
|
|
44
|
+
const ready = formatFrameworkCommand(["session:ready"]);
|
|
45
|
+
const start = formatSessionStartRecoveryCommand(tier);
|
|
46
|
+
const verify = formatFrameworkCommand(["verify:session-ritual", "--", "--tier=gated"]);
|
|
47
|
+
if (tier === "rearm") {
|
|
48
|
+
return (`Recovery: run ${ready} (one-shot), or ${start} ` +
|
|
49
|
+
`(or full ${formatSessionStartRecoveryCommand("cold")} if worktree/HEAD changed), ` +
|
|
50
|
+
`then ${verify}.`);
|
|
51
|
+
}
|
|
52
|
+
return (`Recovery: run ${ready} ` +
|
|
53
|
+
`(one-shot: session:start + gated ritual + cache recovery as needed).`);
|
|
54
|
+
}
|
|
41
55
|
function runGatedStep(projectRoot, payload, stepName, runner, now) {
|
|
42
56
|
const command = [...(GATED_ENTRYPOINT_COMMANDS[stepName] ?? [])];
|
|
43
57
|
const { code, stdout, stderr } = runner(command, projectRoot);
|
|
@@ -60,29 +74,42 @@ function runGatedStep(projectRoot, payload, stepName, runner, now) {
|
|
|
60
74
|
return null;
|
|
61
75
|
}
|
|
62
76
|
function headDriftRecoveryMessage() {
|
|
77
|
+
const coldCmd = formatSessionStartRecoveryCommand("cold");
|
|
63
78
|
return (`session ritual state is stale because git HEAD changed discontinuously. ` +
|
|
64
|
-
`Run \`${
|
|
79
|
+
`Run \`${coldCmd}\` again (full cold ceremony required).`);
|
|
65
80
|
}
|
|
66
81
|
function evaluateLoadedState(projectRoot, state, input) {
|
|
67
82
|
const runGit = input.runGit ?? defaultGitRunner;
|
|
83
|
+
const coldCmd = formatSessionStartRecoveryCommand("cold");
|
|
84
|
+
const rearmCmd = formatSessionStartRecoveryCommand("rearm");
|
|
68
85
|
const { head: currentHead, error: headError } = gitHead(projectRoot, runGit);
|
|
69
86
|
if (currentHead === null) {
|
|
70
|
-
return
|
|
87
|
+
return {
|
|
88
|
+
code: 2,
|
|
89
|
+
message: headError ?? "could not resolve git HEAD",
|
|
90
|
+
recoveryTier: "cold",
|
|
91
|
+
};
|
|
71
92
|
}
|
|
72
93
|
const currentWorktree = worktreePath(projectRoot, runGit);
|
|
73
94
|
if (state.worktreePath !== currentWorktree) {
|
|
74
|
-
return
|
|
75
|
-
1,
|
|
76
|
-
`session ritual state belongs to a different worktree (${state.worktreePath});
|
|
77
|
-
|
|
95
|
+
return {
|
|
96
|
+
code: 1,
|
|
97
|
+
message: `session ritual state belongs to a different worktree (${state.worktreePath}); ` +
|
|
98
|
+
`run \`${coldCmd}\` here (full cold ceremony required).`,
|
|
99
|
+
recoveryTier: "cold",
|
|
100
|
+
};
|
|
78
101
|
}
|
|
79
102
|
if (state.gitHead !== currentHead) {
|
|
80
103
|
const forward = gitIsAncestor(projectRoot, state.gitHead, currentHead, runGit);
|
|
81
104
|
if (forward === null) {
|
|
82
|
-
return
|
|
105
|
+
return {
|
|
106
|
+
code: 2,
|
|
107
|
+
message: "could not verify git history for session ritual",
|
|
108
|
+
recoveryTier: "cold",
|
|
109
|
+
};
|
|
83
110
|
}
|
|
84
111
|
if (!forward) {
|
|
85
|
-
return
|
|
112
|
+
return { code: 1, message: headDriftRecoveryMessage(), recoveryTier: "cold" };
|
|
86
113
|
}
|
|
87
114
|
if (input.rebindForwardHead) {
|
|
88
115
|
const payload = { ...state.raw, git_head: currentHead };
|
|
@@ -90,37 +117,63 @@ function evaluateLoadedState(projectRoot, state, input) {
|
|
|
90
117
|
writeRitualState(projectRoot, payload);
|
|
91
118
|
}
|
|
92
119
|
catch (exc) {
|
|
93
|
-
return
|
|
120
|
+
return {
|
|
121
|
+
code: 2,
|
|
122
|
+
message: `could not rebind session ritual git HEAD: ${String(exc)}`,
|
|
123
|
+
recoveryTier: "cold",
|
|
124
|
+
};
|
|
94
125
|
}
|
|
95
126
|
}
|
|
96
127
|
}
|
|
97
128
|
const staleness = resolveSessionRitualStalenessHours(projectRoot);
|
|
98
129
|
if (staleness.source === "default-on-error") {
|
|
99
|
-
return
|
|
130
|
+
return {
|
|
131
|
+
code: 2,
|
|
132
|
+
message: staleness.error ?? "session ritual staleness policy is invalid",
|
|
133
|
+
recoveryTier: "cold",
|
|
134
|
+
};
|
|
100
135
|
}
|
|
101
136
|
const maxAgeMs = staleness.hours * 60 * 60 * 1000;
|
|
102
137
|
if (input.now.getTime() - state.startedAt.getTime() > maxAgeMs) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
138
|
+
// Age / compact stale on same worktree + continuous HEAD → prefer re-arm (#2992).
|
|
139
|
+
// compact_resume_at / rearm_needed amplify the same recovery path.
|
|
140
|
+
const compactNote = ritualStateMarksRearmNeeded(state)
|
|
141
|
+
? " Compact/resume marked re-arm needed."
|
|
142
|
+
: "";
|
|
143
|
+
return {
|
|
144
|
+
code: 1,
|
|
145
|
+
message: `session ritual state is stale (older than ${staleness.hours}h).${compactNote} ` +
|
|
146
|
+
`Run \`${rearmCmd}\` to re-arm (or \`${coldCmd}\` for a full cold ceremony).`,
|
|
147
|
+
recoveryTier: "rearm",
|
|
148
|
+
};
|
|
108
149
|
}
|
|
109
150
|
for (const stepName of QUICK_STEPS) {
|
|
110
151
|
const step = state.quickSteps[stepName];
|
|
111
152
|
if (!stepPasses(step)) {
|
|
112
|
-
return
|
|
153
|
+
return {
|
|
154
|
+
code: 1,
|
|
155
|
+
message: failedStepMessage("quick", stepName, step),
|
|
156
|
+
recoveryTier: "cold",
|
|
157
|
+
};
|
|
113
158
|
}
|
|
114
159
|
}
|
|
115
160
|
if (input.tier === "gated") {
|
|
116
161
|
for (const stepName of GATED_STEPS) {
|
|
117
162
|
const step = state.gatedSteps[stepName];
|
|
118
163
|
if (!stepPasses(step)) {
|
|
119
|
-
return
|
|
164
|
+
return {
|
|
165
|
+
code: 1,
|
|
166
|
+
message: failedStepMessage("gated", stepName, step),
|
|
167
|
+
recoveryTier: "cold",
|
|
168
|
+
};
|
|
120
169
|
}
|
|
121
170
|
}
|
|
122
171
|
}
|
|
123
|
-
return
|
|
172
|
+
return {
|
|
173
|
+
code: 0,
|
|
174
|
+
message: `OK session ritual ${input.tier} tier is fresh.`,
|
|
175
|
+
recoveryTier: null,
|
|
176
|
+
};
|
|
124
177
|
}
|
|
125
178
|
/**
|
|
126
179
|
* Read-only ritual-state inspection for host hooks.
|
|
@@ -155,7 +208,7 @@ export function inspectSessionRitual(projectRoot, options = {}) {
|
|
|
155
208
|
const [state, err] = readRitualState(projectRoot);
|
|
156
209
|
if (state === null) {
|
|
157
210
|
const code = missingStateFile ? 1 : 2;
|
|
158
|
-
const startCommand =
|
|
211
|
+
const startCommand = formatSessionStartRecoveryCommand("cold");
|
|
159
212
|
return {
|
|
160
213
|
code,
|
|
161
214
|
message: code === 1
|
|
@@ -167,23 +220,25 @@ export function inspectSessionRitual(projectRoot, options = {}) {
|
|
|
167
220
|
wouldFailCode: null,
|
|
168
221
|
posture,
|
|
169
222
|
ritualStateRequired,
|
|
223
|
+
recoveryTier: "cold",
|
|
170
224
|
};
|
|
171
225
|
}
|
|
172
|
-
const
|
|
226
|
+
const evaluated = evaluateLoadedState(projectRoot, state, {
|
|
173
227
|
tier,
|
|
174
228
|
now: options.now ?? new Date(),
|
|
175
229
|
runGit: options.runGit,
|
|
176
230
|
rebindForwardHead: false,
|
|
177
231
|
});
|
|
178
232
|
return {
|
|
179
|
-
code,
|
|
180
|
-
message,
|
|
233
|
+
code: evaluated.code,
|
|
234
|
+
message: evaluated.message,
|
|
181
235
|
tier,
|
|
182
236
|
statePath,
|
|
183
237
|
bypassed: false,
|
|
184
238
|
wouldFailCode: null,
|
|
185
239
|
posture,
|
|
186
240
|
ritualStateRequired,
|
|
241
|
+
recoveryTier: evaluated.recoveryTier,
|
|
187
242
|
};
|
|
188
243
|
}
|
|
189
244
|
export function verifySessionRitual(projectRoot, options = {}) {
|
|
@@ -231,7 +286,7 @@ export function verifySessionRitual(projectRoot, options = {}) {
|
|
|
231
286
|
let [state, err] = readRitualState(projectRoot);
|
|
232
287
|
if (state === null) {
|
|
233
288
|
const code = missingStateFile ? 1 : 2;
|
|
234
|
-
const startCommand =
|
|
289
|
+
const startCommand = formatSessionStartRecoveryCommand("cold");
|
|
235
290
|
const message = code === 1
|
|
236
291
|
? `${err}. Run \`${startCommand}\` before implementation dispatch.`
|
|
237
292
|
: (err ?? "ritual state invalid");
|
|
@@ -245,6 +300,7 @@ export function verifySessionRitual(projectRoot, options = {}) {
|
|
|
245
300
|
wouldFailCode: code,
|
|
246
301
|
posture,
|
|
247
302
|
ritualStateRequired,
|
|
303
|
+
recoveryTier: "cold",
|
|
248
304
|
};
|
|
249
305
|
}
|
|
250
306
|
return {
|
|
@@ -256,25 +312,27 @@ export function verifySessionRitual(projectRoot, options = {}) {
|
|
|
256
312
|
wouldFailCode: null,
|
|
257
313
|
posture,
|
|
258
314
|
ritualStateRequired,
|
|
315
|
+
recoveryTier: "cold",
|
|
259
316
|
};
|
|
260
317
|
}
|
|
261
318
|
if (tier === "gated" && !isBypassed) {
|
|
262
|
-
const
|
|
319
|
+
const precheck = evaluateLoadedState(projectRoot, state, {
|
|
263
320
|
tier: "quick",
|
|
264
321
|
now: instant,
|
|
265
322
|
runGit: options.runGit,
|
|
266
323
|
rebindForwardHead: true,
|
|
267
324
|
});
|
|
268
|
-
if (
|
|
325
|
+
if (precheck.code !== 0) {
|
|
269
326
|
return {
|
|
270
|
-
code:
|
|
271
|
-
message:
|
|
327
|
+
code: precheck.code,
|
|
328
|
+
message: precheck.message,
|
|
272
329
|
tier,
|
|
273
330
|
statePath,
|
|
274
331
|
bypassed: false,
|
|
275
332
|
wouldFailCode: null,
|
|
276
333
|
posture,
|
|
277
334
|
ritualStateRequired,
|
|
335
|
+
recoveryTier: precheck.recoveryTier,
|
|
278
336
|
};
|
|
279
337
|
}
|
|
280
338
|
const reloadedAfterPrecheck = readRitualState(projectRoot);
|
|
@@ -332,7 +390,7 @@ export function verifySessionRitual(projectRoot, options = {}) {
|
|
|
332
390
|
};
|
|
333
391
|
}
|
|
334
392
|
}
|
|
335
|
-
const
|
|
393
|
+
const evaluated = evaluateLoadedState(projectRoot, state, {
|
|
336
394
|
tier,
|
|
337
395
|
now: instant,
|
|
338
396
|
runGit: options.runGit,
|
|
@@ -341,24 +399,26 @@ export function verifySessionRitual(projectRoot, options = {}) {
|
|
|
341
399
|
if (isBypassed) {
|
|
342
400
|
return {
|
|
343
401
|
code: 0,
|
|
344
|
-
message,
|
|
402
|
+
message: evaluated.message,
|
|
345
403
|
tier,
|
|
346
404
|
statePath,
|
|
347
405
|
bypassed: true,
|
|
348
|
-
wouldFailCode: code === 0 ? null : code,
|
|
406
|
+
wouldFailCode: evaluated.code === 0 ? null : evaluated.code,
|
|
349
407
|
posture,
|
|
350
408
|
ritualStateRequired,
|
|
409
|
+
recoveryTier: evaluated.recoveryTier,
|
|
351
410
|
};
|
|
352
411
|
}
|
|
353
412
|
return {
|
|
354
|
-
code,
|
|
355
|
-
message,
|
|
413
|
+
code: evaluated.code,
|
|
414
|
+
message: evaluated.message,
|
|
356
415
|
tier,
|
|
357
416
|
statePath,
|
|
358
417
|
bypassed: false,
|
|
359
418
|
wouldFailCode: null,
|
|
360
419
|
posture,
|
|
361
420
|
ritualStateRequired,
|
|
421
|
+
recoveryTier: evaluated.recoveryTier,
|
|
362
422
|
};
|
|
363
423
|
}
|
|
364
424
|
export function emitVerifyJson(result) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { mkdirSync, readFileSync, renameSync,
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
1
|
+
import { mkdirSync, readFileSync, renameSync, rmSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
3
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
3
4
|
import { resolveTriageCachePath } from "../triage/cache-path.js";
|
|
4
5
|
export const STATE_RELATIVE_PATH = join("xbrief", ".triage-cache", "staleness-tickler-state.json");
|
|
5
6
|
const STATE_FILE_NAME = "staleness-tickler-state.json";
|
|
@@ -15,10 +16,29 @@ function defaultReadText(path) {
|
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
function defaultWriteText(path, content) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const dir = dirname(path);
|
|
20
|
+
mkdirSync(dir, { recursive: true });
|
|
21
|
+
const tmpBase = `${basename(path)}.${process.pid}.tmp`;
|
|
22
|
+
const temporary = join(dir, tmpBase);
|
|
23
|
+
try {
|
|
24
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
25
|
+
containedWrite({
|
|
26
|
+
root: resolve(dir),
|
|
27
|
+
target: tmpBase,
|
|
28
|
+
data: content,
|
|
29
|
+
mode: "create",
|
|
30
|
+
});
|
|
31
|
+
renameSync(temporary, path);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
try {
|
|
35
|
+
rmSync(temporary, { force: true });
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
/* best-effort cleanup */
|
|
39
|
+
}
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
22
42
|
}
|
|
23
43
|
export function parseStalenessTicklerState(text) {
|
|
24
44
|
if (text === null) {
|
package/dist/swarm/launch.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync
|
|
2
|
-
import { basename, isAbsolute, join, resolve } from "node:path";
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
3
4
|
import { inferGithubAuthMode } from "../intake/github-auth-modes.js";
|
|
4
5
|
import { getPlatformCapabilities } from "../intake/platform-capabilities.js";
|
|
5
6
|
import { hasArtifactSuffix, resolveLifecycleFolder, stripArtifactSuffix, } from "../layout/resolve.js";
|
|
@@ -581,7 +582,16 @@ export function swarmLaunch(args) {
|
|
|
581
582
|
const rendered = `${JSON.stringify(manifest, null, 2)}\n`;
|
|
582
583
|
if (args.output !== undefined && args.output !== null) {
|
|
583
584
|
try {
|
|
584
|
-
|
|
585
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
586
|
+
const abs = resolve(args.output);
|
|
587
|
+
const dir = dirname(abs);
|
|
588
|
+
mkdirSync(dir, { recursive: true });
|
|
589
|
+
containedWrite({
|
|
590
|
+
root: dir,
|
|
591
|
+
target: basename(abs),
|
|
592
|
+
data: rendered,
|
|
593
|
+
mode: "replace",
|
|
594
|
+
});
|
|
585
595
|
}
|
|
586
596
|
catch (exc) {
|
|
587
597
|
return {
|
package/dist/swarm/routing.js
CHANGED
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
* explicit default.
|
|
15
15
|
*/
|
|
16
16
|
import { execFileSync } from "node:child_process";
|
|
17
|
-
import { existsSync,
|
|
17
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
18
18
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
19
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
19
20
|
import { assertWriteTargetSafe } from "../fs/projection-containment.js";
|
|
20
21
|
/**
|
|
21
22
|
* The fixed worker-role vocabulary (reused from #1531). No separate tier
|
|
@@ -234,7 +235,12 @@ export function writeModelDecision(projectRoot, path, provider, role, decision)
|
|
|
234
235
|
decidedAt: decision.decidedAt ?? new Date().toISOString(),
|
|
235
236
|
};
|
|
236
237
|
file[provider] = block;
|
|
237
|
-
|
|
238
|
-
|
|
238
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
239
|
+
containedWrite({
|
|
240
|
+
root: resolve(projectRoot),
|
|
241
|
+
target: path,
|
|
242
|
+
data: `${JSON.stringify(file, null, 2)}\n`,
|
|
243
|
+
mode: "replace",
|
|
244
|
+
});
|
|
239
245
|
}
|
|
240
246
|
//# sourceMappingURL=routing.js.map
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, statSync
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, statSync } from "node:fs";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { LEGACY_VBRIEF_VERSION } from "@deftai/directive-types";
|
|
5
|
-
import {
|
|
5
|
+
import { ContainedWriteError, containedWrite } from "../fs/contained-write.js";
|
|
6
|
+
import { assertProjectionContained, ProjectionContainmentError, } from "../fs/projection-containment.js";
|
|
6
7
|
const UNRELEASED_RE = /## \[Unreleased\][ \t]*\n([\s\S]*?)(?=\n## \[|$)/;
|
|
7
8
|
const CHANGE_NAME_RE = /^[\w][\w-]*$/;
|
|
8
9
|
const COMMIT_TYPES = "feat|fix|docs|chore|refactor|test|style|perf|ci|build|revert";
|
|
@@ -14,7 +15,7 @@ function projectionTarget(projectDir, ...relSegments) {
|
|
|
14
15
|
return target;
|
|
15
16
|
}
|
|
16
17
|
function containmentExitCode(io, err) {
|
|
17
|
-
if (err instanceof ProjectionContainmentError) {
|
|
18
|
+
if (err instanceof ProjectionContainmentError || err instanceof ContainedWriteError) {
|
|
18
19
|
io.writeErr(`FAIL: ${err.message}\n`);
|
|
19
20
|
return 2;
|
|
20
21
|
}
|
|
@@ -93,10 +94,19 @@ export function runChangeInit(projectRoot, name, io) {
|
|
|
93
94
|
mkdirSync(specsDir, { recursive: true });
|
|
94
95
|
const proposalPath = join(base, "proposal.xbrief.json");
|
|
95
96
|
const tasksPath = join(base, "tasks.xbrief.json");
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
// #2980 wave D: product write sinks route through containedWrite.
|
|
98
|
+
containedWrite({
|
|
99
|
+
root: projectAbs,
|
|
100
|
+
target: proposalPath,
|
|
101
|
+
data: `${JSON.stringify(proposalTemplate(trimmed), null, 2)}\n`,
|
|
102
|
+
mode: "create",
|
|
103
|
+
});
|
|
104
|
+
containedWrite({
|
|
105
|
+
root: projectAbs,
|
|
106
|
+
target: tasksPath,
|
|
107
|
+
data: `${JSON.stringify(tasksTemplate(trimmed), null, 2)}\n`,
|
|
108
|
+
mode: "create",
|
|
109
|
+
});
|
|
100
110
|
io.writeOut(`OK: Created change proposal at ${base}/\n`);
|
|
101
111
|
for (const file of ["proposal.xbrief.json", "tasks.xbrief.json", "specs/"]) {
|
|
102
112
|
io.writeOut(` - ${file}\n`);
|
|
@@ -150,8 +160,13 @@ export function runInstallUninstall(projectRoot, io) {
|
|
|
150
160
|
const next = filtered.join("");
|
|
151
161
|
if (next !== original) {
|
|
152
162
|
try {
|
|
153
|
-
|
|
154
|
-
|
|
163
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
164
|
+
containedWrite({
|
|
165
|
+
root: resolve(projectRoot),
|
|
166
|
+
target: path,
|
|
167
|
+
data: next,
|
|
168
|
+
mode: "replace",
|
|
169
|
+
});
|
|
155
170
|
io.writeOut("Removed deft entry from AGENTS.md\n");
|
|
156
171
|
}
|
|
157
172
|
catch (err) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic, rule-first tool-event classifier (#2967).
|
|
3
|
+
*
|
|
4
|
+
* Pure: no I/O, no LLM. Misclassification policy: prefer `unknown` over a
|
|
5
|
+
* wrong `verify` (false-positive verify is worse than residual unknown).
|
|
6
|
+
*
|
|
7
|
+
* Distinct from packages/core/src/hooks/classify/ (#2950 write-intent/payload).
|
|
8
|
+
*/
|
|
9
|
+
import type { ClassifyToolEventResult, ToolEventInput } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Classify one tool event into explore | commit | verify | coordinate | unknown.
|
|
12
|
+
*
|
|
13
|
+
* Pure and deterministic. When verify cannot be proven honestly, returns unknown.
|
|
14
|
+
*/
|
|
15
|
+
export declare function classifyToolEvent(event: ToolEventInput): ClassifyToolEventResult;
|
|
16
|
+
/** Classify many events; order preserved. */
|
|
17
|
+
export declare function classifyToolEvents(events: readonly ToolEventInput[]): ClassifyToolEventResult[];
|
|
18
|
+
/** Exported for unit tests of the shell path without wrapping Shell tool names. */
|
|
19
|
+
export declare function classifyShellCommandForTest(command: string): ClassifyToolEventResult;
|
|
20
|
+
//# sourceMappingURL=classify.d.ts.map
|