agentic-workflow-manager 9.15.0 → 9.15.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/dist/src/commands/watch/index.js +10 -0
- package/dist/src/core/admission/index.js +8 -3
- package/dist/src/core/journal/durable-custody.js +19 -0
- package/dist/tests/core/admission/index.test.js +19 -0
- package/dist/tests/core/journal/durable-custody.test.js +44 -0
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/secure_fs.node +0 -0
- package/prebuilds/darwin-x64/secure_fs.node +0 -0
- package/prebuilds/win32-arm64/secure_fs.node +0 -0
- package/prebuilds/win32-x64/secure_fs.node +0 -0
|
@@ -13,6 +13,7 @@ const capabilities_1 = require("../../core/model-policy/capabilities");
|
|
|
13
13
|
const adapter_1 = require("../../core/journal/adapter");
|
|
14
14
|
const process_1 = require("../../core/journal/process");
|
|
15
15
|
const adapter_2 = require("../../core/journal/adapter");
|
|
16
|
+
const durable_custody_1 = require("../../core/journal/durable-custody");
|
|
16
17
|
const context_1 = require("../../core/tracks/context");
|
|
17
18
|
const concurrency_1 = require("../../core/tracks/concurrency");
|
|
18
19
|
const validate_1 = require("../../core/plan/validate");
|
|
@@ -20,6 +21,12 @@ const path_1 = __importDefault(require("path"));
|
|
|
20
21
|
const archive_unused_1 = require("./archive-unused");
|
|
21
22
|
const store_1 = require("../../core/journal/store");
|
|
22
23
|
const fingerprint_1 = require("../../core/journal/fingerprint");
|
|
24
|
+
function refuseIfDurableCustodySuspended() {
|
|
25
|
+
if (!(0, durable_custody_1.isDurableCustodySuspended)())
|
|
26
|
+
return;
|
|
27
|
+
process.stderr.write(`${durable_custody_1.DURABLE_CUSTODY_SUSPENDED_MESSAGE}\n`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
23
30
|
function currentBranch(cwd) {
|
|
24
31
|
// stdio explicito (ver EXEC_STDIO en journal/process.ts): evita el relay
|
|
25
32
|
// default de execFileSync del stderr de git hacia el stderr del llamante,
|
|
@@ -61,6 +68,9 @@ function registerWatchCommand(program) {
|
|
|
61
68
|
// #168: sin esto el controller desatendido arranca y se cuelga en la
|
|
62
69
|
// primera herramienta pidiendo aprobación. Se declara, no se adivina.
|
|
63
70
|
.option('--controller-autonomy <postura>', `postura del controller desatendido (${adapter_1.CONTROLLER_AUTONOMIES.join(' | ')})`)
|
|
71
|
+
// Fail-closed for every watch verb (parent + subcommands) while durable
|
|
72
|
+
// custody is suspended. Help still works; only actions are refused.
|
|
73
|
+
.hook('preAction', () => { refuseIfDurableCustodySuspended(); })
|
|
64
74
|
.action(async (opts) => {
|
|
65
75
|
const repo = process.cwd();
|
|
66
76
|
const branch = currentBranch(repo);
|
|
@@ -6,6 +6,7 @@ exports.sanitizeAdmissionReport = sanitizeAdmissionReport;
|
|
|
6
6
|
exports.admitPlan = admitPlan;
|
|
7
7
|
const providers_1 = require("../../providers");
|
|
8
8
|
const paths_1 = require("../journal/paths");
|
|
9
|
+
const durable_custody_1 = require("../journal/durable-custody");
|
|
9
10
|
const resolve_1 = require("../model-policy/resolve");
|
|
10
11
|
const capabilities_1 = require("../model-policy/capabilities");
|
|
11
12
|
const UNKNOWN = {
|
|
@@ -242,10 +243,14 @@ async function admitPlan(input) {
|
|
|
242
243
|
// The durable controller (journal + awm watch + jobs) is opt-in, as it
|
|
243
244
|
// was before 9.8.0: native v1 dispatch with no journal on its branch
|
|
244
245
|
// runs as one provider session. Creating a journal is the opt-in, and
|
|
245
|
-
// from then on it must be current.
|
|
246
|
-
//
|
|
246
|
+
// from then on it must be current. While durable custody is suspended
|
|
247
|
+
// (see durable-custody.ts), leftover journals must not trap native v1
|
|
248
|
+
// unattended work. v2 routing custody lives in the journal, so
|
|
249
|
+
// awm-routed work still requires it when that path is active.
|
|
247
250
|
const observed = journalStatus(input, plan);
|
|
248
|
-
const journal =
|
|
251
|
+
const journal = plan.schema === 'compact-slices/v1' && (observed === 'missing' || (0, durable_custody_1.isDurableCustodySuspended)())
|
|
252
|
+
? 'not-required'
|
|
253
|
+
: observed;
|
|
249
254
|
if (journal !== 'current' && journal !== 'not-required')
|
|
250
255
|
return blocked(input, [diagnostic('ADMISSION_JOURNAL_BINDING_REQUIRED', 'Unattended execution requires a healthy schema-2 journal binding for this exact plan; run watch --init --plan.')], { planDigest: plan.planDigest, provider, executionMode: mode, journal, currentness: input.requireCurrent ? 'current' : 'not-checked', cliCurrentness, sensors: sensorsReported, ...sensorEvidence });
|
|
251
256
|
const capabilities = unattendedCapabilities(provider, input.controllerAutonomy);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Durable custody = `awm watch` + journal-bound supervisor/controller relaunch.
|
|
4
|
+
*
|
|
5
|
+
* Suspended for every provider until routing/custody work resumes. The supported
|
|
6
|
+
* unattended path is the native provider session (compact-slices/v1, no journal).
|
|
7
|
+
*
|
|
8
|
+
* The Jest suite sets `AWM_ALLOW_DURABLE_CUSTODY=1` so the machinery stays tested
|
|
9
|
+
* for when this suspension is lifted. Operators never set that variable.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DURABLE_CUSTODY_SUSPENDED_MESSAGE = void 0;
|
|
13
|
+
exports.isDurableCustodySuspended = isDurableCustodySuspended;
|
|
14
|
+
exports.DURABLE_CUSTODY_SUSPENDED_MESSAGE = 'Durable custody (awm watch) is suspended for all providers until routing/custody work resumes. '
|
|
15
|
+
+ 'Use native provider-session unattended (compact-slices/v1, no journal).';
|
|
16
|
+
/** True for operators; false only when tests explicitly re-enable the machinery. */
|
|
17
|
+
function isDurableCustodySuspended() {
|
|
18
|
+
return process.env.AWM_ALLOW_DURABLE_CUSTODY !== '1';
|
|
19
|
+
}
|
|
@@ -177,6 +177,25 @@ describe('admitPlan', () => {
|
|
|
177
177
|
expect(report.state).toBe('blocked');
|
|
178
178
|
expect(report.diagnostics[0]).toMatchObject({ code: 'ADMISSION_CONTROLLER_AUTONOMY_REQUIRED' });
|
|
179
179
|
});
|
|
180
|
+
// While Camino B is suspended, a leftover journal on the branch must not
|
|
181
|
+
// trap native v1 unattended admission. Jest sets AWM_ALLOW_DURABLE_CUSTODY=1
|
|
182
|
+
// for the rest of the suite; this case restores the operator default.
|
|
183
|
+
it('ignores leftover journals for native v1 while durable custody is suspended', async () => {
|
|
184
|
+
const previous = process.env.AWM_ALLOW_DURABLE_CUSTODY;
|
|
185
|
+
delete process.env.AWM_ALLOW_DURABLE_CUSTODY;
|
|
186
|
+
try {
|
|
187
|
+
const corrupt = await (0, admission_1.admitPlan)({ ...base(), journalCorrupt: true });
|
|
188
|
+
expect(corrupt).toMatchObject({ state: 'admitted', executionMode: 'desatendido', journal: 'not-required' });
|
|
189
|
+
const stale = await (0, admission_1.admitPlan)({ ...base(), journalState: { ...(0, types_1.emptyState)('main'), schema: 2, planBinding: { path: 'docs/plan.md', digest: 'b'.repeat(64), schema: 'compact-slices/v1', executionMode: 'desatendido', boundAt: '2026-09-15T00:00:00.000Z' } } });
|
|
190
|
+
expect(stale).toMatchObject({ state: 'admitted', journal: 'not-required' });
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
if (previous === undefined)
|
|
194
|
+
delete process.env.AWM_ALLOW_DURABLE_CUSTODY;
|
|
195
|
+
else
|
|
196
|
+
process.env.AWM_ALLOW_DURABLE_CUSTODY = previous;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
180
199
|
});
|
|
181
200
|
// R8: a content registry whose sensors are ALL deliberately disabled may close
|
|
182
201
|
// work; its release proof lives in CI. The local verdict stays not-certified —
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const durable_custody_1 = require("../../../src/core/journal/durable-custody");
|
|
5
|
+
const watch_1 = require("../../../src/commands/watch");
|
|
6
|
+
describe('durable custody suspension', () => {
|
|
7
|
+
const original = process.env.AWM_ALLOW_DURABLE_CUSTODY;
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
if (original === undefined)
|
|
10
|
+
delete process.env.AWM_ALLOW_DURABLE_CUSTODY;
|
|
11
|
+
else
|
|
12
|
+
process.env.AWM_ALLOW_DURABLE_CUSTODY = original;
|
|
13
|
+
});
|
|
14
|
+
it('is suspended for operators (env unset) and only re-enabled by the Jest harness', () => {
|
|
15
|
+
delete process.env.AWM_ALLOW_DURABLE_CUSTODY;
|
|
16
|
+
expect((0, durable_custody_1.isDurableCustodySuspended)()).toBe(true);
|
|
17
|
+
process.env.AWM_ALLOW_DURABLE_CUSTODY = '0';
|
|
18
|
+
expect((0, durable_custody_1.isDurableCustodySuspended)()).toBe(true);
|
|
19
|
+
process.env.AWM_ALLOW_DURABLE_CUSTODY = '1';
|
|
20
|
+
expect((0, durable_custody_1.isDurableCustodySuspended)()).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
it('refuses every awm watch entry point while suspended', async () => {
|
|
23
|
+
delete process.env.AWM_ALLOW_DURABLE_CUSTODY;
|
|
24
|
+
const program = new commander_1.Command();
|
|
25
|
+
(0, watch_1.registerWatchCommand)(program);
|
|
26
|
+
const err = [];
|
|
27
|
+
const exit = jest.spyOn(process, 'exit').mockImplementation(((code) => {
|
|
28
|
+
throw Object.assign(new Error(`exit:${code ?? 0}`), { code });
|
|
29
|
+
}));
|
|
30
|
+
program.configureOutput({ writeErr: (s) => { err.push(String(s)); } });
|
|
31
|
+
// stderr write in the refusal helper bypasses configureOutput; capture it too.
|
|
32
|
+
const stderr = jest.spyOn(process.stderr, 'write').mockImplementation(((chunk) => {
|
|
33
|
+
err.push(String(chunk));
|
|
34
|
+
return true;
|
|
35
|
+
}));
|
|
36
|
+
await expect(program.parseAsync(['node', 'awm', 'watch', 'journal-status'])).rejects.toThrow(/exit:1/);
|
|
37
|
+
expect(err.join('')).toContain(durable_custody_1.DURABLE_CUSTODY_SUSPENDED_MESSAGE);
|
|
38
|
+
err.length = 0;
|
|
39
|
+
await expect(program.parseAsync(['node', 'awm', 'watch', '--init', '--plan', 'docs/plan.md'])).rejects.toThrow(/exit:1/);
|
|
40
|
+
expect(err.join('')).toContain(durable_custody_1.DURABLE_CUSTODY_SUSPENDED_MESSAGE);
|
|
41
|
+
exit.mockRestore();
|
|
42
|
+
stderr.mockRestore();
|
|
43
|
+
});
|
|
44
|
+
});
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|