agentic-workflow-manager 9.15.1 → 9.16.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 +4 -1
- package/dist/src/providers/index.js +9 -0
- package/dist/tests/commands/init.test.js +4 -0
- package/dist/tests/core/admission/index.test.js +26 -4
- package/dist/tests/core/journal/controller-autonomy.test.js +9 -2
- package/dist/tests/core/provider-version.test.js +20 -0
- package/dist/tests/providers/index.test.js +8 -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
|
@@ -25,7 +25,10 @@ exports.PROVIDER_EXECUTION_CAPABILITIES = {
|
|
|
25
25
|
opencode: { ...UNKNOWN },
|
|
26
26
|
'claude-code': { ...UNKNOWN, interactiveExecution: 'supported', unattendedController: 'supported', durableResume: 'supported' },
|
|
27
27
|
codex: { ...UNKNOWN, interactiveExecution: 'supported', unattendedController: 'supported', durableResume: 'supported' },
|
|
28
|
-
|
|
28
|
+
// Plan C (native session only): interactive + journal-less unattended v1.
|
|
29
|
+
// durableResume stays unverified — Camino B / awm watch is suspended (D-023)
|
|
30
|
+
// and Cursor is not in WATCH_PROVIDERS. Evidence: docs/testing/cursor-execution-evidence.md
|
|
31
|
+
cursor: { ...UNKNOWN, interactiveExecution: 'supported', unattendedController: 'supported' },
|
|
29
32
|
copilot: { ...UNKNOWN },
|
|
30
33
|
};
|
|
31
34
|
/** #168: the controller can only act if it was launched with an autonomy
|
|
@@ -163,6 +163,15 @@ function providers() {
|
|
|
163
163
|
cursor: {
|
|
164
164
|
label: 'Cursor',
|
|
165
165
|
configHome: configHomeFor('cursor'),
|
|
166
|
+
// Date-based CLI line (YYYY.MM.DD-<hash>). compareSemver orders the
|
|
167
|
+
// date triple as [YYYY, M, D]. Floor from owner-machine capture
|
|
168
|
+
// 2026.09.26-dd393fe (docs/testing/cursor-execution-evidence.md).
|
|
169
|
+
minimumVersion: '2026.09.26',
|
|
170
|
+
versionCommand: {
|
|
171
|
+
command: 'agent',
|
|
172
|
+
args: ['--version'],
|
|
173
|
+
versionPattern: /^(\d{4}\.\d{2}\.\d{2})-[0-9a-f]+$/,
|
|
174
|
+
},
|
|
166
175
|
// Skills join the Codex/OpenCode shared physical dirs (~/.agents/skills +
|
|
167
176
|
// .agents/skills, renderer link). cursor-mdc remains registered for S3
|
|
168
177
|
// migration reads of historical ~/.cursor/rules installs.
|
|
@@ -434,6 +434,10 @@ describe('runInit', () => {
|
|
|
434
434
|
agent: 'cursor',
|
|
435
435
|
yes: true,
|
|
436
436
|
machineOnly: true,
|
|
437
|
+
// Plan C adds a Cursor version gate; CI has no `agent` binary.
|
|
438
|
+
// Stub the same way Codex init tests do — the gate itself is
|
|
439
|
+
// covered in provider-version.test.ts.
|
|
440
|
+
assertProviderSupported: () => ({ provider: 'cursor', version: '2026.09.26' }),
|
|
437
441
|
// seedBaselineRegistry() writes registries.json pointing at 'baseline'
|
|
438
442
|
// (our manually-seeded content root above) since none exists yet — no
|
|
439
443
|
// real network clone happens because that content root already exists
|
|
@@ -27,7 +27,7 @@ describe('admitPlan', () => {
|
|
|
27
27
|
});
|
|
28
28
|
it.each([
|
|
29
29
|
['journal', { provider: 'codex', executionMode: 'desatendido' }],
|
|
30
|
-
['provider capability', { provider: '
|
|
30
|
+
['provider capability', { provider: 'copilot', executionMode: 'interactivo' }],
|
|
31
31
|
])('does not invoke deferred v2 routing facts when %s gate blocks', async (_name, fields) => {
|
|
32
32
|
const reader = jest.fn(() => { throw new Error('routing reader must not run'); });
|
|
33
33
|
const report = await (0, admission_1.admitPlan)({ plan: v2(), cwd: process.cwd(), enabledAgents: [fields.provider], routingReader: reader, ...fields });
|
|
@@ -139,10 +139,32 @@ describe('admitPlan', () => {
|
|
|
139
139
|
expect(report.currentness).toBe('not-checked');
|
|
140
140
|
});
|
|
141
141
|
it('does not let an unverified execution capability admit interactive work', async () => {
|
|
142
|
-
const report = await (0, admission_1.admitPlan)({ plan: valid, provider: '
|
|
143
|
-
expect(report).toMatchObject({ state: 'blocked', executionMode: 'interactivo', provider: '
|
|
142
|
+
const report = await (0, admission_1.admitPlan)({ plan: valid, provider: 'copilot', cwd: process.cwd(), enabledAgents: ['copilot'] });
|
|
143
|
+
expect(report).toMatchObject({ state: 'blocked', executionMode: 'interactivo', provider: 'copilot', journal: 'not-required' });
|
|
144
144
|
expect(report.diagnostics[0].code).toBe('ADMISSION_CAPABILITY_UNVERIFIED');
|
|
145
145
|
});
|
|
146
|
+
it('admits Cursor interactive work once Plan C marks interactiveExecution supported', async () => {
|
|
147
|
+
const report = await (0, admission_1.admitPlan)({ plan: valid, provider: 'cursor', cwd: process.cwd(), enabledAgents: ['cursor'] });
|
|
148
|
+
expect(report).toMatchObject({ state: 'admitted', executionMode: 'interactivo', provider: 'cursor', journal: 'not-required' });
|
|
149
|
+
expect(report.capabilityResolution).toMatchObject({ outcome: 'native', capabilities: { interactiveExecution: 'supported' } });
|
|
150
|
+
});
|
|
151
|
+
it('admits Cursor journal-less unattended v1 with an explicit autonomy posture', async () => {
|
|
152
|
+
const unattended = { ...valid, manifest: { ...valid.manifest, executionMode: 'desatendido' } };
|
|
153
|
+
const report = await (0, admission_1.admitPlan)({
|
|
154
|
+
plan: unattended, provider: 'cursor', cwd: process.cwd(), enabledAgents: ['cursor'],
|
|
155
|
+
planPath: 'docs/plan.md', controllerAutonomy: 'approval-free',
|
|
156
|
+
});
|
|
157
|
+
expect(report).toMatchObject({ state: 'admitted', executionMode: 'desatendido', provider: 'cursor', journal: 'not-required' });
|
|
158
|
+
expect(report.capabilityResolution).toMatchObject({ outcome: 'native', capabilities: { unattendedController: 'supported' } });
|
|
159
|
+
});
|
|
160
|
+
it('still requires the autonomy posture for Cursor unattended work', async () => {
|
|
161
|
+
const unattended = { ...valid, manifest: { ...valid.manifest, executionMode: 'desatendido' } };
|
|
162
|
+
const report = await (0, admission_1.admitPlan)({
|
|
163
|
+
plan: unattended, provider: 'cursor', cwd: process.cwd(), enabledAgents: ['cursor'], planPath: 'docs/plan.md',
|
|
164
|
+
});
|
|
165
|
+
expect(report.state).toBe('blocked');
|
|
166
|
+
expect(report.diagnostics[0]).toMatchObject({ code: 'ADMISSION_CONTROLLER_AUTONOMY_REQUIRED' });
|
|
167
|
+
});
|
|
146
168
|
// The durable controller (journal + awm watch + jobs) is opt-in again for
|
|
147
169
|
// native v1 dispatch, as it was before 9.8.0: a v1 unattended plan with no
|
|
148
170
|
// journal on its branch runs as one native provider session. Creating a
|
|
@@ -266,7 +288,7 @@ describe('admitPlan', () => {
|
|
|
266
288
|
expect(report.state).toBe('admitted');
|
|
267
289
|
});
|
|
268
290
|
it('keeps the original diagnostic for a provider that never had the capability', async () => {
|
|
269
|
-
const report = await (0, admission_1.admitPlan)({ plan: unattended(), provider: '
|
|
291
|
+
const report = await (0, admission_1.admitPlan)({ plan: unattended(), provider: 'copilot', cwd: process.cwd(), enabledAgents: ['copilot'], journalState: journal(), planPath: 'docs/plan.md', controllerAutonomy: 'approval-free' });
|
|
270
292
|
expect(report.state).toBe('blocked');
|
|
271
293
|
expect(report.diagnostics[0]).toMatchObject({ code: 'ADMISSION_CAPABILITY_UNVERIFIED' });
|
|
272
294
|
});
|
|
@@ -58,8 +58,15 @@ describe('unattendedController stops being asserted for free (#168)', () => {
|
|
|
58
58
|
expect((0, admission_1.unattendedCapabilities)('claude-code', 'approval-free').unattendedController).toBe('supported');
|
|
59
59
|
});
|
|
60
60
|
test('never promotes a provider that never had the capability', () => {
|
|
61
|
-
expect(admission_1.PROVIDER_EXECUTION_CAPABILITIES.
|
|
62
|
-
expect((0, admission_1.unattendedCapabilities)('
|
|
61
|
+
expect(admission_1.PROVIDER_EXECUTION_CAPABILITIES.copilot.unattendedController).toBe('unverified');
|
|
62
|
+
expect((0, admission_1.unattendedCapabilities)('copilot', 'approval-free').unattendedController).toBe('unverified');
|
|
63
|
+
});
|
|
64
|
+
test('Cursor gains unattendedController only with a declared posture (Plan C)', () => {
|
|
65
|
+
expect(admission_1.PROVIDER_EXECUTION_CAPABILITIES.cursor.unattendedController).toBe('supported');
|
|
66
|
+
expect((0, admission_1.unattendedCapabilities)('cursor', undefined).unattendedController).toBe('unverified');
|
|
67
|
+
expect((0, admission_1.unattendedCapabilities)('cursor', 'approval-free').unattendedController).toBe('supported');
|
|
68
|
+
// Watch/custody resume is still unverified and suspended (D-023).
|
|
69
|
+
expect(admission_1.PROVIDER_EXECUTION_CAPABILITIES.cursor.durableResume).toBe('unverified');
|
|
63
70
|
});
|
|
64
71
|
});
|
|
65
72
|
describe('awm watch surfaces the posture on the compiled binary (#168)', () => {
|
|
@@ -75,6 +75,26 @@ describe('assertProviderSupported', () => {
|
|
|
75
75
|
});
|
|
76
76
|
expect(exec).not.toHaveBeenCalled();
|
|
77
77
|
});
|
|
78
|
+
it('accepts the Cursor date-based agent line (Plan C)', () => {
|
|
79
|
+
const exec = jest.fn(() => Buffer.from('2026.09.26-dd393fe\n'));
|
|
80
|
+
expect((0, provider_version_1.assertProviderSupported)('cursor', exec)).toEqual({
|
|
81
|
+
provider: 'cursor',
|
|
82
|
+
version: '2026.09.26',
|
|
83
|
+
});
|
|
84
|
+
expect(exec).toHaveBeenCalledWith('agent', ['--version'], expect.any(Object));
|
|
85
|
+
});
|
|
86
|
+
it.each([
|
|
87
|
+
[Buffer.from('2026.09.25-abc1234\n'), 'requires Cursor >= 2026.09.26'],
|
|
88
|
+
[Buffer.from('2026.09.26\n'), 'could not parse Cursor version'],
|
|
89
|
+
[Buffer.from('v2026.09.26-dd393fe\n'), 'could not parse Cursor version'],
|
|
90
|
+
])('rejects unsupported Cursor output without mutation', (output, message) => {
|
|
91
|
+
expect(() => (0, provider_version_1.assertProviderSupported)('cursor', () => output)).toThrow(message);
|
|
92
|
+
});
|
|
93
|
+
it('reports a missing Cursor agent binary distinctly', () => {
|
|
94
|
+
const missing = Object.assign(new Error('spawnSync agent ENOENT'), { code: 'ENOENT' });
|
|
95
|
+
expect(() => (0, provider_version_1.assertProviderSupported)('cursor', () => { throw missing; }))
|
|
96
|
+
.toThrow('Cursor is not installed or not available on PATH');
|
|
97
|
+
});
|
|
78
98
|
it('reports a missing Codex binary distinctly', () => {
|
|
79
99
|
const missing = Object.assign(new Error('spawnSync codex ENOENT'), { code: 'ENOENT' });
|
|
80
100
|
expect(() => (0, provider_version_1.assertProviderSupported)('codex', () => { throw missing; }))
|
|
@@ -210,6 +210,14 @@ describe('Providers Routing', () => {
|
|
|
210
210
|
});
|
|
211
211
|
expect((0, providers_1.providerFor)('copilot').hooks).toBeUndefined();
|
|
212
212
|
});
|
|
213
|
+
it('declares Cursor agent version gate (Plan C R26)', () => {
|
|
214
|
+
expect((0, providers_1.providerFor)('cursor').minimumVersion).toBe('2026.09.26');
|
|
215
|
+
expect((0, providers_1.providerFor)('cursor').versionCommand).toEqual({
|
|
216
|
+
command: 'agent',
|
|
217
|
+
args: ['--version'],
|
|
218
|
+
versionPattern: /^(\d{4}\.\d{2}\.\d{2})-[0-9a-f]+$/,
|
|
219
|
+
});
|
|
220
|
+
});
|
|
213
221
|
it('assigns Copilot instructions renderer; Cursor skills use link (cursor-mdc kept for migration)', () => {
|
|
214
222
|
expect((0, providers_1.providerFor)('cursor').skill.renderer).toBe('link');
|
|
215
223
|
expect((0, providers_1.providerFor)('copilot').skill.renderer).toBe('copilot-instructions');
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|