agentic-workflow-manager 9.7.1 → 9.9.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 -1
- package/dist/src/commands/job/exec-wrapper.js +53 -3
- package/dist/src/commands/job/gate.js +18 -0
- package/dist/src/commands/job/index.js +61 -0
- package/dist/src/commands/model-policy/index.js +73 -0
- package/dist/src/commands/plan/index.js +182 -7
- package/dist/src/commands/sensors/bootstrap.js +36 -5
- package/dist/src/commands/sensors/compatibility/contract.js +19 -4
- package/dist/src/commands/sensors/compatibility/discovery.js +23 -3
- package/dist/src/commands/sensors/compatibility/live.js +18 -1
- package/dist/src/commands/sensors/compatibility/probe.js +8 -2
- package/dist/src/commands/sensors/compatibility/resolve.js +5 -2
- package/dist/src/commands/sensors/coverage/evidence.js +19 -10
- package/dist/src/commands/sensors/coverage/index.js +11 -2
- package/dist/src/commands/sensors/coverage/resolve.js +10 -0
- package/dist/src/commands/sensors/exec.js +16 -1
- package/dist/src/commands/sensors/migrate.js +62 -2
- package/dist/src/commands/sensors/prepare.js +2 -0
- package/dist/src/commands/sensors/result.js +2 -0
- package/dist/src/commands/sensors/run.js +64 -1
- package/dist/src/commands/sensors/status.js +6 -4
- package/dist/src/commands/watch/apply.js +32 -0
- package/dist/src/commands/watch/archive-unused.js +138 -0
- package/dist/src/commands/watch/generations.js +32 -9
- package/dist/src/commands/watch/index.js +108 -2
- package/dist/src/commands/watch/init.js +149 -18
- package/dist/src/commands/watch/supervisor.js +167 -13
- package/dist/src/commands/watch/teardown-driver.js +13 -13
- package/dist/src/commands/watch/track-state.js +59 -0
- package/dist/src/commands/watch/tracks.js +38 -102
- package/dist/src/core/admission/index.js +231 -0
- package/dist/src/core/admission/registry-contracts.js +290 -0
- package/dist/src/core/journal/fingerprint.js +35 -1
- package/dist/src/core/journal/paths.js +11 -0
- package/dist/src/core/journal/requests.js +1 -1
- package/dist/src/core/journal/store.js +146 -4
- package/dist/src/core/journal/types.js +57 -2
- package/dist/src/core/migration/historical-provenance.js +18 -0
- package/dist/src/core/migration/index.js +322 -0
- package/dist/src/core/model-policy/canonical.js +18 -0
- package/dist/src/core/model-policy/capabilities.js +197 -0
- package/dist/src/core/model-policy/capability-types.js +2 -0
- package/dist/src/core/model-policy/journal.js +124 -0
- package/dist/src/core/model-policy/paths.js +12 -0
- package/dist/src/core/model-policy/resolve.js +116 -0
- package/dist/src/core/model-policy/store.js +182 -0
- package/dist/src/core/model-policy/types.js +2 -0
- package/dist/src/core/model-policy/validate.js +112 -0
- package/dist/src/core/plan/identity.js +77 -0
- package/dist/src/core/plan/validate.js +191 -78
- package/dist/src/index.js +2 -0
- package/dist/tests/commands/job/exec-wrapper.test.js +16 -0
- package/dist/tests/commands/job/gate-reconcile.test.js +40 -10
- package/dist/tests/commands/job/gate.test.js +9 -0
- package/dist/tests/commands/job/routing-report-cli.test.js +46 -0
- package/dist/tests/commands/job/routing.test.js +11 -0
- package/dist/tests/commands/model-policy/index.test.js +57 -0
- package/dist/tests/commands/pin.test.js +23 -23
- package/dist/tests/commands/plan/index.test.js +682 -14
- package/dist/tests/commands/sensors/bootstrap.test.js +57 -4
- package/dist/tests/commands/sensors/compatibility/contract.test.js +21 -0
- package/dist/tests/commands/sensors/compatibility/discovery.test.js +19 -0
- package/dist/tests/commands/sensors/compatibility/probe.test.js +14 -1
- package/dist/tests/commands/sensors/compatibility/resolve.test.js +17 -0
- package/dist/tests/commands/sensors/coverage/evidence.test.js +51 -27
- package/dist/tests/commands/sensors/coverage/resolve.test.js +51 -0
- package/dist/tests/commands/sensors/exec.test.js +112 -0
- package/dist/tests/commands/sensors/run-changed.test.js +11 -0
- package/dist/tests/commands/sensors/run.test.js +15 -2
- package/dist/tests/commands/sensors/status.test.js +3 -3
- package/dist/tests/commands/watch/apply.test.js +12 -0
- package/dist/tests/commands/watch/e2e-crash.test.js +126 -11
- package/dist/tests/commands/watch/generations.test.js +113 -4
- package/dist/tests/commands/watch/plan-lifecycle.test.js +263 -0
- package/dist/tests/commands/watch/supervisor-loop.test.js +247 -49
- package/dist/tests/commands/watch/track-finalize.test.js +20 -3
- package/dist/tests/commands/watch/track-freeze.test.js +43 -30
- package/dist/tests/commands/watch/track-state-dependency.test.js +15 -0
- package/dist/tests/commands/watch/watch-init.test.js +244 -0
- package/dist/tests/core/admission/index.test.js +140 -0
- package/dist/tests/core/journal/fingerprint.test.js +22 -0
- package/dist/tests/core/journal/store.test.js +53 -0
- package/dist/tests/core/journal/types.test.js +7 -0
- package/dist/tests/core/migration/facts.test.js +289 -0
- package/dist/tests/core/migration/historical-provenance.test.js +25 -0
- package/dist/tests/core/model-policy/capabilities.test.js +365 -0
- package/dist/tests/core/model-policy/journal.test.js +46 -0
- package/dist/tests/core/model-policy/policy.test.js +47 -0
- package/dist/tests/core/model-policy/resolve.test.js +111 -0
- package/dist/tests/core/model-policy/store.test.js +177 -0
- package/dist/tests/core/plan/validate.test.js +360 -8
- package/dist/tests/core/secure-fs/native-bridge.test.js +81 -4
- package/dist/tests/integration/pack-e2e.test.js +4 -1
- package/dist/tests/integration/preflight-json-pipe.e2e.test.js +7 -3
- package/dist/tests/integration/sensor-bootstrap.e2e.test.js +37 -0
- package/dist/tests/integration/sensor-structured-run.e2e.test.js +12 -10
- package/dist/tests/providers/injection-config.test.js +14 -6
- package/dist/tests/structural/directory-fsync-is-single-source.test.js +97 -0
- package/dist/tests/structural/jest-environment-is-isolated.test.js +29 -24
- package/dist/tests/structural/native-release-artifacts.test.js +30 -0
- package/package.json +4 -3
- package/prebuilds/darwin-arm64/secure_fs.node +0 -0
- package/prebuilds/darwin-x64/secure_fs.node +0 -0
- package/prebuilds/linux-arm64/secure_fs.node +0 -0
- package/prebuilds/linux-x64/secure_fs.node +0 -0
- package/prebuilds/win32-arm64/secure_fs.node +0 -0
- package/prebuilds/win32-x64/secure_fs.node +0 -0
|
@@ -160,6 +160,28 @@ describe('native secure-fs Windows source contract', () => {
|
|
|
160
160
|
expect(removal).not.toMatch(/\bDeleteFileW\b/);
|
|
161
161
|
});
|
|
162
162
|
});
|
|
163
|
+
describe('native secure-fs durable publication source contract', () => {
|
|
164
|
+
const source = () => fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../../../native/secure_fs.cc'), 'utf8').replace(/\r\n/g, '\n');
|
|
165
|
+
it('turns parent-directory fsync failure after publication into a bounded error', () => {
|
|
166
|
+
const native = source();
|
|
167
|
+
const write = native.slice(native.indexOf('napi_value WriteProjectTransaction'), native.indexOf('\n} // namespace'));
|
|
168
|
+
expect(native).toMatch(/if \(fsync\(parent\) != 0\)[\s\S]{0,240}Throw\(env, "secure-fs durable directory sync failed"\)/);
|
|
169
|
+
expect(write).toMatch(/fsync\(parent\) == 0;[\s\S]{0,180}secure-fs durable directory sync failed/);
|
|
170
|
+
const withoutWriteSync = write.replace('fsync(parent) == 0', 'true');
|
|
171
|
+
expect(withoutWriteSync).not.toMatch(/fsync\(parent\) == 0;/);
|
|
172
|
+
expect(withoutWriteSync).not.toMatch(/fsync\(parent\) == 0;[\s\S]{0,180}secure-fs durable directory sync failed/);
|
|
173
|
+
});
|
|
174
|
+
it('degrades only the unsupported Windows directory flush and retains all other durable failures', () => {
|
|
175
|
+
expect(source()).toMatch(/FlushFileBuffers\(parent\.handle\) == 0 && GetLastError\(\) != ERROR_ACCESS_DENIED/);
|
|
176
|
+
expect(source()).toMatch(/if \(directory_sync_failed\).*secure-fs durable directory sync failed/);
|
|
177
|
+
});
|
|
178
|
+
it('does not clean a staging name already consumed by a fenced POSIX rename', () => {
|
|
179
|
+
const write = source().slice(source().indexOf('napi_value WriteProjectTransaction'), source().indexOf('\n} // namespace'));
|
|
180
|
+
expect(write).toContain('const bool cleaned = options.replace || unlinkat(parent, temporary.c_str(), 0) == 0;');
|
|
181
|
+
const reverted = write.replace('options.replace || ', '');
|
|
182
|
+
expect(reverted).not.toContain('const bool cleaned = options.replace || unlinkat(parent, temporary.c_str(), 0) == 0;');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
163
185
|
describe('native secure-fs POSIX source contract', () => {
|
|
164
186
|
const source = () => fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../../../native/secure_fs.cc'), 'utf8');
|
|
165
187
|
it('uses an unpredictable nonce and a bounded retry loop for descriptor-relative staging', () => {
|
|
@@ -399,6 +421,38 @@ const nativeFixtureAvailable = ['linux', 'darwin', 'win32'].includes(process.pla
|
|
|
399
421
|
&& ['x64', 'arm64'].includes(process.arch)
|
|
400
422
|
&& fs_1.default.existsSync(path_1.default.join(__dirname, '../../../prebuilds', `${process.platform}-${process.arch}`, 'secure_fs.node'));
|
|
401
423
|
const nativeOnly = nativeFixtureAvailable ? describe : describe.skip;
|
|
424
|
+
const testAddonPath = path_1.default.join(__dirname, '../../../native/build/Release/secure_fs_test.node');
|
|
425
|
+
const nativeTestOnly = describe;
|
|
426
|
+
nativeTestOnly('native secure-fs directory-sync fault injection', () => {
|
|
427
|
+
let root;
|
|
428
|
+
let testBinding;
|
|
429
|
+
beforeEach(() => {
|
|
430
|
+
expect(fs_1.default.existsSync(testAddonPath)).toBe(true);
|
|
431
|
+
root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-secure-fs-fsync-'));
|
|
432
|
+
testBinding = require(testAddonPath);
|
|
433
|
+
});
|
|
434
|
+
afterEach(() => { testBinding.setDirectoryFsyncFailureForTests(false); fs_1.default.rmSync(root, { recursive: true, force: true }); });
|
|
435
|
+
it('writes the target then reports the forced post-publication directory-sync failure', () => {
|
|
436
|
+
testBinding.setDirectoryFsyncFailureForTests(true);
|
|
437
|
+
expect(() => testBinding.writeProjectTransaction(root, 'durable.txt', Buffer.from('published'), { mode: 'create', createParents: false })).toThrow('secure-fs durable directory sync failed');
|
|
438
|
+
expect(fs_1.default.readFileSync(path_1.default.join(root, 'durable.txt'), 'utf8')).toBe('published');
|
|
439
|
+
});
|
|
440
|
+
it('publishes an exact fenced replacement with fault injection disabled', () => {
|
|
441
|
+
const target = path_1.default.join(root, 'replace.json');
|
|
442
|
+
fs_1.default.writeFileSync(target, 'before');
|
|
443
|
+
const observed = testBinding.readRegularFile(target, 1024);
|
|
444
|
+
expect(() => testBinding.writeProjectTransaction(root, 'replace.json', Buffer.from('after'), {
|
|
445
|
+
mode: 'replace', expected: observed.bytes, expectedIdentity: observed.identity, createParents: false,
|
|
446
|
+
})).not.toThrow();
|
|
447
|
+
expect(fs_1.default.readFileSync(target, 'utf8')).toBe('after');
|
|
448
|
+
});
|
|
449
|
+
it('keeps the production prebuild free of the test-only control', () => {
|
|
450
|
+
if (!nativeFixtureAvailable)
|
|
451
|
+
return;
|
|
452
|
+
const production = require(path_1.default.join(__dirname, '../../../prebuilds', `${process.platform}-${process.arch}`, 'secure_fs.node'));
|
|
453
|
+
expect(production.setDirectoryFsyncFailureForTests).toBeUndefined();
|
|
454
|
+
});
|
|
455
|
+
});
|
|
402
456
|
nativeOnly('native secure-fs identity fence fixtures', () => {
|
|
403
457
|
let root;
|
|
404
458
|
let binding;
|
|
@@ -406,6 +460,11 @@ nativeOnly('native secure-fs identity fence fixtures', () => {
|
|
|
406
460
|
root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-secure-fs-identity-'));
|
|
407
461
|
binding = require(path_1.default.join(__dirname, '../../../prebuilds', `${process.platform}-${process.arch}`, 'secure_fs.node'));
|
|
408
462
|
});
|
|
463
|
+
it('performs a real artifact-backed publish when the CI prebuild is available', () => {
|
|
464
|
+
const target = path_1.default.join(root, 'durable.txt');
|
|
465
|
+
binding.writeProjectTransaction(root, 'durable.txt', Buffer.from('published'), { mode: 'create', createParents: false });
|
|
466
|
+
expect(fs_1.default.readFileSync(target, 'utf8')).toBe('published');
|
|
467
|
+
});
|
|
409
468
|
afterEach(() => { fs_1.default.rmSync(root, { recursive: true, force: true }); });
|
|
410
469
|
it('returns bytes with a canonical native identity from the same regular-file read', () => {
|
|
411
470
|
const target = path_1.default.join(root, 'sensors.json');
|
|
@@ -690,6 +749,7 @@ windowsOnly('native secure-fs Windows handle fixtures', () => {
|
|
|
690
749
|
fs.symlinkSync(workerData.outside, workerData.trusted, 'junction');
|
|
691
750
|
Atomics.add(state, 1, 1);
|
|
692
751
|
Atomics.notify(state, 1);
|
|
752
|
+
parentPort.postMessage('ready');
|
|
693
753
|
Atomics.wait(state, 0, 0, 1);
|
|
694
754
|
fs.rmSync(workerData.trusted);
|
|
695
755
|
fs.renameSync(workerData.parked, workerData.trusted);
|
|
@@ -701,13 +761,30 @@ windowsOnly('native secure-fs Windows handle fixtures', () => {
|
|
|
701
761
|
restore();
|
|
702
762
|
parentPort.postMessage('done');
|
|
703
763
|
`, { eval: true, workerData: { shared, trusted, parked, outside } });
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
764
|
+
let resolveReady;
|
|
765
|
+
let rejectReady;
|
|
766
|
+
let resolveDone;
|
|
767
|
+
let rejectDone;
|
|
768
|
+
const ready = new Promise((resolve, reject) => { resolveReady = resolve; rejectReady = reject; });
|
|
769
|
+
const done = new Promise((resolve, reject) => { resolveDone = resolve; rejectDone = reject; });
|
|
770
|
+
const readyTimeout = setTimeout(() => rejectReady(new Error('junction swap worker did not become ready')), 5_000);
|
|
771
|
+
worker.on('message', message => {
|
|
772
|
+
if (message === 'ready') {
|
|
773
|
+
clearTimeout(readyTimeout);
|
|
774
|
+
resolveReady();
|
|
775
|
+
}
|
|
776
|
+
if (message === 'done')
|
|
777
|
+
resolveDone();
|
|
778
|
+
});
|
|
779
|
+
worker.once('error', error => {
|
|
780
|
+
clearTimeout(readyTimeout);
|
|
781
|
+
const failure = error instanceof Error ? error : new Error('junction swap worker failed');
|
|
782
|
+
rejectReady(failure);
|
|
783
|
+
rejectDone(failure);
|
|
707
784
|
});
|
|
708
785
|
let published = 0;
|
|
709
786
|
try {
|
|
710
|
-
|
|
787
|
+
await ready;
|
|
711
788
|
expect(Atomics.load(state, 1)).toBeGreaterThan(0);
|
|
712
789
|
for (let attempt = 0; attempt < 500; attempt += 1) {
|
|
713
790
|
try {
|
|
@@ -38,7 +38,10 @@ it('el tarball empaquetado corre awm update sin el monorepo', () => {
|
|
|
38
38
|
const awmHome = path_1.default.join(home, '.awm');
|
|
39
39
|
fs_1.default.mkdirSync(awmHome, { recursive: true });
|
|
40
40
|
fs_1.default.writeFileSync(path_1.default.join(awmHome, 'registries.json'), JSON.stringify([{ name: 'baseline', remote: source }]));
|
|
41
|
-
|
|
41
|
+
// El artefacto se debe ejecutar con el mismo runtime que corre la prueba:
|
|
42
|
+
// usar `node` desde PATH podría probar accidentalmente otra versión. En
|
|
43
|
+
// particular, esto cubre Node 22, declarado como compatible por package.json.
|
|
44
|
+
(0, child_process_1.execSync)(`"${process.execPath}" "${path_1.default.join(pkgDir, 'dist/src/index.js')}" update`, {
|
|
42
45
|
env: { ...process.env, HOME: home, AWM_HOME: awmHome, AWM_NO_UPDATE_CHECK: '1' },
|
|
43
46
|
stdio: 'pipe',
|
|
44
47
|
});
|
|
@@ -105,13 +105,17 @@ test('verify-sensors degrades parseably for a v2 sensor that exits 2 without fin
|
|
|
105
105
|
writeJson(path_1.default.join(project, 'package.json'), { name: 'preflight-verify-fixture', private: true });
|
|
106
106
|
writeJson(path_1.default.join(project, 'node_modules', 'fixture-sensor', 'package.json'), { name: 'fixture-sensor', version: '1.0.0' });
|
|
107
107
|
fs_1.default.writeFileSync(path_1.default.join(project, 'fixture-sensor.config.mjs'), 'export default {};\n');
|
|
108
|
-
|
|
108
|
+
const fixtureArgs = ['-e', 'process.exit(2);', '--', '--fixture'];
|
|
109
|
+
const fixtureBin = path_1.default.join(project, 'node_modules', '.bin', process.platform === 'win32' ? 'fixture-sensor.exe' : 'fixture-sensor');
|
|
110
|
+
fs_1.default.mkdirSync(path_1.default.dirname(fixtureBin), { recursive: true });
|
|
111
|
+
fs_1.default.copyFileSync(process.execPath, fixtureBin);
|
|
112
|
+
fs_1.default.chmodSync(fixtureBin, 0o755);
|
|
109
113
|
writeJson(path_1.default.join(registry, 'sensor-packs', 'fixture', 'pack.json'), {
|
|
110
114
|
schemaVersion: 2, name: 'fixture', description: 'preflight exit-2 fixture', detects: ['package.json'],
|
|
111
115
|
sensors: { lint: { applicability: { allFiles: ['package.json'] }, variants: [{
|
|
112
116
|
id: 'fixture-v1', priority: 100,
|
|
113
117
|
requirements: { tool: 'fixture-sensor', toolRange: '>=1 <2', runtime: 'node', runtimeRange: '>=20', configFiles: ['fixture-sensor.config.mjs'] },
|
|
114
|
-
certifiedRange: '>=1 <2', command: { executable: '
|
|
118
|
+
certifiedRange: '>=1 <2', command: { executable: 'fixture-sensor', resolution: 'node-modules-bin', args: fixtureArgs },
|
|
115
119
|
assets: ['fixture-sensor.config.mjs'], formatter: 'generic', probe: { kind: 'config-present' },
|
|
116
120
|
}] } },
|
|
117
121
|
coverage: { schemaVersion: 1, classes: {
|
|
@@ -124,7 +128,7 @@ test('verify-sensors degrades parseably for a v2 sensor that exits 2 without fin
|
|
|
124
128
|
writeJson(path_1.default.join(awmHome, 'registries.json'), [{ name: 'baseline', remote: 'fixture' }]);
|
|
125
129
|
writeJson(path_1.default.join(project, '.awm', 'sensors.json'), {
|
|
126
130
|
schemaVersion: 2, pack: 'fixture', packSelection: 'explicit', sensors: { lint: {
|
|
127
|
-
enabled: true, fast: true, variantId: 'fixture-v1', command: { executable: '
|
|
131
|
+
enabled: true, fast: true, variantId: 'fixture-v1', command: { executable: 'fixture-sensor', resolution: 'node-modules-bin', args: fixtureArgs }, assets: ['fixture-sensor.config.mjs'],
|
|
128
132
|
initializedCompatibility: { state: 'certified', reason: 'fixture', variantId: 'fixture-v1', toolVersion: '1.0.0', runtimeVersion: process.versions.node, certifiedRange: '>=1 <2', evidence: [] },
|
|
129
133
|
} },
|
|
130
134
|
});
|
|
@@ -14,6 +14,7 @@ const safe_file_1 = require("../../src/commands/sensors/compatibility/safe-file"
|
|
|
14
14
|
const native_bridge_1 = require("../../src/core/secure-fs/native-bridge");
|
|
15
15
|
const cliRoot = path_1.default.resolve(__dirname, '../..');
|
|
16
16
|
const bin = path_1.default.join(cliRoot, 'dist/src/index.js');
|
|
17
|
+
const nativeArtifact = path_1.default.join(cliRoot, 'prebuilds', `${process.platform}-${process.arch}`, 'secure_fs.node');
|
|
17
18
|
const fixtureRoot = path_1.default.join(cliRoot, 'tests/fixtures/sensor-compatibility');
|
|
18
19
|
function hashTree(root) {
|
|
19
20
|
const hash = crypto_1.default.createHash('sha256');
|
|
@@ -70,6 +71,8 @@ function v2Manifest() {
|
|
|
70
71
|
beforeAll(() => {
|
|
71
72
|
if (!fs_1.default.existsSync(bin))
|
|
72
73
|
throw new Error(`Sensor bootstrap E2E requires the compiled CLI at ${bin}; run npm run build before this test.`);
|
|
74
|
+
if (!fs_1.default.existsSync(nativeArtifact))
|
|
75
|
+
throw new Error(`Sensor bootstrap E2E requires the host secure-fs artifact at ${nativeArtifact}; run npm run native:build before this test.`);
|
|
73
76
|
});
|
|
74
77
|
test('compiled bootstrap creates once and the exact second invocation is a byte-stable no-op', () => {
|
|
75
78
|
const subject = fixture();
|
|
@@ -163,3 +166,37 @@ test('compiled bootstrap migrates v2 once, preserves all non-manifest project by
|
|
|
163
166
|
fs_1.default.rmSync(subject.root, { recursive: true, force: true });
|
|
164
167
|
}
|
|
165
168
|
});
|
|
169
|
+
test('compiled bootstrap requires explicit project-sensors mode before replacing a legacy manifest', () => {
|
|
170
|
+
const subject = fixture();
|
|
171
|
+
try {
|
|
172
|
+
const manifest = path_1.default.join(subject.project, '.awm', 'sensors.json');
|
|
173
|
+
const legacy = {
|
|
174
|
+
pack: 'js-ts',
|
|
175
|
+
sensors: { lint: { cmd: 'npx eslint .' } },
|
|
176
|
+
};
|
|
177
|
+
fs_1.default.writeFileSync(manifest, JSON.stringify(legacy, null, 2) + '\n');
|
|
178
|
+
const before = fs_1.default.readFileSync(manifest);
|
|
179
|
+
const machineBefore = hashTree(subject.awmHome);
|
|
180
|
+
const blocked = run(subject, '--dry-run');
|
|
181
|
+
expect(blocked.status).toBe(1);
|
|
182
|
+
expect(`${blocked.stdout}${blocked.stderr}`).toContain('legacy-replacement-requires-project-sensors-mode');
|
|
183
|
+
expect(fs_1.default.readFileSync(manifest)).toEqual(before);
|
|
184
|
+
const dryRun = run(subject, '--mode', 'project-sensors', '--dry-run');
|
|
185
|
+
expect(dryRun.status).toBe(0);
|
|
186
|
+
expect(fs_1.default.readFileSync(manifest)).toEqual(before);
|
|
187
|
+
const migrated = run(subject, '--mode', 'project-sensors');
|
|
188
|
+
expect(migrated.status).toBe(0);
|
|
189
|
+
expect(`${migrated.stdout}${migrated.stderr}`).toContain('migrated');
|
|
190
|
+
expect(`${migrated.stdout}${migrated.stderr}`).not.toContain('legacy-v1-preserved');
|
|
191
|
+
expect(JSON.parse(fs_1.default.readFileSync(manifest, 'utf8'))).toMatchObject({
|
|
192
|
+
schemaVersion: 3,
|
|
193
|
+
mode: 'project-sensors',
|
|
194
|
+
pack: 'js-ts',
|
|
195
|
+
source: { registry: 'baseline' },
|
|
196
|
+
});
|
|
197
|
+
expect(hashTree(subject.awmHome)).toBe(machineBefore);
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
fs_1.default.rmSync(subject.root, { recursive: true, force: true });
|
|
201
|
+
}
|
|
202
|
+
});
|
|
@@ -26,6 +26,7 @@ function createFixture() {
|
|
|
26
26
|
const awmHome = path_1.default.join(root, 'awm-home');
|
|
27
27
|
const registryRoot = path_1.default.join(awmHome, 'registries', 'baseline');
|
|
28
28
|
const literal = shellSensitiveLiteral;
|
|
29
|
+
const args = ['-e', "require('fs').writeFileSync('structured-argv.json', JSON.stringify(process.argv.slice(1)));", '--', literal];
|
|
29
30
|
writeJson(path_1.default.join(project, 'package.json'), { name: 'structured-run-fixture', private: true });
|
|
30
31
|
// Local metadata is the compatibility evidence. It is not a tool found in a
|
|
31
32
|
// global installation, so init and run must keep resolving this fixture's pack.
|
|
@@ -33,10 +34,12 @@ function createFixture() {
|
|
|
33
34
|
name: 'fixture-sensor', version: '1.0.0',
|
|
34
35
|
});
|
|
35
36
|
fs_1.default.writeFileSync(path_1.default.join(project, 'fixture-sensor.config.mjs'), 'export default {};\n');
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const fixtureBin = path_1.default.join(project, 'node_modules', '.bin', process.platform === 'win32' ? 'fixture-sensor.exe' : 'fixture-sensor');
|
|
38
|
+
fs_1.default.mkdirSync(path_1.default.dirname(fixtureBin), { recursive: true });
|
|
39
|
+
// A real local native executable works on Windows too; shebang scripts do
|
|
40
|
+
// not. The controlled program and adversarial literal remain separate argv.
|
|
41
|
+
fs_1.default.copyFileSync(process.execPath, fixtureBin);
|
|
42
|
+
fs_1.default.chmodSync(fixtureBin, 0o755);
|
|
40
43
|
writeJson(path_1.default.join(registryRoot, 'sensor-packs', 'fixture', 'pack.json'), {
|
|
41
44
|
schemaVersion: 2,
|
|
42
45
|
name: 'fixture',
|
|
@@ -53,10 +56,9 @@ function createFixture() {
|
|
|
53
56
|
runtime: 'node', runtimeRange: '>=20', configFiles: ['fixture-sensor.config.mjs'],
|
|
54
57
|
},
|
|
55
58
|
certifiedRange: '>=1 <2',
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
command: { executable: 'node', resolution: 'path', args: ['fixture-sensor.mjs', literal] },
|
|
59
|
+
// The fixture executable is project-local. Keeping the literal
|
|
60
|
+
// as one argv element proves no shell parses it.
|
|
61
|
+
command: { executable: 'fixture-sensor', resolution: 'node-modules-bin', args },
|
|
60
62
|
assets: ['fixture-sensor.config.mjs'], formatter: 'generic', probe: { kind: 'config-present' },
|
|
61
63
|
}],
|
|
62
64
|
},
|
|
@@ -72,7 +74,7 @@ function createFixture() {
|
|
|
72
74
|
},
|
|
73
75
|
});
|
|
74
76
|
writeJson(path_1.default.join(awmHome, 'registries.json'), [{ name: 'baseline', remote: 'fixture' }]);
|
|
75
|
-
return { root, project, awmHome, registryRoot, literal };
|
|
77
|
+
return { root, project, awmHome, registryRoot, literal, args };
|
|
76
78
|
}
|
|
77
79
|
function runCli(fixture, ...args) {
|
|
78
80
|
return (0, child_process_1.spawnSync)(process.execPath, [bin, 'sensors', ...args], {
|
|
@@ -111,7 +113,7 @@ test('compiled sensors run materializes a v2 registry command and passes its lit
|
|
|
111
113
|
mode: 'project-sensors',
|
|
112
114
|
pack: 'fixture',
|
|
113
115
|
source: { registry: 'baseline' },
|
|
114
|
-
sensors: { structured: { variantId: 'fixture-v1', command: { executable: '
|
|
116
|
+
sensors: { structured: { variantId: 'fixture-v1', command: { executable: 'fixture-sensor', resolution: 'node-modules-bin', args: fixture.args } } },
|
|
115
117
|
});
|
|
116
118
|
const result = runCli(fixture, 'run', '--fast');
|
|
117
119
|
assertSuccessfulCli(result, 'run --fast', true);
|
|
@@ -6,18 +6,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const os_1 = __importDefault(require("os"));
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const providers_1 = require("../../src/providers");
|
|
9
|
+
const paths_1 = require("../../src/core/paths");
|
|
9
10
|
describe('getInjection', () => {
|
|
10
11
|
it('returns cc-settings-merge for claude-code', () => {
|
|
11
12
|
const inj = (0, providers_1.getInjection)('claude-code');
|
|
12
13
|
expect(inj?.type).toBe('cc-settings-merge');
|
|
13
14
|
});
|
|
14
15
|
it('returns config-instructions for opencode pointing at the global opencode.json', () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
// Windows os.homedir() uses USERPROFILE while the CLI honors HOME.
|
|
17
|
+
const systemHome = jest.spyOn(os_1.default, 'homedir').mockReturnValue(path_1.default.resolve('different-system-profile'));
|
|
18
|
+
try {
|
|
19
|
+
const inj = (0, providers_1.getInjection)('opencode');
|
|
20
|
+
expect(inj).toEqual({
|
|
21
|
+
type: 'config-instructions',
|
|
22
|
+
configPath: path_1.default.join((0, paths_1.homeDir)(), '.config/opencode/opencode.json'),
|
|
23
|
+
field: 'instructions',
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
systemHome.mockRestore();
|
|
28
|
+
}
|
|
21
29
|
});
|
|
22
30
|
it('returns undefined for antigravity (no injection mechanism wired yet)', () => {
|
|
23
31
|
expect((0, providers_1.getInjection)('antigravity')).toBeUndefined();
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
// Structural guard, same family as symlink-type-is-explicit.test.ts.
|
|
7
|
+
//
|
|
8
|
+
// fsync-ing a DIRECTORY file descriptor is a POSIX-only capability. On Windows
|
|
9
|
+
// `fs.openSync(dir, 'r')` succeeds and the following `fs.fsyncSync(fd)` always
|
|
10
|
+
// fails with EPERM — libuv's mapping of `FlushFileBuffers` on a directory
|
|
11
|
+
// handle, which Win32 rejects categorically. That is not a durability failure
|
|
12
|
+
// (NTFS journals the rename itself); the mechanism simply does not exist there.
|
|
13
|
+
//
|
|
14
|
+
// `atomic-file.fsyncDirSync` is where that decision lives, and it is deliberately
|
|
15
|
+
// narrow: degrade ONLY on win32 + EPERM at the fsync, keep throwing everywhere
|
|
16
|
+
// else. Re-implementing the open/fsync/close sequence inline re-creates the gap
|
|
17
|
+
// without the exception, and it fails on Windows and nowhere else — invisible to
|
|
18
|
+
// every local run, and behind CI's `--bail` it costs one full matrix round to
|
|
19
|
+
// surface. That is exactly how `tests/core/model-policy/store.test.ts` broke the
|
|
20
|
+
// Windows legs of the matrix while all four POSIX legs stayed green.
|
|
21
|
+
//
|
|
22
|
+
// So the rule is about the CALL, not about any one call site: a directory fd may
|
|
23
|
+
// be flushed only through `fsyncDirSync`. This scans `tests` as well as `src` —
|
|
24
|
+
// the regression that motivated it lived in a test double, and a guard that only
|
|
25
|
+
// watched `src` would have reported a clean bill of health.
|
|
26
|
+
const fs_1 = __importDefault(require("fs"));
|
|
27
|
+
const path_1 = __importDefault(require("path"));
|
|
28
|
+
const CLI = path_1.default.join(__dirname, '..', '..');
|
|
29
|
+
const ROOTS = ['src', 'tests'];
|
|
30
|
+
/** The single source of the policy: the one file allowed to flush a directory fd. */
|
|
31
|
+
const SINGLE_SOURCE = path_1.default.join('src', 'core', 'atomic-file.ts');
|
|
32
|
+
/** This guard itself, which must quote the forbidden shape to describe and test it. */
|
|
33
|
+
const THIS_GUARD = path_1.default.join('tests', 'structural', 'directory-fsync-is-single-source.test.ts');
|
|
34
|
+
function sourceFiles(dir) {
|
|
35
|
+
const out = [];
|
|
36
|
+
for (const entry of fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
37
|
+
const full = path_1.default.join(dir, entry.name);
|
|
38
|
+
if (entry.isDirectory())
|
|
39
|
+
out.push(...sourceFiles(full));
|
|
40
|
+
else if (entry.name.endsWith('.ts'))
|
|
41
|
+
out.push(full);
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
/** True when `lines[i]` opens something that reads as a directory. Deliberately
|
|
46
|
+
* shallow — it recognises the shapes this codebase actually writes. Something
|
|
47
|
+
* cleverer that defeats it should be calling `fsyncDirSync` instead. */
|
|
48
|
+
function opensADirectory(line) {
|
|
49
|
+
const open = /\bfs\.openSync\s*\(\s*([^,]+),/.exec(line);
|
|
50
|
+
if (!open)
|
|
51
|
+
return false;
|
|
52
|
+
const target = open[1];
|
|
53
|
+
return /\bpath\.dirname\s*\(|\bdirname\s*\(/.test(target) || /\b(dir|Dir|root|Root)\b|Dir\b/.test(target);
|
|
54
|
+
}
|
|
55
|
+
/** True when the fd opened at `lines[i]` is flushed within the next few lines. */
|
|
56
|
+
function flushedNearby(lines, i) {
|
|
57
|
+
return /\bfsyncSync\s*\(/.test(lines.slice(i, i + 4).join('\n'));
|
|
58
|
+
}
|
|
59
|
+
describe('directory fsync has exactly one implementation', () => {
|
|
60
|
+
it('no file outside atomic-file.ts opens a directory and flushes it inline', () => {
|
|
61
|
+
const offenders = [];
|
|
62
|
+
for (const root of ROOTS) {
|
|
63
|
+
for (const file of sourceFiles(path_1.default.join(CLI, root))) {
|
|
64
|
+
const relative = path_1.default.relative(CLI, file);
|
|
65
|
+
if (relative === SINGLE_SOURCE || relative === THIS_GUARD)
|
|
66
|
+
continue;
|
|
67
|
+
const lines = fs_1.default.readFileSync(file, 'utf-8').split('\n');
|
|
68
|
+
lines.forEach((line, i) => {
|
|
69
|
+
if (!opensADirectory(line) || !flushedNearby(lines, i))
|
|
70
|
+
return;
|
|
71
|
+
offenders.push(`${relative}:${i + 1}: ${line.trim()}`);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
expect(offenders).toEqual([]);
|
|
76
|
+
});
|
|
77
|
+
it('the guard actually rejects the shape that broke the Windows matrix', () => {
|
|
78
|
+
// Without this, a guard whose regex silently stopped matching would read as
|
|
79
|
+
// a clean bill of health forever — the failure mode of every structural test.
|
|
80
|
+
const rejects = (lines, i) => opensADirectory(lines[i]) && flushedNearby(lines, i);
|
|
81
|
+
// Verbatim shape of the store.test.ts regression this guard exists to stop.
|
|
82
|
+
const regression = [
|
|
83
|
+
'fs.renameSync(temporary, file);',
|
|
84
|
+
"const parent = fs.openSync(path.dirname(file), 'r');",
|
|
85
|
+
'try { fs.fsyncSync(parent); } finally { fs.closeSync(parent); }',
|
|
86
|
+
];
|
|
87
|
+
expect(rejects(regression, 1)).toBe(true);
|
|
88
|
+
// The sanctioned replacement carries no directory open at all.
|
|
89
|
+
expect(regression.map((_, i) => i).some(i => rejects(['fsyncDirSync(path.dirname(file));'], 0))).toBe(false);
|
|
90
|
+
// Flushing a FILE descriptor stays legal — that is a real, portable fsync.
|
|
91
|
+
const fileFlush = ["const fd = fs.openSync(temporary, 'wx', 0o600);", 'fs.fsyncSync(fd);'];
|
|
92
|
+
expect(rejects(fileFlush, 0)).toBe(false);
|
|
93
|
+
// Opening a directory without flushing it (readdir-style handles) stays legal.
|
|
94
|
+
const openOnly = ["const parent = fs.openSync(path.dirname(file), 'r');", 'fs.closeSync(parent);'];
|
|
95
|
+
expect(rejects(openOnly, 0)).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -6,44 +6,49 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const os_1 = __importDefault(require("os"));
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
function isWithin(parent, candidate, pathApi = path_1.default) {
|
|
10
|
+
const relative = pathApi.relative(parent, candidate);
|
|
11
|
+
return relative === '' || (relative !== '..' && !relative.startsWith(`..${pathApi.sep}`) && !pathApi.isAbsolute(relative));
|
|
12
|
+
}
|
|
9
13
|
describe('Jest environment isolation', () => {
|
|
14
|
+
it('treats a path on another volume as outside the operator home', () => {
|
|
15
|
+
expect(isWithin('C:\\operator-home', 'D:\\suite-root', path_1.default.win32)).toBe(false);
|
|
16
|
+
});
|
|
10
17
|
it('does not inherit the operator Codex home', () => {
|
|
11
18
|
expect(process.env.CODEX_HOME).toBeUndefined();
|
|
12
19
|
});
|
|
13
20
|
it('uses a suite-owned temporary directory', () => {
|
|
14
21
|
expect(os_1.default.tmpdir()).toContain('awm-jest-');
|
|
15
22
|
});
|
|
16
|
-
it('
|
|
23
|
+
it('routes every unscoped AWM write into the suite-owned temporary directory', () => {
|
|
24
|
+
expect(process.env.AWM_HOME).toBe(path_1.default.join(process.env.AWM_JEST_TMPDIR, 'awm-home'));
|
|
25
|
+
});
|
|
26
|
+
it('keeps the suite root and both homes outside the operator home', () => {
|
|
27
|
+
const suiteRoot = process.env.AWM_JEST_TMPDIR;
|
|
28
|
+
const operatorHome = fs_1.default.realpathSync(os_1.default.userInfo().homedir);
|
|
29
|
+
expect(isWithin(operatorHome, suiteRoot)).toBe(false);
|
|
30
|
+
expect(process.env.HOME).toBe(path_1.default.join(suiteRoot, 'home'));
|
|
31
|
+
expect(process.env.AWM_HOME).toBe(path_1.default.join(suiteRoot, 'awm-home'));
|
|
32
|
+
});
|
|
33
|
+
it('creates its physical root below the system temp directory, not the operator home', async () => {
|
|
17
34
|
const originalEnv = { ...process.env };
|
|
18
|
-
const
|
|
35
|
+
const systemTemp = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-jest-system-'));
|
|
36
|
+
const operatorHome = path_1.default.join(systemTemp, 'operator-home');
|
|
19
37
|
try {
|
|
38
|
+
fs_1.default.mkdirSync(operatorHome);
|
|
20
39
|
jest.resetModules();
|
|
21
40
|
jest.doMock('os', () => ({
|
|
22
41
|
...jest.requireActual('os'),
|
|
23
|
-
homedir: () =>
|
|
24
|
-
tmpdir: () =>
|
|
25
|
-
}));
|
|
26
|
-
const actualFs = jest.requireActual('fs');
|
|
27
|
-
jest.doMock('fs', () => ({
|
|
28
|
-
...actualFs,
|
|
29
|
-
mkdirSync: jest.fn((target, ...args) => {
|
|
30
|
-
if (String(target).includes('readonly-home')) {
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
33
|
-
return actualFs.mkdirSync(target, ...args);
|
|
34
|
-
}),
|
|
35
|
-
mkdtempSync: jest.fn((prefix, ...args) => {
|
|
36
|
-
if (prefix.includes('readonly-home')) {
|
|
37
|
-
const error = new Error('read-only');
|
|
38
|
-
error.code = 'EROFS';
|
|
39
|
-
throw error;
|
|
40
|
-
}
|
|
41
|
-
return actualFs.mkdtempSync(prefix, ...args);
|
|
42
|
-
}),
|
|
42
|
+
homedir: () => operatorHome,
|
|
43
|
+
tmpdir: () => systemTemp,
|
|
43
44
|
}));
|
|
44
45
|
const setup = require('../../jest.global-setup.js');
|
|
45
46
|
await expect(setup()).resolves.toBeUndefined();
|
|
46
|
-
|
|
47
|
+
const suiteRoot = process.env.AWM_JEST_TMPDIR;
|
|
48
|
+
expect(suiteRoot.startsWith(path_1.default.join(fs_1.default.realpathSync(systemTemp), 'awm-jest-'))).toBe(true);
|
|
49
|
+
expect(isWithin(operatorHome, suiteRoot)).toBe(false);
|
|
50
|
+
expect(process.env.HOME).toBe(path_1.default.join(suiteRoot, 'home'));
|
|
51
|
+
expect(process.env.AWM_HOME).toBe(path_1.default.join(suiteRoot, 'awm-home'));
|
|
47
52
|
}
|
|
48
53
|
finally {
|
|
49
54
|
jest.dontMock('fs');
|
|
@@ -52,7 +57,7 @@ describe('Jest environment isolation', () => {
|
|
|
52
57
|
for (const key of Object.keys(process.env))
|
|
53
58
|
delete process.env[key];
|
|
54
59
|
Object.assign(process.env, originalEnv);
|
|
55
|
-
fs_1.default.rmSync(
|
|
60
|
+
fs_1.default.rmSync(systemTemp, { recursive: true, force: true });
|
|
56
61
|
}
|
|
57
62
|
});
|
|
58
63
|
});
|
|
@@ -9,6 +9,22 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const CLI_ROOT = path_1.default.resolve(__dirname, '..', '..');
|
|
10
10
|
const REPO_ROOT = path_1.default.resolve(CLI_ROOT, '..');
|
|
11
11
|
describe('native release artifacts', () => {
|
|
12
|
+
it('checks Windows admission before full suites and stops a failed suite without weakening publication', () => {
|
|
13
|
+
for (const name of ['ci.yml', 'release.yml']) {
|
|
14
|
+
const workflow = fs_1.default.readFileSync(path_1.default.join(REPO_ROOT, '.github', 'workflows', name), 'utf8');
|
|
15
|
+
expect(workflow).toContain('- name: Windows admission smoke');
|
|
16
|
+
expect(workflow).toContain("if: runner.os == 'Windows'");
|
|
17
|
+
expect(workflow).toContain('run: npx jest tests/commands/plan/index.test.ts --runInBand --bail');
|
|
18
|
+
expect(workflow).toContain('run: npx jest --runInBand --bail');
|
|
19
|
+
expect(workflow.indexOf('- name: Windows admission smoke')).toBeLessThan(workflow.indexOf('run: npx jest --runInBand --bail'));
|
|
20
|
+
}
|
|
21
|
+
const release = fs_1.default.readFileSync(path_1.default.join(REPO_ROOT, '.github', 'workflows', 'release.yml'), 'utf8');
|
|
22
|
+
expect(release).toMatch(/release:\s*\n\s*needs: test/);
|
|
23
|
+
for (const target of ['linux-x64', 'linux-arm64', 'darwin-x64', 'darwin-arm64', 'win32-x64', 'win32-arm64']) {
|
|
24
|
+
expect(release).toContain(`target: ${target}`);
|
|
25
|
+
}
|
|
26
|
+
expect(release).toContain('cancel-in-progress: false');
|
|
27
|
+
});
|
|
12
28
|
it('keeps native prebuilds generated instead of versioned source', () => {
|
|
13
29
|
const gitignore = fs_1.default.readFileSync(path_1.default.join(REPO_ROOT, '.gitignore'), 'utf8');
|
|
14
30
|
const tracked = (0, child_process_1.execFileSync)('git', ['ls-files', '--', 'cli/prebuilds'], {
|
|
@@ -19,4 +35,18 @@ describe('native release artifacts', () => {
|
|
|
19
35
|
expect(gitignore).toContain('cli/native-artifacts/');
|
|
20
36
|
expect(tracked).toBe('');
|
|
21
37
|
});
|
|
38
|
+
it('builds the fault-injection addon before every Jest suite without publishing it', () => {
|
|
39
|
+
const pkg = JSON.parse(fs_1.default.readFileSync(path_1.default.join(CLI_ROOT, 'package.json'), 'utf8'));
|
|
40
|
+
expect(pkg.scripts['native:test-build']).toContain('secure_fs_test');
|
|
41
|
+
for (const name of ['ci.yml', 'release.yml']) {
|
|
42
|
+
const workflow = fs_1.default.readFileSync(path_1.default.join(REPO_ROOT, '.github', 'workflows', name), 'utf8');
|
|
43
|
+
const testBuild = workflow.indexOf('run: npm run native:test-build');
|
|
44
|
+
const jest = workflow.indexOf('run: npx jest --runInBand --bail');
|
|
45
|
+
expect(testBuild).toBeGreaterThanOrEqual(0);
|
|
46
|
+
expect(testBuild).toBeLessThan(jest);
|
|
47
|
+
expect(workflow).toContain("'native/build/Release', 'secure_fs_test.node'");
|
|
48
|
+
expect(workflow).not.toContain('path: cli/prebuilds/${{ matrix.target }}/secure_fs_test.node');
|
|
49
|
+
expect(workflow).not.toContain('secure_fs_test.node\n');
|
|
50
|
+
}
|
|
51
|
+
});
|
|
22
52
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-workflow-manager",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.9.0",
|
|
4
4
|
"main": "dist/src/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"awm": "./dist/src/index.js"
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"doc": "docs"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"native:build": "node-gyp
|
|
21
|
+
"native:build": "node-gyp configure --directory native && node-gyp build --directory native -- secure_fs && node scripts/package-native.js",
|
|
22
|
+
"native:test-build": "node-gyp configure --directory native && node-gyp build --directory native -- secure_fs_test",
|
|
22
23
|
"native:package-check": "node scripts/assert-native-package.js",
|
|
23
24
|
"build": "tsc && chmod +x dist/src/index.js",
|
|
24
25
|
"typecheck": "tsc --noEmit",
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
},
|
|
48
49
|
"description": "CLI to manage Agentic Workflows - install skills, workflows, and processes for AI agents",
|
|
49
50
|
"dependencies": {
|
|
50
|
-
"@clack/prompts": "^
|
|
51
|
+
"@clack/prompts": "^0.11.0",
|
|
51
52
|
"commander": "^14.0.3",
|
|
52
53
|
"picocolors": "^1.1.1",
|
|
53
54
|
"semver": "^7.7.4",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|