agentic-workflow-manager 9.13.2 → 9.14.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/src/core/admission/index.js +8 -2
- package/dist/tests/commands/plan/index.test.js +6 -2
- package/dist/tests/core/admission/index.test.js +34 -6
- 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
|
@@ -233,8 +233,14 @@ async function admitPlan(input) {
|
|
|
233
233
|
return blocked(input, [diagnostic('ADMISSION_SENSORS_BLOCKED', `Sensor verdict is ${sensors}.`)], { planDigest: plan.planDigest, provider, executionMode: mode, currentness: input.requireCurrent ? 'current' : 'not-checked', cliCurrentness, sensors });
|
|
234
234
|
}
|
|
235
235
|
if (mode === 'desatendido') {
|
|
236
|
-
|
|
237
|
-
|
|
236
|
+
// The durable controller (journal + awm watch + jobs) is opt-in, as it
|
|
237
|
+
// was before 9.8.0: native v1 dispatch with no journal on its branch
|
|
238
|
+
// runs as one provider session. Creating a journal is the opt-in, and
|
|
239
|
+
// from then on it must be current. v2 routing custody lives in the
|
|
240
|
+
// journal, so awm-routed work still requires it.
|
|
241
|
+
const observed = journalStatus(input, plan);
|
|
242
|
+
const journal = observed === 'missing' && plan.schema === 'compact-slices/v1' ? 'not-required' : observed;
|
|
243
|
+
if (journal !== 'current' && journal !== 'not-required')
|
|
238
244
|
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: input.verifySensors ? 'pass' : 'not-required' });
|
|
239
245
|
const capabilities = unattendedCapabilities(provider, input.controllerAutonomy);
|
|
240
246
|
const resolution = { outcome: capabilities.unattendedController === 'supported' ? 'native' : 'blocked', provider, capabilities, evidenceVersion: 'r1-v1', diagnostics: [] };
|
|
@@ -309,7 +309,7 @@ describe('plan admit Commander wiring', () => {
|
|
|
309
309
|
process.exitCode = undefined;
|
|
310
310
|
}
|
|
311
311
|
});
|
|
312
|
-
it('derives desatendido from the canonical plan header
|
|
312
|
+
it('derives desatendido from the canonical plan header; a native v1 plan needs no journal (opt-in durable custody)', async () => {
|
|
313
313
|
const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-admit-header-'));
|
|
314
314
|
const output = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
315
315
|
try {
|
|
@@ -327,7 +327,11 @@ describe('plan admit Commander wiring', () => {
|
|
|
327
327
|
readPreferences: () => ({ defaultAgent: 'codex', enabledAgents: ['codex'], installMethod: 'symlink', defaultScope: 'local' }),
|
|
328
328
|
});
|
|
329
329
|
await program.parseAsync(['node', 'awm', 'plan', 'admit', 'plan.md', '--provider', 'codex', '--cwd', root, '--json']);
|
|
330
|
-
|
|
330
|
+
const withoutPosture = JSON.parse(String(output.mock.calls[0][0]));
|
|
331
|
+
expect(withoutPosture).toMatchObject({ state: 'blocked', executionMode: 'desatendido', journal: 'not-required' });
|
|
332
|
+
expect(withoutPosture.diagnostics[0]).toMatchObject({ code: 'ADMISSION_CONTROLLER_AUTONOMY_REQUIRED' });
|
|
333
|
+
await program.parseAsync(['node', 'awm', 'plan', 'admit', 'plan.md', '--provider', 'codex', '--cwd', root, '--controller-autonomy', 'approval-free', '--json']);
|
|
334
|
+
expect(JSON.parse(String(output.mock.calls[1][0]))).toMatchObject({ state: 'admitted', executionMode: 'desatendido', journal: 'not-required' });
|
|
331
335
|
}
|
|
332
336
|
finally {
|
|
333
337
|
output.mockRestore();
|
|
@@ -143,12 +143,40 @@ describe('admitPlan', () => {
|
|
|
143
143
|
expect(report).toMatchObject({ state: 'blocked', executionMode: 'interactivo', provider: 'cursor', journal: 'not-required' });
|
|
144
144
|
expect(report.diagnostics[0].code).toBe('ADMISSION_CAPABILITY_UNVERIFIED');
|
|
145
145
|
});
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
// The durable controller (journal + awm watch + jobs) is opt-in again for
|
|
147
|
+
// native v1 dispatch, as it was before 9.8.0: a v1 unattended plan with no
|
|
148
|
+
// journal on its branch runs as one native provider session. Creating a
|
|
149
|
+
// journal (awm watch --init) is the opt-in, after which it must be current.
|
|
150
|
+
// v2 routing custody lives in the journal, so awm-routed still requires it.
|
|
151
|
+
describe('the durable journal is opt-in for native v1 unattended work', () => {
|
|
152
|
+
const unattended = () => ({ ...valid, manifest: { ...valid.manifest, executionMode: 'desatendido' } });
|
|
153
|
+
const base = () => ({ plan: unattended(), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], planPath: 'docs/plan.md', controllerAutonomy: 'approval-free' });
|
|
154
|
+
it('admits a v1 unattended plan with no journal as journal not-required', async () => {
|
|
155
|
+
const report = await (0, admission_1.admitPlan)(base());
|
|
156
|
+
expect(report).toMatchObject({ state: 'admitted', executionMode: 'desatendido', journal: 'not-required' });
|
|
157
|
+
expect(report.diagnostics.map(d => d.code)).not.toContain('ADMISSION_JOURNAL_BINDING_REQUIRED');
|
|
158
|
+
});
|
|
159
|
+
it('keeps a journal that exists (the opt-in) fail-closed when it is corrupt or stale', async () => {
|
|
160
|
+
const corrupt = await (0, admission_1.admitPlan)({ ...base(), journalCorrupt: true });
|
|
161
|
+
expect(corrupt).toMatchObject({ state: 'blocked', journal: 'corrupt' });
|
|
162
|
+
expect(corrupt.diagnostics[0]).toMatchObject({ code: 'ADMISSION_JOURNAL_BINDING_REQUIRED' });
|
|
163
|
+
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' } } });
|
|
164
|
+
expect(stale).toMatchObject({ state: 'blocked', journal: 'stale' });
|
|
165
|
+
const legacy = await (0, admission_1.admitPlan)({ ...base(), journalState: (0, types_1.emptyState)('main') });
|
|
166
|
+
expect(legacy).toMatchObject({ state: 'blocked', journal: 'stale' });
|
|
167
|
+
});
|
|
168
|
+
it('still requires the journal for awm-routed v2 unattended work', async () => {
|
|
169
|
+
const v2Unattended = { ...valid, schema: 'compact-slices/v2', manifest: { ...valid.manifest, executionMode: 'desatendido', schema: 'compact-slices/v2', slices: valid.manifest.slices.map(slice => ({ ...slice, implementerProfile: 'mechanical' })) } };
|
|
170
|
+
const report = await (0, admission_1.admitPlan)({ ...base(), plan: v2Unattended });
|
|
171
|
+
expect(report).toMatchObject({ state: 'blocked', executionMode: 'desatendido', journal: 'missing' });
|
|
172
|
+
expect(report.diagnostics[0]).toMatchObject({ code: 'ADMISSION_JOURNAL_BINDING_REQUIRED' });
|
|
173
|
+
expect(report.forecast).toBeUndefined();
|
|
174
|
+
});
|
|
175
|
+
it('keeps the controller posture gate for journal-less unattended work', async () => {
|
|
176
|
+
const report = await (0, admission_1.admitPlan)({ ...base(), controllerAutonomy: undefined });
|
|
177
|
+
expect(report.state).toBe('blocked');
|
|
178
|
+
expect(report.diagnostics[0]).toMatchObject({ code: 'ADMISSION_CONTROLLER_AUTONOMY_REQUIRED' });
|
|
179
|
+
});
|
|
152
180
|
});
|
|
153
181
|
it('admits unattended work only with an exact schema-2 plan binding', async () => {
|
|
154
182
|
const unattended = { ...valid, manifest: { ...valid.manifest, executionMode: 'desatendido' } };
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|