@sabaiway/agent-workflow-kit 5.10.0 → 5.11.1
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/CHANGELOG.md +152 -0
- package/README.md +2 -2
- package/SKILL.md +1 -1
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/hooks/gate-approve.mjs +13 -2
- package/references/hooks/state-block-guard.mjs +14 -2
- package/references/modes/commit-guard.md +11 -8
- package/references/modes/core-evidence.md +1 -1
- package/references/modes/dispatch.md +32 -10
- package/references/modes/worktrees.md +47 -3
- package/references/scripts/archive-changelog.mjs +14 -3
- package/references/scripts/archive-decisions.mjs +14 -3
- package/references/scripts/archive-issues.mjs +14 -3
- package/references/scripts/check-docs-size.mjs +14 -3
- package/references/scripts/migrate-gates.mjs +13 -2
- package/tools/ack-write.mjs +3 -3
- package/tools/advisor-matrix.mjs +165 -0
- package/tools/autonomy-doctor.mjs +2 -3
- package/tools/bridge-settings.mjs +2 -3
- package/tools/cheap-agents.mjs +3 -3
- package/tools/commands.mjs +4 -5
- package/tools/commit-guard.mjs +77 -20
- package/tools/core-evidence.mjs +12 -3
- package/tools/coverage-check.mjs +2 -3
- package/tools/delegation.mjs +2 -3
- package/tools/detect-backends.mjs +2 -3
- package/tools/dispatch-advisor.mjs +323 -0
- package/tools/dispatch.mjs +174 -109
- package/tools/doc-parity.mjs +69 -16
- package/tools/family-registry.mjs +3 -3
- package/tools/flow-adoption-mint.mjs +70 -0
- package/tools/flow-append.mjs +309 -0
- package/tools/flow-chain-state.mjs +91 -0
- package/tools/flow-check-cores.mjs +35 -6
- package/tools/flow-check-rungs.mjs +20 -2
- package/tools/flow-check.mjs +22 -8
- package/tools/flow-delta-proof.mjs +307 -0
- package/tools/flow-record.mjs +1 -1
- package/tools/flow-store-read.mjs +3 -3
- package/tools/flow-store.mjs +35 -812
- package/tools/flow-subset-budget.mjs +81 -0
- package/tools/flow-writer.mjs +3 -3
- package/tools/gate-hook.mjs +3 -3
- package/tools/gates-init.mjs +3 -3
- package/tools/grounding.mjs +2 -3
- package/tools/hide-footprint.mjs +2 -3
- package/tools/inject-methodology.mjs +2 -3
- package/tools/lens-region.mjs +2 -3
- package/tools/manifest/validate.mjs +2 -3
- package/tools/migrate-adr-store.mjs +3 -3
- package/tools/observation-builder.mjs +123 -0
- package/tools/path-inventory.mjs +2 -3
- package/tools/procedures.mjs +3 -3
- package/tools/receipt-deadline.mjs +2 -3
- package/tools/recipes.mjs +2 -3
- package/tools/recommendations.mjs +3 -3
- package/tools/release-scan.mjs +2 -3
- package/tools/repo-search.mjs +2 -3
- package/tools/review-state.mjs +3 -3
- package/tools/run-gates.mjs +2 -3
- package/tools/sandbox-masks.mjs +3 -3
- package/tools/satellite-locator.mjs +179 -0
- package/tools/set-autonomy.mjs +2 -3
- package/tools/set-flow.mjs +3 -3
- package/tools/set-recipe.mjs +2 -3
- package/tools/setup-backends.mjs +3 -3
- package/tools/store-append.mjs +2 -2
- package/tools/uninstall.mjs +2 -3
- package/tools/velocity-profile.mjs +3 -3
- package/tools/worktree-handoff-return.mjs +369 -0
- package/tools/worktree-prompt.mjs +190 -0
- package/tools/worktrees-record.mjs +171 -0
- package/tools/worktrees.mjs +311 -300
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// satellite-locator.mjs — slug → satellite worktree, and the proof that the handoff found there IS
|
|
2
|
+
// that satellite's identity (delegation Plan 3, Phase 2).
|
|
3
|
+
//
|
|
4
|
+
// Extracted out of worktrees.mjs so BOTH modes can ask the question: `worktrees prompt` composes a
|
|
5
|
+
// satellite's cold-start prompt today, and the dispatch-side handoff-return rung — a later phase,
|
|
6
|
+
// not yet wired — will read what came back through this same leaf. That rung is a `dispatch` verb,
|
|
7
|
+
// so this leaf is what will keep the 3200-line worktrees tool out of the dispatch CLI's closure.
|
|
8
|
+
//
|
|
9
|
+
// READ-ONLY by construction: it writes nothing, spawns nothing, and — deliberately — CONTENT-READS
|
|
10
|
+
// nothing of its own. The git runner and the fs seams are INJECTED, so a caller decides what may
|
|
11
|
+
// run, and the content read arrives as `fs.readFileNoFollow(abs)` returning the family's structured
|
|
12
|
+
// outcome { bytes } | { absent } | { unsafe } | { error: code }. That is not fastidiousness: the ONE
|
|
13
|
+
// no-follow read door lives in worktrees.mjs, its single body is pinned there by a tripwire, and a
|
|
14
|
+
// second body here would be exactly the duplication that pin exists to prevent. `fs` is the shape
|
|
15
|
+
// worktrees.mjs builds: { lstat, readdir, realpath, readFileNoFollow }.
|
|
16
|
+
//
|
|
17
|
+
// Node built-ins plus two pure leaves. No side effects on import; no CLI. Dependency-free, Node >= 22.
|
|
18
|
+
|
|
19
|
+
import { join } from 'node:path';
|
|
20
|
+
import { PLANS_REL } from './plan-files.mjs';
|
|
21
|
+
import { stop, handoffBasename, parseProvisionRecord, displayValue } from './worktrees-record.mjs';
|
|
22
|
+
|
|
23
|
+
// Every refusal below is the worktrees STOP, unchanged — a caller that reached this leaf directly
|
|
24
|
+
// (the dispatch side does) must be able to recognize it without importing worktrees.mjs.
|
|
25
|
+
export { WORKTREES_STOP } from './worktrees-record.mjs';
|
|
26
|
+
|
|
27
|
+
export const DEFAULT_BRANCH_PREFIX = 'aw/';
|
|
28
|
+
|
|
29
|
+
export const parseWorktreeList = (text) => {
|
|
30
|
+
const entries = [];
|
|
31
|
+
let fields = [];
|
|
32
|
+
const finishEntry = () => {
|
|
33
|
+
if (fields.length === 0) return;
|
|
34
|
+
const entry = { path: null, head: null, branch: null, detached: false, prunable: false, bare: false };
|
|
35
|
+
for (const field of fields) {
|
|
36
|
+
if (field.startsWith('worktree ')) entry.path = field.slice('worktree '.length);
|
|
37
|
+
else if (field.startsWith('HEAD ')) entry.head = field.slice('HEAD '.length);
|
|
38
|
+
else if (field.startsWith('branch ')) entry.branch = field.slice('branch '.length);
|
|
39
|
+
else if (field === 'detached') entry.detached = true;
|
|
40
|
+
else if (field === 'bare') entry.bare = true;
|
|
41
|
+
else if (field === 'prunable' || field.startsWith('prunable ')) entry.prunable = true;
|
|
42
|
+
}
|
|
43
|
+
if (entry.path !== null) entries.push(entry);
|
|
44
|
+
fields = [];
|
|
45
|
+
};
|
|
46
|
+
for (const field of String(text).split('\0')) {
|
|
47
|
+
if (field === '') finishEntry();
|
|
48
|
+
else fields.push(field);
|
|
49
|
+
}
|
|
50
|
+
finishEntry();
|
|
51
|
+
return entries;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const listWorktrees = (git, cwd) => {
|
|
55
|
+
const r = git(['worktree', 'list', '--porcelain', '-z'], cwd);
|
|
56
|
+
if (r.status !== 0) throw stop(`git worktree list failed: ${r.stderr.trim() || r.stdout.trim()}`);
|
|
57
|
+
return parseWorktreeList(r.stdout);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const classifyNodeNoFollow = (path, fs) => {
|
|
61
|
+
const node = (() => {
|
|
62
|
+
try {
|
|
63
|
+
return { stat: fs.lstat(path) };
|
|
64
|
+
} catch (error) {
|
|
65
|
+
return error?.code === 'ENOENT'
|
|
66
|
+
? { stat: null }
|
|
67
|
+
: { error: error?.code ?? 'fs error' };
|
|
68
|
+
}
|
|
69
|
+
})();
|
|
70
|
+
if (node.error) return { kind: 'error', error: node.error };
|
|
71
|
+
if (node.stat === null) return { kind: 'absent' };
|
|
72
|
+
if (!node.stat.isSymbolicLink()) {
|
|
73
|
+
if (node.stat.isDirectory()) return { kind: 'plain-directory', stat: node.stat };
|
|
74
|
+
if (node.stat.isFile()) return { kind: 'regular-file', stat: node.stat };
|
|
75
|
+
return { kind: 'special', stat: node.stat };
|
|
76
|
+
}
|
|
77
|
+
const realPath = (() => {
|
|
78
|
+
try {
|
|
79
|
+
return { path: fs.realpath(path) };
|
|
80
|
+
} catch (error) {
|
|
81
|
+
return { error: error?.code ?? 'fs error' };
|
|
82
|
+
}
|
|
83
|
+
})();
|
|
84
|
+
if (realPath.error) return { kind: 'symlink-unresolvable', error: realPath.error };
|
|
85
|
+
const target = (() => {
|
|
86
|
+
try {
|
|
87
|
+
return { stat: fs.lstat(realPath.path) };
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return { error: error?.code ?? 'fs error' };
|
|
90
|
+
}
|
|
91
|
+
})();
|
|
92
|
+
if (target.error) return { kind: 'symlink-unresolvable', error: target.error };
|
|
93
|
+
if (target.stat.isDirectory()) return { kind: 'symlink-to-directory', realPath: realPath.path, stat: node.stat };
|
|
94
|
+
if (target.stat.isFile()) return { kind: 'symlink-to-file', realPath: realPath.path, stat: node.stat };
|
|
95
|
+
return { kind: 'symlink-to-special', realPath: realPath.path, stat: node.stat };
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Whole-chain no-follow: the worktree root, docs, and docs/plans must be plain directories;
|
|
99
|
+
// handoff candidates count ONLY as regular files. states: ok | absent | unreadable.
|
|
100
|
+
// ANY stat failure (not just readdir) renders honestly — list must never crash on a bad node.
|
|
101
|
+
export const scanPlansDir = ({ wtRoot, fs }) => {
|
|
102
|
+
if (classifyNodeNoFollow(wtRoot, fs).kind !== 'plain-directory') return { state: 'unreadable' };
|
|
103
|
+
const docs = classifyNodeNoFollow(join(wtRoot, 'docs'), fs);
|
|
104
|
+
if (docs.kind === 'absent') return { state: 'absent' };
|
|
105
|
+
if (docs.kind !== 'plain-directory') return { state: 'unreadable' };
|
|
106
|
+
const plans = classifyNodeNoFollow(join(wtRoot, PLANS_REL), fs);
|
|
107
|
+
if (plans.kind === 'absent') return { state: 'absent' };
|
|
108
|
+
if (plans.kind !== 'plain-directory') return { state: 'unreadable' };
|
|
109
|
+
let names;
|
|
110
|
+
try {
|
|
111
|
+
names = fs.readdir(join(wtRoot, PLANS_REL));
|
|
112
|
+
} catch {
|
|
113
|
+
return { state: 'unreadable' };
|
|
114
|
+
}
|
|
115
|
+
const handoffs = [];
|
|
116
|
+
const nonRegular = [];
|
|
117
|
+
for (const n of names) {
|
|
118
|
+
if (!/^handoff-.+\.md$/.test(n)) continue;
|
|
119
|
+
const cand = classifyNodeNoFollow(join(wtRoot, PLANS_REL, n), fs);
|
|
120
|
+
if (cand.kind !== 'regular-file') nonRegular.push(n);
|
|
121
|
+
else handoffs.push(n);
|
|
122
|
+
}
|
|
123
|
+
return { state: 'ok', handoffs, nonRegular };
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const branchNameOf = (entry) => entry.branch?.replace(/^refs\/heads\//, '') ?? null;
|
|
127
|
+
|
|
128
|
+
export const findSatelliteEntry = ({ root, slug, branch, git, fs }) => {
|
|
129
|
+
const entries = listWorktrees(git, root).slice(1);
|
|
130
|
+
const exactHandoff = [];
|
|
131
|
+
for (const entry of entries) {
|
|
132
|
+
if (entry.prunable) continue;
|
|
133
|
+
const scan = scanPlansDir({ wtRoot: entry.path, fs });
|
|
134
|
+
if (scan.state === 'ok' && scan.handoffs.includes(handoffBasename(slug))) exactHandoff.push(entry);
|
|
135
|
+
}
|
|
136
|
+
if (exactHandoff.length > 1) {
|
|
137
|
+
throw stop(`multiple worktrees carry ${handoffBasename(slug)} — cleanup the duplicate identity before continuing`);
|
|
138
|
+
}
|
|
139
|
+
if (branch !== null) {
|
|
140
|
+
const byBranch = entries.filter((entry) => entry.branch === `refs/heads/${branch}`);
|
|
141
|
+
if (byBranch.length > 1) throw stop(`multiple worktrees claim branch ${branch}`);
|
|
142
|
+
if (byBranch.length === 1) return byBranch[0];
|
|
143
|
+
}
|
|
144
|
+
if (exactHandoff.length === 1) return exactHandoff[0];
|
|
145
|
+
const fallback = entries.filter((entry) => entry.branch === `refs/heads/${DEFAULT_BRANCH_PREFIX}${slug}`);
|
|
146
|
+
if (fallback.length === 1) return fallback[0];
|
|
147
|
+
throw stop(`no registered satellite worktree for ${slug}`);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export const readSatelliteIdentity = ({ entry, slug, expectedBranch, fs, abandon = false }) => {
|
|
151
|
+
const name = handoffBasename(slug);
|
|
152
|
+
const scan = scanPlansDir({ wtRoot: entry.path, fs });
|
|
153
|
+
if (scan.state === 'ok' && scan.nonRegular.includes(name)) {
|
|
154
|
+
throw stop(`handoff identity mismatch: ${name} is not a regular file`);
|
|
155
|
+
}
|
|
156
|
+
if (scan.state !== 'ok' || !scan.handoffs.includes(name)) {
|
|
157
|
+
if (abandon) throw stop(`${name} is absent — force deletion is forbidden without the handoff identity`);
|
|
158
|
+
throw stop(`handoff identity mismatch: expected ${name} in the satellite`);
|
|
159
|
+
}
|
|
160
|
+
// Every value below reaches a terminal, and every one of them is foreign: the names come from a
|
|
161
|
+
// directory listing, the record fields from a hand-editable file. They render ESCAPED — the guard
|
|
162
|
+
// that refuses them for the prompt must not be undone by the message that reports them.
|
|
163
|
+
if (scan.handoffs.length !== 1) {
|
|
164
|
+
throw stop(`handoff identity mismatch: expected exactly ${name}, found [${scan.handoffs.map(displayValue).join(', ')}]`);
|
|
165
|
+
}
|
|
166
|
+
const leaf = fs.readFileNoFollow(join(entry.path, PLANS_REL, name));
|
|
167
|
+
if (!leaf.bytes) throw stop(`handoff identity mismatch: ${name} is not readable as a regular file`);
|
|
168
|
+
const record = parseProvisionRecord(String(leaf.bytes));
|
|
169
|
+
const liveBranch = branchNameOf(entry);
|
|
170
|
+
const wantedBranch = expectedBranch ?? liveBranch;
|
|
171
|
+
if (record.slug !== slug || record.branch !== wantedBranch || liveBranch !== wantedBranch) {
|
|
172
|
+
throw stop(
|
|
173
|
+
`handoff identity mismatch: expected slug ${slug} and branch ${displayValue(wantedBranch)}; ` +
|
|
174
|
+
`record has slug ${record.slug === null ? '(missing)' : displayValue(record.slug)} and branch ${record.branch === null ? '(missing)' : displayValue(record.branch)}, ` +
|
|
175
|
+
`live branch ${liveBranch === null ? '(detached)' : displayValue(liveBranch)}`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return { record, path: join(entry.path, PLANS_REL, name), branch: wantedBranch };
|
|
179
|
+
};
|
package/tools/set-autonomy.mjs
CHANGED
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
// Dependency-free, Node >= 22. No side effects on import (the isDirectRun idiom).
|
|
23
23
|
|
|
24
24
|
import { readFileSync, lstatSync } from 'node:fs';
|
|
25
|
-
import { pathToFileURL } from 'node:url';
|
|
26
25
|
import {
|
|
27
26
|
AUTONOMY_REL,
|
|
28
27
|
fail,
|
|
@@ -35,6 +34,7 @@ import {
|
|
|
35
34
|
AUTONOMY_README,
|
|
36
35
|
} from './autonomy-config.mjs';
|
|
37
36
|
import { writeAutonomy as writeAutonomyFs } from './autonomy-write.mjs';
|
|
37
|
+
import { isDirectRun } from './direct-run.mjs';
|
|
38
38
|
|
|
39
39
|
// ── argument parsing (usage errors → exit 2) ────────────────────────────────────────
|
|
40
40
|
|
|
@@ -186,8 +186,7 @@ export const main = (argv, ctx = {}) => {
|
|
|
186
186
|
}
|
|
187
187
|
};
|
|
188
188
|
|
|
189
|
-
|
|
190
|
-
if (isDirectRun) {
|
|
189
|
+
if (isDirectRun(import.meta.url)) {
|
|
191
190
|
const r = main(process.argv.slice(2));
|
|
192
191
|
if (r.stdout) console.log(r.stdout);
|
|
193
192
|
if (r.stderr) console.error(r.stderr);
|
package/tools/set-flow.mjs
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
import { readFileSync, lstatSync } from 'node:fs';
|
|
32
32
|
import { join, dirname, resolve } from 'node:path';
|
|
33
|
-
import {
|
|
33
|
+
import { fileURLToPath } from 'node:url';
|
|
34
34
|
import { spawnSync } from 'node:child_process';
|
|
35
35
|
import {
|
|
36
36
|
CONFIG_REL,
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
FLOW_CANDIDATE_CLASSES,
|
|
45
45
|
FLOW_SCHEMA_1_FIXTURE,
|
|
46
46
|
} from './orchestration-config.mjs';
|
|
47
|
+
import { isDirectRun } from './direct-run.mjs';
|
|
47
48
|
import { writeConfig as writeConfigFs } from './orchestration-write.mjs';
|
|
48
49
|
import { loadDeclaration } from './run-gates.mjs';
|
|
49
50
|
import { compareSemver } from './semver-lite.mjs';
|
|
@@ -456,8 +457,7 @@ export const main = (argv, ctx = {}) => {
|
|
|
456
457
|
}
|
|
457
458
|
};
|
|
458
459
|
|
|
459
|
-
|
|
460
|
-
if (isDirectRun) {
|
|
460
|
+
if (isDirectRun(import.meta.url)) {
|
|
461
461
|
const r = main(process.argv.slice(2));
|
|
462
462
|
if (r.stdout) console.log(r.stdout);
|
|
463
463
|
if (r.stderr) console.error(r.stderr);
|
package/tools/set-recipe.mjs
CHANGED
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
|
|
24
24
|
import { readFileSync, lstatSync } from 'node:fs';
|
|
25
25
|
import { homedir } from 'node:os';
|
|
26
|
-
import { pathToFileURL } from 'node:url';
|
|
27
26
|
import { detectBackends } from './detect-backends.mjs';
|
|
27
|
+
import { isDirectRun } from './direct-run.mjs';
|
|
28
28
|
import { resolveActivityRecipe, composeActiveRecipeLine } from './recipes.mjs';
|
|
29
29
|
import { loadAutonomy, resolveAutonomy } from './autonomy-config.mjs';
|
|
30
30
|
import {
|
|
@@ -230,8 +230,7 @@ export const main = (argv, ctx = {}) => {
|
|
|
230
230
|
}
|
|
231
231
|
};
|
|
232
232
|
|
|
233
|
-
|
|
234
|
-
if (isDirectRun) {
|
|
233
|
+
if (isDirectRun(import.meta.url)) {
|
|
235
234
|
const r = main(process.argv.slice(2));
|
|
236
235
|
if (r.stdout) console.log(r.stdout);
|
|
237
236
|
if (r.stderr) console.error(r.stderr);
|
package/tools/setup-backends.mjs
CHANGED
|
@@ -28,9 +28,10 @@ import {
|
|
|
28
28
|
chmodSync, readFileSync, realpathSync,
|
|
29
29
|
} from 'node:fs';
|
|
30
30
|
import { join, resolve, relative, dirname, isAbsolute } from 'node:path';
|
|
31
|
-
import { fileURLToPath
|
|
31
|
+
import { fileURLToPath } from 'node:url';
|
|
32
32
|
import os from 'node:os';
|
|
33
33
|
import { KNOWN_BACKENDS, detectBackend, detectBackends, resolveDir, guideFor, READY } from './detect-backends.mjs';
|
|
34
|
+
import { isDirectRun } from './direct-run.mjs';
|
|
34
35
|
import { copyTreeRefresh, linkManaged, isReadonlyWriteBoundary } from './fs-safe.mjs';
|
|
35
36
|
import {
|
|
36
37
|
READONLY_RERUN_HINT, WRAPPER_MODE, scanBundleOwnedDrift, scanWrapperParity, parityVerdict,
|
|
@@ -821,5 +822,4 @@ export const main = (argv = process.argv.slice(2), deps = {}) => {
|
|
|
821
822
|
return worst;
|
|
822
823
|
};
|
|
823
824
|
|
|
824
|
-
|
|
825
|
-
if (isDirectRun) process.exit(main(process.argv.slice(2)));
|
|
825
|
+
if (isDirectRun(import.meta.url)) process.exit(main(process.argv.slice(2)));
|
package/tools/store-append.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// store-append.mjs — the PARAMETERIZED lock/CAS serialized-append leaf (delegation Plan 1, Phase 2,
|
|
2
|
-
// D12). Extracted VERBATIM from flow-
|
|
3
|
-
// (dispatch-store.mjs) is the second. No CLI, no side effects on import.
|
|
2
|
+
// D12). Extracted VERBATIM from the flow store, whose write door flow-append.mjs is now its first
|
|
3
|
+
// caller; the delegation store (dispatch-store.mjs) is the second. No CLI, no side effects on import.
|
|
4
4
|
//
|
|
5
5
|
// Why a leaf rather than an import of the flow appender: `appendFlowRecordWithPreflight` hardwires
|
|
6
6
|
// the AW_FLOW_STORE seam and validateFlowRecord, so a second store could only reuse it by pretending
|
package/tools/uninstall.mjs
CHANGED
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
|
|
25
25
|
import { existsSync, statSync, lstatSync, readlinkSync, readFileSync, readdirSync, realpathSync } from 'node:fs';
|
|
26
26
|
import { join, resolve, dirname, basename, isAbsolute } from 'node:path';
|
|
27
|
-
import { pathToFileURL } from 'node:url';
|
|
28
27
|
import os from 'node:os';
|
|
28
|
+
import { isDirectRun } from './direct-run.mjs';
|
|
29
29
|
import { surveyFamily, surveyProject, FAMILY_MEMBERS, classifyMember, OK } from './family-registry.mjs';
|
|
30
30
|
import { removeTreeManaged, unlinkManaged, MANAGED_LINK_CONFLICT } from './fs-safe.mjs';
|
|
31
31
|
import { deriveLinks } from './setup-backends.mjs';
|
|
@@ -606,8 +606,7 @@ const main = (argv) => {
|
|
|
606
606
|
}
|
|
607
607
|
};
|
|
608
608
|
|
|
609
|
-
|
|
610
|
-
if (isDirectRun) {
|
|
609
|
+
if (isDirectRun(import.meta.url)) {
|
|
611
610
|
try {
|
|
612
611
|
main(process.argv.slice(2));
|
|
613
612
|
} catch (err) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, lstatSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
3
3
|
import { homedir, tmpdir } from 'node:os';
|
|
4
|
-
import { fileURLToPath
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
5
|
// The --autonomy render reads the per-project autonomy policy through the read-only autonomy core
|
|
6
6
|
// (AD-044). This file is the family's one .claude/settings.json writer, so the policy render lives here;
|
|
7
7
|
// it never imports the policy fs-writer (autonomy-write.mjs) — the render owns the settings file, not
|
|
@@ -10,6 +10,7 @@ import { AUTONOMY_REL, loadAutonomy, resolveAutonomy, COMMAND_REDLINES } from '.
|
|
|
10
10
|
// The bridge-wrappers tier's placement probe (AD-044 Plan 4, Decision 2): a tier entry derives ONLY
|
|
11
11
|
// for a PLACED bridge wrapper — findOnPath is the same read-only PATH scan the backend detector uses.
|
|
12
12
|
import { findOnPath } from './detect-backends.mjs';
|
|
13
|
+
import { isDirectRun } from './direct-run.mjs';
|
|
13
14
|
import { compareSemver } from './semver-lite.mjs';
|
|
14
15
|
// The declared-path resolution + segment containment the allowWrite degrade shares with the
|
|
15
16
|
// advisor's worktrees-dir convergence lane — ONE leaf, so the two readings cannot drift.
|
|
@@ -1820,5 +1821,4 @@ export const main = (argv = process.argv.slice(2), deps = {}) => {
|
|
|
1820
1821
|
}
|
|
1821
1822
|
};
|
|
1822
1823
|
|
|
1823
|
-
|
|
1824
|
-
if (isDirectRun) process.exit(main(process.argv.slice(2)));
|
|
1824
|
+
if (isDirectRun(import.meta.url)) process.exit(main(process.argv.slice(2)));
|