javi-forge 1.35.1 → 1.37.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/README.md +5 -0
- package/assets/claude-hooks/javi-forge-skillguard-pre-tool-use.mjs +97 -29
- package/assets/claude-hooks/manifest.json +1 -1
- package/ci-local/README.md +11 -6
- package/ci-local/ci-local.ps1 +34 -0
- package/ci-local/ci-local.sh +19 -1
- package/ci-local/install.ps1 +23 -0
- package/ci-local/install.sh +18 -1
- package/dist/cli/dispatch/hooks.d.ts +9 -2
- package/dist/cli/dispatch/hooks.js +22 -8
- package/dist/cli/dispatch/simple-renderers.js +7 -0
- package/dist/commands/claude-hooks.js +2 -0
- package/dist/commands/codex-hooks.d.ts +26 -0
- package/dist/commands/codex-hooks.js +106 -0
- package/dist/commands/init.d.ts +9 -1
- package/dist/commands/init.js +10 -6
- package/dist/lib/__fixtures__/claude-hook-ownership.d.ts +6 -0
- package/dist/lib/__fixtures__/claude-hook-ownership.js +7 -1
- package/dist/lib/agent-adapter.d.ts +56 -0
- package/dist/lib/agent-adapter.js +88 -0
- package/dist/lib/claude-hook-manager.d.ts +17 -1
- package/dist/lib/claude-hook-manager.js +20 -4
- package/dist/lib/claude-hook-settings.d.ts +3 -3
- package/dist/lib/claude-hook-settings.js +3 -3
- package/dist/lib/codex-hook-manager.d.ts +178 -0
- package/dist/lib/codex-hook-manager.js +546 -0
- package/dist/lib/platform-support.d.ts +19 -0
- package/dist/lib/platform-support.js +22 -0
- package/dist/lib/secure-fs-transaction.d.ts +25 -5
- package/dist/lib/secure-fs-transaction.js +44 -19
- package/package.json +1 -1
|
@@ -65,14 +65,34 @@ function ancestorChain(leaf) {
|
|
|
65
65
|
* manual-recovery guidance (never clobbers a concurrent change).
|
|
66
66
|
*/
|
|
67
67
|
export async function runTransaction(input) {
|
|
68
|
+
// Seam validation (fail-closed): the topology is EITHER a `layout` OR the
|
|
69
|
+
// default Claude pair [asset, settings]. A caller with neither would deref
|
|
70
|
+
// `undefined.desired` deep in the engine — refuse up front with a clear error.
|
|
71
|
+
if (!input.layout && !(input.asset && input.settings)) {
|
|
72
|
+
throw new TxAbort("validate", "runTransaction requires `layout` or both `asset` and `settings`");
|
|
73
|
+
}
|
|
68
74
|
const { secureFs, clock, nonce, projectDir } = input;
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
// Container topology + write components. The default (no `layout`) is the exact
|
|
76
|
+
// Claude `.claude` → `.claude/hooks` nesting with [asset, settings]; a `layout`
|
|
77
|
+
// (Codex) supplies absolute containers parent-first and an ordered component
|
|
78
|
+
// list. Either way the proof primitives below are identical.
|
|
79
|
+
const containers = input.layout
|
|
80
|
+
? input.layout.containers
|
|
81
|
+
: [
|
|
82
|
+
path.join(projectDir, ".claude"),
|
|
83
|
+
path.join(projectDir, ".claude", "hooks"),
|
|
84
|
+
];
|
|
85
|
+
const components = input.layout
|
|
86
|
+
? input.layout.components
|
|
87
|
+
: [
|
|
88
|
+
input.asset,
|
|
89
|
+
input.settings,
|
|
90
|
+
];
|
|
71
91
|
// The dirs the tool OWNS: their children include the executed asset and the
|
|
72
92
|
// settings it is referenced from. Fixed and known to the core regardless of
|
|
73
93
|
// the per-run write plan; each existing member is proved on EVERY anyWrite run
|
|
74
94
|
// (Round-4/5 / JDA-401 + JDB5-001).
|
|
75
|
-
const managedContainers = new Set(
|
|
95
|
+
const managedContainers = new Set(containers);
|
|
76
96
|
const heldByPath = new Map();
|
|
77
97
|
const heldOrder = [];
|
|
78
98
|
const createdDirs = [];
|
|
@@ -80,7 +100,12 @@ export async function runTransaction(input) {
|
|
|
80
100
|
const committed = [];
|
|
81
101
|
const backups = [];
|
|
82
102
|
const needsWrite = (c) => c.desired !== null;
|
|
83
|
-
const anyWrite =
|
|
103
|
+
const anyWrite = components.some(needsWrite);
|
|
104
|
+
// A component writes into `container` when its parent dir IS the container or a
|
|
105
|
+
// descendant of it — used to decide which absent containers to create.
|
|
106
|
+
const writesInto = (container) => components.some((c) => needsWrite(c) &&
|
|
107
|
+
(path.dirname(c.path) === container ||
|
|
108
|
+
path.dirname(c.path).startsWith(`${container}${path.sep}`)));
|
|
84
109
|
// The uniform per-held-dir gate. It runs the LENIENT ancestor ACL predicate on
|
|
85
110
|
// EVERY held dir — including managed containers, which are ALSO proved strict by
|
|
86
111
|
// `proveManagedContainer` right after they are gated (in ensureManagedContainer)
|
|
@@ -168,23 +193,23 @@ export async function runTransaction(input) {
|
|
|
168
193
|
// pre-commit); one that is absent is CREATED only when a child is written
|
|
169
194
|
// into it this run, else left alone (nothing to secure).
|
|
170
195
|
if (anyWrite) {
|
|
171
|
-
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
196
|
+
// Ensure every managed container PARENT-FIRST. Each container's parent is
|
|
197
|
+
// already held (its dirname was gated in preflight or ensured by an earlier
|
|
198
|
+
// iteration). A container is CREATED only when a component writes into it
|
|
199
|
+
// or a descendant container this run; otherwise it is proved IF present,
|
|
200
|
+
// else left alone (JDB5-001). This generalizes the former hardcoded
|
|
201
|
+
// `.claude` → `.claude/hooks` pair without changing any proof primitive.
|
|
202
|
+
for (const container of containers) {
|
|
203
|
+
const parentHandle = heldByPath.get(path.dirname(container));
|
|
204
|
+
if (!parentHandle) {
|
|
205
|
+
throw new TxAbort(`container ${container}`, "parent chain not held");
|
|
206
|
+
}
|
|
207
|
+
await ensureManagedContainer(parentHandle, container,
|
|
208
|
+
/* createIfAbsent */ writesInto(container));
|
|
179
209
|
}
|
|
180
|
-
// .claude/hooks: create when the asset writes into it; otherwise prove
|
|
181
|
-
// IF it exists (settings-only repair must still secure the hook's
|
|
182
|
-
// container — JDB5-001).
|
|
183
|
-
await ensureManagedContainer(claudeHandle, hooksDir,
|
|
184
|
-
/* createIfAbsent */ needsWrite(input.asset));
|
|
185
210
|
}
|
|
186
|
-
// --- CAPTURE + (FORCED) BACKUP + STAGE,
|
|
187
|
-
for (const component of
|
|
211
|
+
// --- CAPTURE + (FORCED) BACKUP + STAGE, in component order ---
|
|
212
|
+
for (const component of components) {
|
|
188
213
|
if (!needsWrite(component))
|
|
189
214
|
continue;
|
|
190
215
|
const parentPath = path.dirname(component.path);
|