@deftai/directive-core 0.88.0 → 0.89.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/doctor-state.js +28 -4
- package/dist/doctor/main.d.ts +10 -0
- package/dist/doctor/main.js +160 -0
- package/dist/doctor/types.d.ts +11 -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 +212 -163
- 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 +4 -0
- package/dist/index.js +5 -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 +29 -20
- package/dist/lifecycle/lifecycle-hygiene.js +9 -3
- 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-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/release-availability.js +26 -6
- package/dist/session/ritual-sentinel.js +19 -12
- package/dist/session/session-start.js +7 -0
- 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/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 +15 -3
package/dist/scope/audit-log.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
import { dirname,
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
4
5
|
import { resolveTriageCachePath } from "../triage/cache-path.js";
|
|
5
6
|
import { utcNowIso } from "./vbrief-json.js";
|
|
6
7
|
export class ScopeAuditLogError extends Error {
|
|
@@ -28,6 +29,12 @@ const DEMOTE_META_REQUIRED = [
|
|
|
28
29
|
"demoted_from",
|
|
29
30
|
];
|
|
30
31
|
let threadLock = false;
|
|
32
|
+
/** Ensure parent exists and return it as the containment root for log writes. */
|
|
33
|
+
function containmentRootForLog(logPath) {
|
|
34
|
+
const parent = dirname(logPath);
|
|
35
|
+
mkdirSync(parent, { recursive: true });
|
|
36
|
+
return resolve(parent);
|
|
37
|
+
}
|
|
31
38
|
function replacerSortKeys(_key, value) {
|
|
32
39
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
33
40
|
const sorted = {};
|
|
@@ -97,34 +104,16 @@ export function canonicalLogPath(projectRoot) {
|
|
|
97
104
|
// Layout-aware (#1703): triage working-set under `.triage-cache/`.
|
|
98
105
|
return resolveTriageCachePath(resolve(projectRoot), "scope-lifecycle.jsonl");
|
|
99
106
|
}
|
|
100
|
-
function withAppendLock(
|
|
101
|
-
const lockPath = `${logPath}.lock`;
|
|
102
|
-
mkdirSync(dirname(logPath), { recursive: true });
|
|
107
|
+
function withAppendLock(fn) {
|
|
103
108
|
while (threadLock) {
|
|
104
109
|
/* spin-wait for in-process serialization */
|
|
105
110
|
}
|
|
106
111
|
threadLock = true;
|
|
107
|
-
let fd = null;
|
|
108
112
|
try {
|
|
109
|
-
fd = openSync(lockPath, "a+");
|
|
110
|
-
if (readFileSync(lockPath).length === 0) {
|
|
111
|
-
writeSync(fd, "\0");
|
|
112
|
-
}
|
|
113
113
|
fn();
|
|
114
114
|
}
|
|
115
115
|
finally {
|
|
116
116
|
threadLock = false;
|
|
117
|
-
if (fd !== null) {
|
|
118
|
-
closeSync(fd);
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
if (existsSync(lockPath)) {
|
|
122
|
-
unlinkSync(lockPath);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch {
|
|
126
|
-
/* best-effort lock cleanup */
|
|
127
|
-
}
|
|
128
117
|
}
|
|
129
118
|
}
|
|
130
119
|
/** Validate and append an audit entry; returns decision_id. */
|
|
@@ -134,10 +123,16 @@ export function append(entry, logPath) {
|
|
|
134
123
|
}
|
|
135
124
|
validateEntry(entry);
|
|
136
125
|
const logFile = resolve(logPath);
|
|
137
|
-
|
|
126
|
+
const root = containmentRootForLog(logFile);
|
|
138
127
|
const line = JSON.stringify(entry, replacerSortKeys);
|
|
139
|
-
|
|
140
|
-
|
|
128
|
+
// #2980 wave B: product write sink routes through containedWrite.
|
|
129
|
+
withAppendLock(() => {
|
|
130
|
+
containedWrite({
|
|
131
|
+
root,
|
|
132
|
+
target: logFile,
|
|
133
|
+
data: `${line}\n`,
|
|
134
|
+
mode: "append",
|
|
135
|
+
});
|
|
141
136
|
});
|
|
142
137
|
return String(entry.decision_id);
|
|
143
138
|
}
|
package/dist/scope/decompose.js
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
* A caller supplies a draft with child story definitions; this module validates
|
|
7
7
|
* that draft, writes the child story vBRIEFs, and updates the parent scope references.
|
|
8
8
|
*/
|
|
9
|
-
import { accessSync, constants, existsSync, mkdirSync, readFileSync
|
|
9
|
+
import { accessSync, constants, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
10
10
|
import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
11
11
|
import { referenceTypeMatches } from "@deftai/directive-types";
|
|
12
|
-
import {
|
|
12
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
13
|
+
import { ProjectionContainmentError } from "../fs/projection-containment.js";
|
|
13
14
|
import { hasArtifactSuffix, LEGACY_ARTIFACT_DIR, MIGRATED_ARTIFACT_DIR, resolveLifecycleRoot, } from "../layout/resolve.js";
|
|
14
15
|
import { referenceWithDefaultTrust, slugify } from "../vbrief-build/build.js";
|
|
15
16
|
import { EMITTED_VBRIEF_VERSION } from "../vbrief-build/constants.js";
|
|
@@ -54,9 +55,13 @@ function loadJson(path) {
|
|
|
54
55
|
return data;
|
|
55
56
|
}
|
|
56
57
|
function writeJson(projectRoot, path, data) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
59
|
+
containedWrite({
|
|
60
|
+
root: resolve(projectRoot),
|
|
61
|
+
target: path,
|
|
62
|
+
data: formatBriefJson(data),
|
|
63
|
+
mode: "replace",
|
|
64
|
+
});
|
|
60
65
|
}
|
|
61
66
|
// ---------------------------------------------------------------------------
|
|
62
67
|
// Story quality helpers (ported from _vbrief_story_quality.py)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { existsSync, readFileSync
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { dirname, relative, resolve } from "node:path";
|
|
3
3
|
import { referenceTypeMatches } from "@deftai/directive-types";
|
|
4
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
4
5
|
import { formatBriefJson } from "./vbrief-json.js";
|
|
5
6
|
import { collectChildUris, collectPlanRefs, resolveVbriefRef } from "./vbrief-ref.js";
|
|
6
7
|
function rewriteOnePlanRef(value, oldParentResolved, newParentRel, vbriefDir) {
|
|
@@ -53,7 +54,14 @@ function rewriteParentChildReference(parentPath, oldChildResolved, newChildRel,
|
|
|
53
54
|
}
|
|
54
55
|
if (changed) {
|
|
55
56
|
try {
|
|
56
|
-
|
|
57
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
58
|
+
const dir = dirname(parentPath);
|
|
59
|
+
containedWrite({
|
|
60
|
+
root: resolve(dir),
|
|
61
|
+
target: parentPath,
|
|
62
|
+
data: formatBriefJson(parentData),
|
|
63
|
+
mode: "replace",
|
|
64
|
+
});
|
|
57
65
|
}
|
|
58
66
|
catch {
|
|
59
67
|
return false;
|
|
@@ -127,7 +135,14 @@ function rewriteChildParentReference(childPath, oldParentResolved, newParentRel,
|
|
|
127
135
|
}
|
|
128
136
|
if (changed) {
|
|
129
137
|
try {
|
|
130
|
-
|
|
138
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
139
|
+
const dir = dirname(childPath);
|
|
140
|
+
containedWrite({
|
|
141
|
+
root: resolve(dir),
|
|
142
|
+
target: childPath,
|
|
143
|
+
data: formatBriefJson(childData),
|
|
144
|
+
mode: "replace",
|
|
145
|
+
});
|
|
131
146
|
}
|
|
132
147
|
catch {
|
|
133
148
|
return false;
|
package/dist/scope/demote.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync } from "node:fs";
|
|
2
2
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
3
4
|
import { assertWriteTargetSafe, ProjectionContainmentError } from "../fs/projection-containment.js";
|
|
4
5
|
import { hasArtifactSuffix, resolveLifecycleFolder } from "../layout/resolve.js";
|
|
5
6
|
import { stripTrailingPathSeparators } from "../text/redos-safe.js";
|
|
@@ -85,7 +86,13 @@ export function demoteOne(filePath, projectRoot, reason, options = {}) {
|
|
|
85
86
|
const timestamp = utcNowIso(now);
|
|
86
87
|
planObj.status = TARGET_STATUS;
|
|
87
88
|
planObj.updated = timestamp;
|
|
88
|
-
|
|
89
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
90
|
+
containedWrite({
|
|
91
|
+
root: resolve(projectRoot),
|
|
92
|
+
target: resolved,
|
|
93
|
+
data: formatBriefJson(data),
|
|
94
|
+
mode: "replace",
|
|
95
|
+
});
|
|
89
96
|
const vbriefRoot = dirname(dirname(resolved));
|
|
90
97
|
const targetDir = join(vbriefRoot, TARGET_FOLDER);
|
|
91
98
|
mkdirSync(targetDir, { recursive: true });
|
package/dist/scope/undo.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, renameSync
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync } from "node:fs";
|
|
2
2
|
import { basename, join, relative, resolve } from "node:path";
|
|
3
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
3
4
|
import { assertWriteTargetSafe, ProjectionContainmentError } from "../fs/projection-containment.js";
|
|
4
5
|
import { resolveLifecycleRoot } from "../layout/resolve.js";
|
|
5
6
|
import { append, canonicalLogPath, newDecisionId, readAll } from "./audit-log.js";
|
|
@@ -185,7 +186,13 @@ function moveAndFlip(srcFile, destFolder, newStatus, timestamp, projectRoot) {
|
|
|
185
186
|
const planObj = plan;
|
|
186
187
|
planObj.status = newStatus;
|
|
187
188
|
planObj.updated = timestamp;
|
|
188
|
-
|
|
189
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
190
|
+
containedWrite({
|
|
191
|
+
root: resolve(projectRoot),
|
|
192
|
+
target: srcFile,
|
|
193
|
+
data: formatBriefJson(data),
|
|
194
|
+
mode: "replace",
|
|
195
|
+
});
|
|
189
196
|
mkdirSync(destFolder, { recursive: true });
|
|
190
197
|
const destPath = join(destFolder, basename(srcFile));
|
|
191
198
|
renameSync(srcFile, destPath);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, renameSync,
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync } from "node:fs";
|
|
3
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
4
4
|
import { locateManifest, parseInstallManifest } from "../doctor/manifest.js";
|
|
5
5
|
import { runningInsideDeftRepo } from "../doctor/paths.js";
|
|
6
6
|
import { evaluateReleaseAvailability } from "../doctor/release-availability.js";
|
|
7
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
7
8
|
import { resolveTriageCachePath } from "../triage/cache-path.js";
|
|
8
9
|
const THROTTLE_MS = 24 * 60 * 60 * 1000;
|
|
9
10
|
const PUBLIC_NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
@@ -56,10 +57,29 @@ function isThrottled(state, latestVersion, now) {
|
|
|
56
57
|
return Number.isFinite(notifiedAt) && now.getTime() - notifiedAt < THROTTLE_MS;
|
|
57
58
|
}
|
|
58
59
|
function defaultWriteState(path, content) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
const dir = dirname(path);
|
|
61
|
+
mkdirSync(dir, { recursive: true });
|
|
62
|
+
const tmpBase = `${basename(path)}.${process.pid}.tmp`;
|
|
63
|
+
const temporary = join(dir, tmpBase);
|
|
64
|
+
try {
|
|
65
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
66
|
+
containedWrite({
|
|
67
|
+
root: resolve(dir),
|
|
68
|
+
target: tmpBase,
|
|
69
|
+
data: content,
|
|
70
|
+
mode: "create",
|
|
71
|
+
});
|
|
72
|
+
renameSync(temporary, path);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
try {
|
|
76
|
+
rmSync(temporary, { force: true });
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
/* best-effort cleanup */
|
|
80
|
+
}
|
|
81
|
+
throw err;
|
|
82
|
+
}
|
|
63
83
|
}
|
|
64
84
|
/**
|
|
65
85
|
* Probe the public npm registry separately from doctor. Doctor stays offline
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, } from "node:fs";
|
|
2
2
|
import { join, relative, resolve } from "node:path";
|
|
3
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
3
4
|
import { hasArtifactSuffix, LEGACY_ARTIFACT_DIR, MIGRATED_ARTIFACT_DIR, } from "../layout/resolve.js";
|
|
4
5
|
import { stableJson } from "./json.js";
|
|
5
6
|
import { RITUAL_STATE_CONTRACT } from "./posture.js";
|
|
@@ -92,24 +93,30 @@ function validateSteps(raw, key) {
|
|
|
92
93
|
return [steps, null];
|
|
93
94
|
}
|
|
94
95
|
function atomicWriteJson(targetPath, payload, prefix) {
|
|
95
|
-
mkdirSync(join(targetPath, ".."), { recursive: true });
|
|
96
96
|
const dir = join(targetPath, "..");
|
|
97
|
-
|
|
98
|
-
const
|
|
97
|
+
mkdirSync(dir, { recursive: true });
|
|
98
|
+
const tmpBase = `${prefix}${process.pid}.json.tmp`;
|
|
99
|
+
const tmpName = join(dir, tmpBase);
|
|
100
|
+
const text = `${stableJson(payload, 2)}\n`;
|
|
99
101
|
try {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
// #2980 wave D: ritual-state product write routes through containedWrite.
|
|
103
|
+
containedWrite({
|
|
104
|
+
root: resolve(dir),
|
|
105
|
+
target: tmpBase,
|
|
106
|
+
data: text,
|
|
107
|
+
mode: "create",
|
|
108
|
+
});
|
|
109
|
+
renameSync(tmpName, targetPath);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
102
112
|
try {
|
|
103
|
-
|
|
113
|
+
rmSync(tmpName, { force: true });
|
|
104
114
|
}
|
|
105
115
|
catch {
|
|
106
|
-
|
|
116
|
+
/* best-effort cleanup */
|
|
107
117
|
}
|
|
118
|
+
throw err;
|
|
108
119
|
}
|
|
109
|
-
finally {
|
|
110
|
-
closeSync(fd);
|
|
111
|
-
}
|
|
112
|
-
renameSync(tmpName, targetPath);
|
|
113
120
|
}
|
|
114
121
|
export function readRitualState(projectRoot) {
|
|
115
122
|
const stateFile = ritualStatePath(projectRoot);
|
|
@@ -5,6 +5,7 @@ import { MIGRATE_COMPLETION_NUDGE, shouldEmitMigrateNudge } from "../init-deposi
|
|
|
5
5
|
import { detectEnvironmentContext, environmentContextToDict, formatEnvironmentContext, } from "../platform/shell-context.js";
|
|
6
6
|
import { disclosureLine } from "../policy/disclosure.js";
|
|
7
7
|
import { detectNoDeftDirective, NO_DEFT_DIRECTIVE_DISABLED_MESSAGE, NO_DEFT_DIRECTIVE_FLAG_NAME, NO_DEFT_DIRECTIVE_INCONSISTENT_MESSAGE, NO_DEFT_DIRECTIVE_INCONSISTENT_POLICY, } from "../policy/no-deft-directive.js";
|
|
8
|
+
import { humanMergeDisclosureLine, resolveHumanMergePolicy, } from "../policy/require-human-merge.js";
|
|
8
9
|
import { resolvePolicy } from "../policy/resolve.js";
|
|
9
10
|
import { maybeFormatProductSignalConsentPrompt } from "../product-signal/consent-prompt.js";
|
|
10
11
|
import { maybeRunStalenessTickler } from "../staleness-tickler/run.js";
|
|
@@ -319,6 +320,12 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
319
320
|
exitCode: ok ? 0 : 2,
|
|
320
321
|
});
|
|
321
322
|
lines.push(message);
|
|
323
|
+
// Human merge gate disclosure (#1193) — surface when ON (or env bypass active).
|
|
324
|
+
const humanMerge = resolveHumanMergePolicy(projectRoot);
|
|
325
|
+
const humanMergeLine = humanMergeDisclosureLine(humanMerge);
|
|
326
|
+
if (humanMergeLine !== null) {
|
|
327
|
+
lines.push(humanMergeLine);
|
|
328
|
+
}
|
|
322
329
|
const branchSync = defaultBranchSync(projectRoot, runGit);
|
|
323
330
|
if (branchSync.warning) {
|
|
324
331
|
lines.push(branchSync.warning);
|
|
@@ -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) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync
|
|
2
|
-
import { dirname, relative } from "node:path";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, relative, resolve } from "node:path";
|
|
3
|
+
import { containedWrite } from "../../fs/contained-write.js";
|
|
3
4
|
import { assertProjectionContained, ProjectionContainmentError, } from "../../fs/projection-containment.js";
|
|
4
5
|
import { MIGRATED_ARTIFACT_DIR, resolveLifecycleLayout } from "../../layout/resolve.js";
|
|
5
6
|
import { resolveCandidatesLogPath, resolveTriageCachePath, TRIAGE_CACHE_DIR_NAME, triageCacheRelPath, } from "../cache-path.js";
|
|
@@ -197,7 +198,14 @@ function ensureGitignoreLine(projectRoot, gitignorePath, line, stepName, createI
|
|
|
197
198
|
return stepOutcome(stepName, false, `.gitignore not present after the prior gitignore step; ${line} not written -- re-run bootstrap to retry`, { created: false, appended: false, skipped: "no-gitignore" }, "prior gitignore step did not create .gitignore");
|
|
198
199
|
}
|
|
199
200
|
try {
|
|
200
|
-
|
|
201
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
202
|
+
const root = resolve(projectRoot);
|
|
203
|
+
containedWrite({
|
|
204
|
+
root,
|
|
205
|
+
target: gitignorePath,
|
|
206
|
+
data: `${line}\n`,
|
|
207
|
+
mode: "create",
|
|
208
|
+
});
|
|
201
209
|
}
|
|
202
210
|
catch (exc) {
|
|
203
211
|
return stepOutcome(stepName, false, "could not create .gitignore", {}, String(exc));
|
|
@@ -232,7 +240,13 @@ function ensureGitignoreLine(projectRoot, gitignorePath, line, stepName, createI
|
|
|
232
240
|
const suffix = existing.endsWith("\n") || existing === "" ? "" : "\n";
|
|
233
241
|
const newContent = `${existing + suffix + rationaleBlock + line}\n`;
|
|
234
242
|
try {
|
|
235
|
-
|
|
243
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
244
|
+
containedWrite({
|
|
245
|
+
root: resolve(projectRoot),
|
|
246
|
+
target: gitignorePath,
|
|
247
|
+
data: newContent,
|
|
248
|
+
mode: "replace",
|
|
249
|
+
});
|
|
236
250
|
}
|
|
237
251
|
catch (exc) {
|
|
238
252
|
return stepOutcome(stepName, false, "could not write .gitignore", {}, String(exc));
|
|
@@ -303,7 +317,13 @@ function ensureGitignoreSelectiveEntries(projectRoot, stepName, entries) {
|
|
|
303
317
|
: `${EVAL_ENTRIES_RATIONALE}${missing.join("\n")}\n`;
|
|
304
318
|
const newContent = existing + suffix + appendedBlock;
|
|
305
319
|
try {
|
|
306
|
-
|
|
320
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
321
|
+
containedWrite({
|
|
322
|
+
root: resolve(projectRoot),
|
|
323
|
+
target: gitignorePath,
|
|
324
|
+
data: newContent,
|
|
325
|
+
mode: "replace",
|
|
326
|
+
});
|
|
307
327
|
}
|
|
308
328
|
catch (exc) {
|
|
309
329
|
return stepOutcome(stepName, false, "could not write .gitignore", { gitignore_appended_lines: 0 }, String(exc));
|
|
@@ -341,7 +361,13 @@ function ensureGitattributesMergeUnion(projectRoot, stepName, glob, ruleLine) {
|
|
|
341
361
|
const suffix = existing.endsWith("\n") || existing === "" ? "" : "\n";
|
|
342
362
|
const newContent = `${existing + suffix + GITATTRIBUTES_EVAL_RATIONALE + ruleLine}\n`;
|
|
343
363
|
try {
|
|
344
|
-
|
|
364
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
365
|
+
containedWrite({
|
|
366
|
+
root: resolve(projectRoot),
|
|
367
|
+
target: gitattributesPath,
|
|
368
|
+
data: newContent,
|
|
369
|
+
mode: "replace",
|
|
370
|
+
});
|
|
345
371
|
}
|
|
346
372
|
catch (exc) {
|
|
347
373
|
return stepOutcome(stepName, false, "could not write .gitattributes", { gitattributes_appended: false }, String(exc));
|
|
@@ -353,7 +379,13 @@ function ensureGitattributesMergeUnion(projectRoot, stepName, glob, ruleLine) {
|
|
|
353
379
|
}
|
|
354
380
|
const newContent = `${GITATTRIBUTES_EVAL_RATIONALE + ruleLine}\n`;
|
|
355
381
|
try {
|
|
356
|
-
|
|
382
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
383
|
+
containedWrite({
|
|
384
|
+
root: resolve(projectRoot),
|
|
385
|
+
target: gitattributesPath,
|
|
386
|
+
data: newContent,
|
|
387
|
+
mode: "create",
|
|
388
|
+
});
|
|
357
389
|
}
|
|
358
390
|
catch (exc) {
|
|
359
391
|
return stepOutcome(stepName, false, "could not create .gitattributes", { gitattributes_appended: false }, String(exc));
|
|
@@ -382,8 +414,13 @@ function ensureEvalReadme(options) {
|
|
|
382
414
|
// create below
|
|
383
415
|
}
|
|
384
416
|
try {
|
|
385
|
-
|
|
386
|
-
|
|
417
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
418
|
+
containedWrite({
|
|
419
|
+
root: resolve(projectRoot),
|
|
420
|
+
target: readmePath,
|
|
421
|
+
data: generateTriageCacheReadmeBody(projectRoot),
|
|
422
|
+
mode: "create",
|
|
423
|
+
});
|
|
387
424
|
}
|
|
388
425
|
catch (exc) {
|
|
389
426
|
return stepOutcome(stepName, false, `could not create ${readmePath}`, { readme_created: false }, String(exc));
|
|
@@ -474,7 +511,13 @@ export function stepSeedCandidatesLog(projectRoot) {
|
|
|
474
511
|
// create below
|
|
475
512
|
}
|
|
476
513
|
try {
|
|
477
|
-
|
|
514
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
515
|
+
containedWrite({
|
|
516
|
+
root: resolve(projectRoot),
|
|
517
|
+
target: auditPath,
|
|
518
|
+
data: "",
|
|
519
|
+
mode: "create",
|
|
520
|
+
});
|
|
478
521
|
}
|
|
479
522
|
catch (exc) {
|
|
480
523
|
return stepOutcome("seed_candidates_log", false, `could not seed ${auditPath}`, {}, String(exc));
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Triage append-only logs and scratch dirs live under `.triage-cache/` so the
|
|
5
5
|
* `.eval/` namespace can be reclaimed for version-eval results (#1703 Tier 2).
|
|
6
6
|
*/
|
|
7
|
-
import { existsSync, mkdirSync, renameSync, unlinkSync
|
|
8
|
-
import { join, relative } from "node:path";
|
|
7
|
+
import { existsSync, mkdirSync, renameSync, unlinkSync } from "node:fs";
|
|
8
|
+
import { join, relative, resolve } from "node:path";
|
|
9
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
9
10
|
import { assertProjectionContained } from "../fs/projection-containment.js";
|
|
10
11
|
import { MIGRATED_ARTIFACT_DIR, resolveEvalDir, resolveLifecycleLayout, resolveLifecycleRoot, } from "../layout/resolve.js";
|
|
11
12
|
import { generateTriageCacheReadmeBody } from "./bootstrap/gitignore.js";
|
|
@@ -99,7 +100,13 @@ export function migrateLegacyTriageCacheFromEval(projectRoot) {
|
|
|
99
100
|
removedLegacyFiles.push(name);
|
|
100
101
|
}
|
|
101
102
|
else {
|
|
102
|
-
|
|
103
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
104
|
+
containedWrite({
|
|
105
|
+
root: resolve(projectRoot),
|
|
106
|
+
target: targetPath,
|
|
107
|
+
data: generateTriageCacheReadmeBody(projectRoot),
|
|
108
|
+
mode: "create",
|
|
109
|
+
});
|
|
103
110
|
unlinkSync(legacyPath);
|
|
104
111
|
regeneratedFiles.push(name);
|
|
105
112
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
3
|
+
import { containedWrite } from "../../fs/contained-write.js";
|
|
3
4
|
import { hasArtifactSuffix, resolveLifecycleFolder, resolveProjectDefinitionPath, } from "../../layout/resolve.js";
|
|
4
5
|
import { readPlanPolicy } from "../../policy/plan-extensions.js";
|
|
5
6
|
import { countVbriefWip, resolveWipCap } from "../../policy/wip.js";
|
|
@@ -296,8 +297,14 @@ export function appendHistory(historyPath, result, line) {
|
|
|
296
297
|
reconcilable: result.reconcilable,
|
|
297
298
|
};
|
|
298
299
|
try {
|
|
299
|
-
|
|
300
|
-
|
|
300
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
301
|
+
const dir = dirname(historyPath);
|
|
302
|
+
containedWrite({
|
|
303
|
+
root: resolve(dir),
|
|
304
|
+
target: basename(historyPath),
|
|
305
|
+
data: `${JSON.stringify(record)}\n`,
|
|
306
|
+
mode: "append",
|
|
307
|
+
});
|
|
301
308
|
}
|
|
302
309
|
catch {
|
|
303
310
|
// observability only
|