agentic-workflow-manager 9.11.12 → 9.12.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/doctor.js +23 -1
- package/dist/src/commands/hooks/claude.js +61 -8
- package/dist/src/commands/hooks/resync.js +1 -1
- package/dist/src/commands/job/gate.js +6 -1
- package/dist/src/commands/job/index.js +61 -5
- package/dist/src/commands/model-policy/index.js +253 -0
- package/dist/src/commands/plan/index.js +53 -9
- package/dist/src/commands/preflight/checks.js +18 -0
- package/dist/src/commands/watch/apply.js +69 -5
- package/dist/src/commands/watch/archive-unused.js +2 -0
- package/dist/src/commands/watch/index.js +24 -0
- package/dist/src/commands/watch/init.js +2 -1
- package/dist/src/commands/watch/request-recovery.js +153 -0
- package/dist/src/commands/watch/supervisor.js +70 -6
- package/dist/src/core/admission/index.js +20 -6
- package/dist/src/core/journal/requests.js +1 -0
- package/dist/src/core/journal/types.js +50 -6
- package/dist/src/core/model-policy/capabilities-v2.js +152 -0
- package/dist/src/core/model-policy/capabilities.js +7 -1
- package/dist/src/core/model-policy/claude-hook-events.js +120 -0
- package/dist/src/core/model-policy/event-store.js +221 -0
- package/dist/src/core/model-policy/hook-diagnostics.js +94 -0
- package/dist/src/core/model-policy/journal.js +113 -18
- package/dist/src/core/model-policy/local-claude-scope.js +41 -0
- package/dist/src/core/model-policy/local-codex-scope.js +33 -0
- package/dist/src/core/model-policy/local-event-scope.js +13 -0
- package/dist/src/core/model-policy/machine-key.js +56 -0
- package/dist/src/core/model-policy/native-claude-agent-definition.js +82 -0
- package/dist/src/core/model-policy/native-claude-config.js +107 -0
- package/dist/src/core/model-policy/native-claude-machine.js +58 -0
- package/dist/src/core/model-policy/native-claude-transcript.js +80 -0
- package/dist/src/core/model-policy/native-claude.js +41 -0
- package/dist/src/core/model-policy/native-codex-machine.js +116 -0
- package/dist/src/core/model-policy/native-codex-rollout.js +111 -0
- package/dist/src/core/model-policy/native-codex.js +302 -0
- package/dist/src/core/model-policy/native-routing-observe.js +106 -0
- package/dist/src/core/model-policy/native-routing-proof.js +52 -0
- package/dist/src/core/model-policy/native-runtime.js +86 -0
- package/dist/src/core/model-policy/resolve.js +96 -6
- package/dist/src/core/model-policy/selection-policy-digest.js +22 -0
- package/dist/src/core/model-policy/setup-readiness.js +77 -0
- package/dist/src/providers/index.js +3 -1
- package/dist/tests/commands/doctor-routing.test.js +22 -0
- package/dist/tests/commands/doctor.test.js +5 -0
- package/dist/tests/commands/hooks/install.test.js +6 -0
- package/dist/tests/commands/hooks/resync.test.js +3 -0
- package/dist/tests/commands/hooks/status.test.js +12 -1
- package/dist/tests/commands/job/routing-file.test.js +32 -0
- package/dist/tests/commands/job/routing-report-cli.test.js +4 -3
- package/dist/tests/commands/model-policy/claude-hook-flow.test.js +104 -0
- package/dist/tests/commands/model-policy/index.test.js +179 -0
- package/dist/tests/commands/preflight/preflight.test.js +65 -0
- package/dist/tests/commands/watch/apply.test.js +84 -0
- package/dist/tests/commands/watch/dispatch-routing-identity.test.js +23 -0
- package/dist/tests/commands/watch/request-recovery.test.js +253 -0
- package/dist/tests/core/admission/index.test.js +21 -0
- package/dist/tests/core/model-policy/capabilities-v2.test.js +42 -0
- package/dist/tests/core/model-policy/claude-hook-events.test.js +40 -0
- package/dist/tests/core/model-policy/event-store-claude.test.js +64 -0
- package/dist/tests/core/model-policy/event-store.test.js +151 -0
- package/dist/tests/core/model-policy/hook-diagnostics.test.js +34 -0
- package/dist/tests/core/model-policy/journal.test.js +112 -1
- package/dist/tests/core/model-policy/local-claude-scope.test.js +31 -0
- package/dist/tests/core/model-policy/machine-key.test.js +38 -0
- package/dist/tests/core/model-policy/native-claude-agent-definition.test.js +31 -0
- package/dist/tests/core/model-policy/native-claude-config.test.js +53 -0
- package/dist/tests/core/model-policy/native-claude-machine.test.js +18 -0
- package/dist/tests/core/model-policy/native-claude-transcript.test.js +45 -0
- package/dist/tests/core/model-policy/native-claude.test.js +21 -0
- package/dist/tests/core/model-policy/native-codex-machine.test.js +34 -0
- package/dist/tests/core/model-policy/native-codex-rollout.test.js +44 -0
- package/dist/tests/core/model-policy/native-codex.test.js +133 -0
- package/dist/tests/core/model-policy/native-routing-observe.test.js +60 -0
- package/dist/tests/core/model-policy/native-routing-proof.test.js +30 -0
- package/dist/tests/core/model-policy/native-runtime.test.js +14 -0
- package/dist/tests/core/model-policy/resolve-event.test.js +65 -0
- package/dist/tests/core/model-policy/setup-readiness.test.js +83 -0
- package/dist/tests/providers/index.test.js +1 -1
- package/package.json +2 -2
- 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
|
@@ -0,0 +1,133 @@
|
|
|
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
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const os_1 = __importDefault(require("os"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const native_codex_1 = require("../../../src/core/model-policy/native-codex");
|
|
10
|
+
describe('Codex native model discovery', () => {
|
|
11
|
+
const response = () => ({
|
|
12
|
+
data: [
|
|
13
|
+
{ id: 'gpt-6-sol', model: 'gpt-6-sol', hidden: false, isDefault: true,
|
|
14
|
+
defaultReasoningEffort: 'medium', supportedReasoningEfforts: [
|
|
15
|
+
{ reasoningEffort: 'medium', description: 'balanced' },
|
|
16
|
+
{ reasoningEffort: 'high', description: 'deep' },
|
|
17
|
+
] },
|
|
18
|
+
], nextCursor: null,
|
|
19
|
+
});
|
|
20
|
+
it('normalizes catalog selections without certifying dispatch or actual model identity', () => {
|
|
21
|
+
expect((0, native_codex_1.normalizeCodexModelCatalog)(response())).toEqual({
|
|
22
|
+
provenance: 'native-catalog',
|
|
23
|
+
selections: [
|
|
24
|
+
{ selector: { kind: 'model', id: 'gpt-6-sol' }, effort: { kind: 'explicit', value: 'medium' } },
|
|
25
|
+
{ selector: { kind: 'model', id: 'gpt-6-sol' }, effort: { kind: 'explicit', value: 'high' } },
|
|
26
|
+
],
|
|
27
|
+
nativeDispatchVerified: false,
|
|
28
|
+
actualModelVerified: false,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
it('rejects malformed and duplicate native catalog data instead of inventing selections', () => {
|
|
32
|
+
expect(() => (0, native_codex_1.normalizeCodexModelCatalog)({ data: [{ ...response().data[0], model: '' }] })).toThrow(/model/i);
|
|
33
|
+
expect(() => (0, native_codex_1.normalizeCodexModelCatalog)({ data: [response().data[0], response().data[0]] })).toThrow(/duplicate/i);
|
|
34
|
+
expect(() => (0, native_codex_1.normalizeCodexModelCatalog)({ data: [
|
|
35
|
+
{ ...response().data[0], supportedReasoningEfforts: [{ reasoningEffort: 'medium' }] },
|
|
36
|
+
] })).toThrow(/effort/i);
|
|
37
|
+
});
|
|
38
|
+
it('reads the native model/list protocol without starting a model turn', async () => {
|
|
39
|
+
const server = `
|
|
40
|
+
const readline = require('readline');
|
|
41
|
+
const input = readline.createInterface({ input: process.stdin });
|
|
42
|
+
input.on('line', line => {
|
|
43
|
+
const request = JSON.parse(line);
|
|
44
|
+
if (request.method === 'initialize') process.stdout.write(JSON.stringify({ id: request.id, result: { userAgent: 'fake' } }) + '\\n');
|
|
45
|
+
if (request.method === 'model/list') process.stdout.write(JSON.stringify({ id: request.id, result: ${JSON.stringify(response())} }) + '\\n');
|
|
46
|
+
});`;
|
|
47
|
+
const result = await (0, native_codex_1.queryCodexModelCatalog)({ command: process.execPath, args: ['-e', server], timeoutMs: 5000 });
|
|
48
|
+
expect(result.selections).toHaveLength(2);
|
|
49
|
+
expect(result.nativeDispatchVerified).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
it('fails closed on an invalid native response', async () => {
|
|
52
|
+
const server = `process.stdin.on('data', () => process.stdout.write('not-json\\n'));`;
|
|
53
|
+
await expect((0, native_codex_1.queryCodexModelCatalog)({ command: process.execPath, args: ['-e', server], timeoutMs: 5000 })).rejects.toThrow(/protocol|JSON/i);
|
|
54
|
+
});
|
|
55
|
+
it('separates real child dispatch from configured selection and backend identity', () => {
|
|
56
|
+
const child = { thread: { id: 'child-1', parentThreadId: 'parent-1', model: 'gpt-6-sol', reasoningEffort: 'low', turns: [{ id: 'turn-1', status: 'completed', items: [] }] } };
|
|
57
|
+
expect((0, native_codex_1.normalizeCodexChildThreadObservation)(child, 'parent-1')).toEqual({
|
|
58
|
+
provenance: 'codex-app-server-thread-read', parentThreadId: 'parent-1', childThreadId: 'child-1', turnId: 'turn-1',
|
|
59
|
+
nativeDispatchVerified: true, configuredSelection: { selector: { kind: 'model', id: 'gpt-6-sol' }, effort: { kind: 'explicit', value: 'low' } },
|
|
60
|
+
acceptedSelectionVerified: false, actualModelVerified: false, tokenUsage: 'unknown',
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
it('rejects a parent mismatch and refuses to promote a child with no turn', () => {
|
|
64
|
+
const child = { thread: { id: 'child-1', parentThreadId: 'parent-1', model: 'gpt-6-sol', reasoningEffort: 'low', turns: [{ id: 'turn-1', status: 'completed', items: [] }] } };
|
|
65
|
+
expect(() => (0, native_codex_1.normalizeCodexChildThreadObservation)(child, 'parent-2')).toThrow(/parent/i);
|
|
66
|
+
expect(() => (0, native_codex_1.normalizeCodexChildThreadObservation)({ thread: { ...child.thread, turns: [] } }, 'parent-1')).toThrow(/turn/i);
|
|
67
|
+
expect(() => (0, native_codex_1.normalizeCodexChildThreadObservation)({ thread: { ...child.thread, model: null } }, 'parent-1')).toThrow(/model/i);
|
|
68
|
+
});
|
|
69
|
+
it('reads an actual child thread through native thread/read without sending a turn', async () => {
|
|
70
|
+
const observed = { thread: { id: 'child-1', parentThreadId: 'parent-1', model: 'gpt-6-sol', reasoningEffort: 'low', turns: [{ id: 'turn-1', status: 'completed', items: [] }] } };
|
|
71
|
+
const server = `
|
|
72
|
+
const readline = require('readline');
|
|
73
|
+
const input = readline.createInterface({ input: process.stdin });
|
|
74
|
+
input.on('line', line => {
|
|
75
|
+
const request = JSON.parse(line);
|
|
76
|
+
if (request.method === 'initialize') process.stdout.write(JSON.stringify({ id: request.id, result: { userAgent: 'fake' } }) + '\\n');
|
|
77
|
+
if (request.method === 'thread/read') {
|
|
78
|
+
if (request.params.threadId !== 'child-1' || request.params.includeTurns !== true) process.exit(13);
|
|
79
|
+
process.stdout.write(JSON.stringify({ id: request.id, result: ${JSON.stringify(observed)} }) + '\\n');
|
|
80
|
+
}
|
|
81
|
+
if (request.method === 'turn/start' || request.method === 'thread/start') process.exit(14);
|
|
82
|
+
});`;
|
|
83
|
+
const result = await (0, native_codex_1.queryCodexChildThreadObservation)({ command: process.execPath, args: ['-e', server], timeoutMs: 5000, parentThreadId: 'parent-1', childThreadId: 'child-1' });
|
|
84
|
+
expect(result).toMatchObject({ nativeDispatchVerified: true, acceptedSelectionVerified: false, actualModelVerified: false, configuredSelection: { selector: { id: 'gpt-6-sol' } } });
|
|
85
|
+
});
|
|
86
|
+
it('binds an immutable turn context to the observed child, parent and turn', () => {
|
|
87
|
+
const events = [
|
|
88
|
+
{ type: 'session_meta', payload: { id: 'child-1', source: { subagent: { thread_spawn: { parent_thread_id: 'parent-1' } } }, cli_version: '0.156.1' } },
|
|
89
|
+
{ timestamp: '2026-09-23T20:00:00.000Z', type: 'turn_context', payload: { turn_id: 'turn-1', model: 'gpt-6-luna', effort: 'high' } },
|
|
90
|
+
];
|
|
91
|
+
expect((0, native_codex_1.normalizeCodexRolloutSelection)(events, { parentThreadId: 'parent-1', childThreadId: 'child-1', turnId: 'turn-1' })).toEqual({
|
|
92
|
+
provenance: 'codex-rollout-turn-context', cliVersion: '0.156.1', observedAt: '2026-09-23T20:00:00.000Z',
|
|
93
|
+
configuredSelection: { selector: { kind: 'model', id: 'gpt-6-luna' }, effort: { kind: 'explicit', value: 'high' } },
|
|
94
|
+
actualModelVerified: false,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
it('rejects unrelated parent, child and turn contexts', () => {
|
|
98
|
+
const events = [
|
|
99
|
+
{ type: 'session_meta', payload: { id: 'child-1', source: { subagent: { thread_spawn: { parent_thread_id: 'parent-1' } } }, cli_version: '0.156.1' } },
|
|
100
|
+
{ timestamp: '2026-09-23T20:00:00.000Z', type: 'turn_context', payload: { turn_id: 'turn-1', model: 'gpt-6-luna', effort: 'high' } },
|
|
101
|
+
];
|
|
102
|
+
expect(() => (0, native_codex_1.normalizeCodexRolloutSelection)(events, { parentThreadId: 'other', childThreadId: 'child-1', turnId: 'turn-1' })).toThrow(/parent/i);
|
|
103
|
+
expect(() => (0, native_codex_1.normalizeCodexRolloutSelection)(events, { parentThreadId: 'parent-1', childThreadId: 'other', turnId: 'turn-1' })).toThrow(/child/i);
|
|
104
|
+
expect(() => (0, native_codex_1.normalizeCodexRolloutSelection)(events, { parentThreadId: 'parent-1', childThreadId: 'child-1', turnId: 'other' })).toThrow(/turn/i);
|
|
105
|
+
expect(() => (0, native_codex_1.normalizeCodexRolloutSelection)([...events, events[1]], { parentThreadId: 'parent-1', childThreadId: 'child-1', turnId: 'turn-1' })).toThrow(/duplicate/i);
|
|
106
|
+
expect(() => (0, native_codex_1.normalizeCodexRolloutSelection)([{ ...events[0] }, { ...events[1], timestamp: undefined }], { parentThreadId: 'parent-1', childThreadId: 'child-1', turnId: 'turn-1' })).toThrow(/timestamp/i);
|
|
107
|
+
});
|
|
108
|
+
it('attests the configured selection at the completed native turn only with matching rollout provenance', async () => {
|
|
109
|
+
const home = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-codex-observe-'));
|
|
110
|
+
const file = path_1.default.join(home, 'sessions', 'rollout.jsonl');
|
|
111
|
+
fs_1.default.mkdirSync(path_1.default.dirname(file));
|
|
112
|
+
fs_1.default.writeFileSync(file, [
|
|
113
|
+
{ type: 'session_meta', payload: { id: 'child-1', source: { subagent: { thread_spawn: { parent_thread_id: 'parent-1' } } }, cli_version: '0.156.1' } },
|
|
114
|
+
{ timestamp: '2026-09-23T20:00:00.000Z', type: 'turn_context', payload: { turn_id: 'turn-1', model: 'gpt-6-luna', effort: 'high' } },
|
|
115
|
+
].map(value => JSON.stringify(value)).join('\n'));
|
|
116
|
+
const observed = { thread: { id: 'child-1', parentThreadId: 'parent-1', model: 'gpt-6-luna', reasoningEffort: 'high', path: file, turns: [{ id: 'turn-1', status: 'completed', items: [] }] } };
|
|
117
|
+
const server = `
|
|
118
|
+
const readline = require('readline');
|
|
119
|
+
const input = readline.createInterface({ input: process.stdin });
|
|
120
|
+
input.on('line', line => {
|
|
121
|
+
const request = JSON.parse(line);
|
|
122
|
+
if (request.method === 'initialize') process.stdout.write(JSON.stringify({ id: request.id, result: {} }) + '\\n');
|
|
123
|
+
if (request.method === 'thread/read') process.stdout.write(JSON.stringify({ id: request.id, result: ${JSON.stringify(observed)} }) + '\\n');
|
|
124
|
+
});`;
|
|
125
|
+
try {
|
|
126
|
+
const result = await (0, native_codex_1.queryCodexChildThreadObservation)({ command: process.execPath, args: ['-e', server], timeoutMs: 5000, parentThreadId: 'parent-1', childThreadId: 'child-1', codexHome: home });
|
|
127
|
+
expect(result).toMatchObject({ acceptedSelectionVerified: true, childRuntimeVersion: '0.156.1', configuredSelection: { selector: { id: 'gpt-6-luna' }, effort: { value: 'high' } }, actualModelVerified: false });
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
fs_1.default.rmSync(home, { recursive: true, force: true });
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const native_routing_observe_1 = require("../../../src/core/model-policy/native-routing-observe");
|
|
4
|
+
const local_event_scope_1 = require("../../../src/core/model-policy/local-event-scope");
|
|
5
|
+
const machine_key_1 = require("../../../src/core/model-policy/machine-key");
|
|
6
|
+
const native_codex_1 = require("../../../src/core/model-policy/native-codex");
|
|
7
|
+
const event_store_1 = require("../../../src/core/model-policy/event-store");
|
|
8
|
+
const store_1 = require("../../../src/core/model-policy/store");
|
|
9
|
+
const selection_policy_digest_1 = require("../../../src/core/model-policy/selection-policy-digest");
|
|
10
|
+
const routing_approval_1 = require("../../helpers/routing-approval");
|
|
11
|
+
const native_routing_proof_1 = require("../../../src/core/model-policy/native-routing-proof");
|
|
12
|
+
jest.mock('../../../src/core/model-policy/local-event-scope');
|
|
13
|
+
jest.mock('../../../src/core/model-policy/machine-key');
|
|
14
|
+
jest.mock('../../../src/core/model-policy/native-codex');
|
|
15
|
+
jest.mock('../../../src/core/model-policy/event-store');
|
|
16
|
+
jest.mock('../../../src/core/model-policy/store');
|
|
17
|
+
const key = Buffer.alloc(32, 9);
|
|
18
|
+
const now = new Date('2026-09-23T12:00:03.000Z');
|
|
19
|
+
const reservedAt = '2026-09-23T12:00:00.000Z';
|
|
20
|
+
const observedAt = '2026-09-23T12:00:02.000Z';
|
|
21
|
+
const scope = { runtime: routing_approval_1.routingEnvelope.runtime, binaryDigest: 'b'.repeat(64), configDigest: 'c'.repeat(64) };
|
|
22
|
+
function attempt() {
|
|
23
|
+
return { schema: 'routing-attempt/v1', id: 'route-1', obligationId: 'o1', lineageId: 'l1', attempt: 1,
|
|
24
|
+
envelope: routing_approval_1.routingEnvelope, envelopeDigest: 'e'.repeat(64), fingerprint: 'f'.repeat(64), state: 'reserved',
|
|
25
|
+
nativeEvidenceRequired: true, reservedAt };
|
|
26
|
+
}
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
jest.clearAllMocks();
|
|
29
|
+
const approved = (0, routing_approval_1.routingApproval)();
|
|
30
|
+
jest.mocked(store_1.readEffectivePolicy).mockReturnValue({ state: 'approved', provenance: 'project', policy: approved.policy });
|
|
31
|
+
jest.mocked(machine_key_1.readMachineKey).mockReturnValue(key);
|
|
32
|
+
jest.mocked(local_event_scope_1.queryLocalEventScope).mockResolvedValue({ state: 'current', scope });
|
|
33
|
+
const receipt = { schema: 'routing-capabilities/v2', ...scope, recordedAt: observedAt,
|
|
34
|
+
claims: [{ selection: routing_approval_1.routingEnvelope.resolved,
|
|
35
|
+
mappingDigest: (0, selection_policy_digest_1.selectionPolicyDigest)(approved.policy.content.mappings[0], routing_approval_1.routingEnvelope.resolved),
|
|
36
|
+
eventDigest: 'a'.repeat(64), source: 'codex-turn-context', observedAt,
|
|
37
|
+
actualModel: 'unverified', tokenUsage: 'unknown' }] };
|
|
38
|
+
jest.mocked(event_store_1.readStoredEventReceipt).mockReturnValue({ state: 'present', receipt });
|
|
39
|
+
jest.mocked(native_codex_1.queryCodexChildThreadObservation).mockResolvedValue({ provenance: 'codex-app-server-thread-read',
|
|
40
|
+
parentThreadId: 'parent-1', childThreadId: 'child-1', turnId: 'turn-1', nativeDispatchVerified: true,
|
|
41
|
+
configuredSelection: routing_approval_1.routingEnvelope.resolved, acceptedSelectionVerified: true,
|
|
42
|
+
childRuntimeVersion: routing_approval_1.routingEnvelope.runtime.version, observedAt,
|
|
43
|
+
actualModelVerified: false, tokenUsage: 'unknown' });
|
|
44
|
+
});
|
|
45
|
+
describe('normal-work native routing observation', () => {
|
|
46
|
+
it('reconciles a completed Codex child and renews only its matching claim', async () => {
|
|
47
|
+
const proof = await (0, native_routing_observe_1.observeNativeRoutingChild)({ attempt: attempt(), nativeAgentId: 'child-1', parentThreadId: 'parent-1',
|
|
48
|
+
cwd: '/tmp/awm-native-observe-test', now, consumedEventDigests: [] });
|
|
49
|
+
expect((0, native_routing_proof_1.verifyNativeRoutingProof)(proof, { attemptId: 'route-1', nativeAgentId: 'child-1',
|
|
50
|
+
reservedAt, selection: routing_approval_1.routingEnvelope.resolved }, key, now)).toBe(true);
|
|
51
|
+
expect(event_store_1.publishCodexObservation).toHaveBeenCalledWith(expect.objectContaining({ expectedSelection: routing_approval_1.routingEnvelope.resolved }));
|
|
52
|
+
});
|
|
53
|
+
it('rejects a setup turn preceding reservation without renewing its claim', async () => {
|
|
54
|
+
jest.mocked(native_codex_1.queryCodexChildThreadObservation).mockResolvedValueOnce({ ...await (0, native_codex_1.queryCodexChildThreadObservation)({ command: 'codex', args: [], timeoutMs: 1, parentThreadId: 'parent-1', childThreadId: 'child-1' }),
|
|
55
|
+
observedAt: '2026-09-23T11:59:59.000Z' });
|
|
56
|
+
await expect((0, native_routing_observe_1.observeNativeRoutingChild)({ attempt: attempt(), nativeAgentId: 'child-1', parentThreadId: 'parent-1',
|
|
57
|
+
cwd: '/tmp/awm-native-observe-test', now, consumedEventDigests: [] })).rejects.toThrow(/predates reservation/);
|
|
58
|
+
expect(event_store_1.publishCodexObservation).not.toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const native_routing_proof_1 = require("../../../src/core/model-policy/native-routing-proof");
|
|
4
|
+
const routing_approval_1 = require("../../helpers/routing-approval");
|
|
5
|
+
const key = Buffer.alloc(32, 7);
|
|
6
|
+
const input = { attemptId: 'route-1', nativeAgentId: 'child-1', source: 'codex-turn-context',
|
|
7
|
+
eventDigest: 'a'.repeat(64), observedAt: '2026-09-23T12:00:02.000Z', selection: (0, routing_approval_1.routingSelection)('medium') };
|
|
8
|
+
describe('native routing proof', () => {
|
|
9
|
+
it('binds a native event to one reserved attempt and child', () => {
|
|
10
|
+
const proof = (0, native_routing_proof_1.signNativeRoutingProof)(input, key);
|
|
11
|
+
expect((0, native_routing_proof_1.verifyNativeRoutingProof)(proof, { attemptId: 'route-1', nativeAgentId: 'child-1',
|
|
12
|
+
reservedAt: '2026-09-23T12:00:00.000Z', selection: input.selection }, key, new Date('2026-09-23T12:00:03.000Z'))).toBe(true);
|
|
13
|
+
expect((0, native_routing_proof_1.verifyNativeRoutingProof)(proof, { attemptId: 'route-2', nativeAgentId: 'child-1',
|
|
14
|
+
reservedAt: '2026-09-23T12:00:00.000Z', selection: input.selection }, key, new Date('2026-09-23T12:00:03.000Z'))).toBe(false);
|
|
15
|
+
expect((0, native_routing_proof_1.verifyNativeRoutingProof)({ ...proof, selection: (0, routing_approval_1.routingSelection)('high') }, { attemptId: 'route-1', nativeAgentId: 'child-1',
|
|
16
|
+
reservedAt: '2026-09-23T12:00:00.000Z', selection: input.selection }, key, new Date('2026-09-23T12:00:03.000Z'))).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
it('rejects a setup event replayed as a daily dispatch', () => {
|
|
19
|
+
const proof = (0, native_routing_proof_1.signNativeRoutingProof)(input, key);
|
|
20
|
+
expect((0, native_routing_proof_1.verifyNativeRoutingProof)(proof, { attemptId: 'route-1', nativeAgentId: 'child-1',
|
|
21
|
+
reservedAt: '2026-09-23T12:00:03.000Z', selection: input.selection }, key, new Date('2026-09-23T12:00:04.000Z'))).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
it('rejects a proof after its bounded observation window and protects a provider model claim', () => {
|
|
24
|
+
const proof = (0, native_routing_proof_1.signNativeRoutingProof)({ ...input, source: 'claude-assistant-transcript', actualModel: 'claude-example-model' }, key);
|
|
25
|
+
const expected = { attemptId: 'route-1', nativeAgentId: 'child-1', reservedAt: '2026-09-23T12:00:00.000Z', selection: input.selection };
|
|
26
|
+
expect((0, native_routing_proof_1.verifyNativeRoutingProof)(proof, expected, key, new Date('2026-09-23T12:00:03.000Z'))).toBe(true);
|
|
27
|
+
expect((0, native_routing_proof_1.verifyNativeRoutingProof)({ ...proof, actualModel: 'different' }, expected, key, new Date('2026-09-23T12:00:03.000Z'))).toBe(false);
|
|
28
|
+
expect((0, native_routing_proof_1.verifyNativeRoutingProof)(proof, expected, key, new Date('2026-09-23T12:16:03.000Z'))).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const native_runtime_1 = require("../../../src/core/model-policy/native-runtime");
|
|
4
|
+
describe('native runtime fingerprint', () => {
|
|
5
|
+
it('binds reported version and executable content without launching inference', async () => {
|
|
6
|
+
const result = await (0, native_runtime_1.queryRuntimeExecutable)({ command: process.execPath, args: ['--version'], timeoutMs: 5000 });
|
|
7
|
+
expect(result).toMatchObject({ version: expect.stringMatching(/^\d+\.\d+\.\d+$/), binaryDigest: expect.stringMatching(/^[a-f0-9]{64}$/), inferenceDispatched: false });
|
|
8
|
+
expect(await (0, native_runtime_1.queryRuntimeExecutable)({ command: process.execPath, args: ['--version'], timeoutMs: 5000 })).toEqual(result);
|
|
9
|
+
});
|
|
10
|
+
it('rejects an invalid binary or an inference-shaped invocation', async () => {
|
|
11
|
+
await expect((0, native_runtime_1.queryRuntimeExecutable)({ command: '/definitely/missing/awm-runtime', args: ['--version'], timeoutMs: 1000 })).rejects.toThrow(/runtime|executable/i);
|
|
12
|
+
await expect((0, native_runtime_1.queryRuntimeExecutable)({ command: process.execPath, args: ['-e', 'console.log(1)'], timeoutMs: 1000 })).rejects.toThrow(/version/i);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const resolve_1 = require("../../../src/core/model-policy/resolve");
|
|
4
|
+
const selection_policy_digest_1 = require("../../../src/core/model-policy/selection-policy-digest");
|
|
5
|
+
const a = 'a'.repeat(64);
|
|
6
|
+
const b = 'b'.repeat(64);
|
|
7
|
+
const c = 'c'.repeat(64);
|
|
8
|
+
const selected = (id) => ({ selector: { kind: 'model', id }, effort: { kind: 'explicit', value: 'high' } });
|
|
9
|
+
const policy = () => ({ schema: 'approved-model-policy/v1', content: { schema: 'model-policy/v1', mappings: [{ target: 'codex', runtimeKind: 'native',
|
|
10
|
+
profiles: { mechanical: selected('luna'), integration: selected('sol'), judgment: selected('astra') }, fullCapability: selected('astra'),
|
|
11
|
+
degradation: { allowMissingModelOverride: false, allowMissingEffortOverride: false, allowMissingObservedIdentity: true } }],
|
|
12
|
+
implementationBudget: { maxAttempts: 3, escalation: ['mechanical', 'integration', 'judgment'], judgmentEfforts: ['medium', 'high'] } },
|
|
13
|
+
contentDigest: a, approval: { approvedAt: '2026-09-23T00:00:00.000Z', approvalId: 'owner' }, lineage: { previousDigest: null } });
|
|
14
|
+
const scope = () => ({ runtime: { target: 'codex', kind: 'native', version: '0.156.1', accountScopeDigest: a }, binaryDigest: b, configDigest: c });
|
|
15
|
+
const receipt = () => ({ schema: 'routing-capabilities/v2', ...scope(), recordedAt: '2026-09-23T00:00:00.000Z', claims: ['luna', 'astra'].map(id => ({ selection: selected(id),
|
|
16
|
+
mappingDigest: (0, selection_policy_digest_1.selectionPolicyDigest)(policy().content.mappings[0], selected(id)), eventDigest: b, source: 'codex-turn-context',
|
|
17
|
+
observedAt: '2026-09-22T23:59:00.000Z', actualModel: 'unverified', tokenUsage: 'unknown' })) });
|
|
18
|
+
const input = () => ({ role: 'implementer', requestedProfile: 'mechanical', policy: policy(), receipt: receipt(), scope: scope(), now: new Date('2026-09-24T01:00:00.000Z') });
|
|
19
|
+
describe('event-scoped routing resolution', () => {
|
|
20
|
+
it('routes a proved selection after 25 hours but labels missing backend identity as degraded', () => {
|
|
21
|
+
expect((0, resolve_1.resolveEventSelection)(input())).toMatchObject({ state: 'resolved', selection: selected('luna'), outcome: 'degraded', unavailableEvidence: ['observedModelEvidence'] });
|
|
22
|
+
});
|
|
23
|
+
it('requires the full selection to be separately proved', () => {
|
|
24
|
+
const value = input();
|
|
25
|
+
value.receipt.claims = value.receipt.claims.filter(item => item.selection.selector.id !== 'astra');
|
|
26
|
+
expect((0, resolve_1.resolveEventSelection)({ ...value, role: 'code-quality-reviewer' })).toMatchObject({ state: 'blocked', diagnostics: [{ code: 'ROUTING_SELECTION_UNENROLLED' }] });
|
|
27
|
+
});
|
|
28
|
+
it('blocks on account drift and when the owner did not permit missing backend identity', () => {
|
|
29
|
+
expect((0, resolve_1.resolveEventSelection)({ ...input(), scope: { ...scope(), runtime: { ...scope().runtime, accountScopeDigest: c } } })).toMatchObject({ state: 'blocked', diagnostics: [{ code: 'ROUTING_ACCOUNT_DRIFT' }] });
|
|
30
|
+
const value = input();
|
|
31
|
+
value.policy.content.mappings[0].degradation.allowMissingObservedIdentity = false;
|
|
32
|
+
expect((0, resolve_1.resolveEventSelection)(value)).toMatchObject({ state: 'blocked' });
|
|
33
|
+
});
|
|
34
|
+
it('uses independently enrolled full capability when only the optimized selection is absent', () => {
|
|
35
|
+
const value = input();
|
|
36
|
+
value.receipt.claims = value.receipt.claims.filter(item => item.selection.selector.id === 'astra');
|
|
37
|
+
expect((0, resolve_1.resolveEventWithFallback)(value)).toMatchObject({ state: 'resolved', selection: selected('astra'), effectiveProfile: 'full', outcome: 'degraded', fallbackReason: 'ROUTING_SELECTION_UNENROLLED' });
|
|
38
|
+
const drift = { ...value, scope: { ...scope(), runtime: { ...scope().runtime, accountScopeDigest: c } } };
|
|
39
|
+
expect((0, resolve_1.resolveEventWithFallback)(drift)).toMatchObject({ state: 'blocked', diagnostics: [expect.objectContaining({ code: 'ROUTING_FALLBACK_UNAVAILABLE' })] });
|
|
40
|
+
});
|
|
41
|
+
it('trips a same-run circuit to full when a provider rejects an otherwise current optimized selection', () => {
|
|
42
|
+
const value = input();
|
|
43
|
+
expect((0, resolve_1.resolveEventSelection)(value)).toMatchObject({ state: 'resolved', selection: selected('luna') });
|
|
44
|
+
expect((0, resolve_1.resolveEventWithFallback)({ ...value, circuitReason: 'PROVIDER_REJECTED' })).toMatchObject({ state: 'resolved', selection: selected('astra'), effectiveProfile: 'full', fallbackReason: 'PROVIDER_REJECTED' });
|
|
45
|
+
value.receipt.claims = value.receipt.claims.filter(item => item.selection.selector.id !== 'astra');
|
|
46
|
+
expect((0, resolve_1.resolveEventWithFallback)({ ...value, circuitReason: 'PROVIDER_REJECTED' })).toMatchObject({ state: 'blocked', diagnostics: [{ code: 'ROUTING_FALLBACK_UNAVAILABLE' }] });
|
|
47
|
+
});
|
|
48
|
+
it('returns the certified Claude agent type and preserves it on full fallback', () => {
|
|
49
|
+
const value = input();
|
|
50
|
+
value.policy.content.mappings[0].target = 'claude-code';
|
|
51
|
+
value.policy.content.mappings[0].profiles.mechanical = { selector: { kind: 'model', id: 'claude-haiku-4-5' }, effort: { kind: 'runtime-default' } };
|
|
52
|
+
value.policy.content.mappings[0].fullCapability = { selector: { kind: 'model', id: 'claude-opus-4-7' }, effort: { kind: 'runtime-default' } };
|
|
53
|
+
const claudeScope = { ...scope(), runtime: { ...scope().runtime, target: 'claude-code' } };
|
|
54
|
+
const mapping = value.policy.content.mappings[0];
|
|
55
|
+
const claims = [
|
|
56
|
+
{ selection: mapping.profiles.mechanical, nativeAgentType: 'awm-mechanical' },
|
|
57
|
+
{ selection: mapping.fullCapability, nativeAgentType: 'awm-full' },
|
|
58
|
+
].map(row => ({ ...row, mappingDigest: (0, selection_policy_digest_1.selectionPolicyDigest)(mapping, row.selection), eventDigest: b,
|
|
59
|
+
source: 'claude-assistant-transcript', observedAt: '2026-09-22T23:59:00.000Z',
|
|
60
|
+
actualModel: { id: row.selection.selector.id, evidenceDigest: c }, tokenUsage: 'unknown' }));
|
|
61
|
+
const routed = { ...value, receipt: { schema: 'routing-capabilities/v2', ...claudeScope, recordedAt: '2026-09-23T00:00:00.000Z', claims }, scope: claudeScope };
|
|
62
|
+
expect((0, resolve_1.resolveEventSelection)(routed)).toMatchObject({ state: 'resolved', nativeAgentType: 'awm-mechanical' });
|
|
63
|
+
expect((0, resolve_1.resolveEventWithFallback)({ ...routed, circuitReason: 'PROVIDER_REJECTED' })).toMatchObject({ state: 'resolved', nativeAgentType: 'awm-full', effectiveProfile: 'full' });
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
const setup_readiness_1 = require("../../../src/core/model-policy/setup-readiness");
|
|
7
|
+
const capabilities_1 = require("../../../src/core/model-policy/capabilities");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const selection_policy_digest_1 = require("../../../src/core/model-policy/selection-policy-digest");
|
|
12
|
+
const approved = {
|
|
13
|
+
state: 'approved', provenance: 'user',
|
|
14
|
+
policy: { schema: 'approved-model-policy/v1', contentDigest: 'a'.repeat(64), approval: { approvedAt: '2026-09-23T00:00:00.000Z', approvalId: 'test' }, lineage: { previousDigest: null },
|
|
15
|
+
content: { schema: 'model-policy/v1', implementationBudget: { maxAttempts: 3, escalation: ['mechanical', 'integration', 'judgment'], judgmentEfforts: ['medium', 'high'] }, mappings: [
|
|
16
|
+
{ target: 'codex', runtimeKind: 'native', profiles: {}, fullCapability: {}, degradation: { allowMissingModelOverride: false, allowMissingEffortOverride: false, allowMissingObservedIdentity: false } },
|
|
17
|
+
] } },
|
|
18
|
+
};
|
|
19
|
+
describe('routing setup guidance', () => {
|
|
20
|
+
it('does not demand machine setup when routing policy is absent', () => {
|
|
21
|
+
expect((0, setup_readiness_1.routingSetupGuidance)({ state: 'absent' })).toEqual([]);
|
|
22
|
+
});
|
|
23
|
+
it('names the exact provider and explicit discovery step without certifying the receipt', () => {
|
|
24
|
+
expect((0, setup_readiness_1.routingSetupGuidance)(approved)).toEqual([
|
|
25
|
+
{ target: 'codex', runtimeKind: 'native', state: 'needs-evidence', command: 'awm model-policy setup --provider codex --json' },
|
|
26
|
+
]);
|
|
27
|
+
});
|
|
28
|
+
it('reports invalid policy instead of silently falling back to a machine default', () => {
|
|
29
|
+
expect((0, setup_readiness_1.routingSetupGuidance)({ state: 'invalid', provenance: 'project', reason: 'bad digest' })).toEqual([
|
|
30
|
+
{ state: 'policy-invalid', reason: 'bad digest' },
|
|
31
|
+
]);
|
|
32
|
+
});
|
|
33
|
+
it('does not keep nudging when a valid local receipt exists; runtime matching remains a separate gate', () => {
|
|
34
|
+
const previous = process.env.AWM_HOME;
|
|
35
|
+
const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-routing-setup-'));
|
|
36
|
+
process.env.AWM_HOME = root;
|
|
37
|
+
try {
|
|
38
|
+
const runtime = { target: 'codex', kind: 'native', version: '1.0.0', accountScopeDigest: 'b'.repeat(64) };
|
|
39
|
+
const destination = (0, capabilities_1.capabilityReceiptPath)(runtime);
|
|
40
|
+
fs_1.default.mkdirSync(path_1.default.dirname(destination), { recursive: true });
|
|
41
|
+
const receipt = {
|
|
42
|
+
schema: 'routing-capabilities/v1', runtime,
|
|
43
|
+
recordedAt: '2026-09-23T19:00:00.000Z', expiresAt: '2026-09-24T19:00:00.000Z',
|
|
44
|
+
capabilities: { artifactDelivery: 'unverified', interactiveExecution: 'unverified', unattendedController: 'unverified', nativeSubagents: 'unverified', modelOverride: 'unverified', effortOverride: 'unverified', observedModelEvidence: 'unverified', durableResume: 'unverified' },
|
|
45
|
+
availableSelections: [{ selector: { kind: 'model', id: 'gpt-6-sol' }, effort: { kind: 'explicit', value: 'medium' } }],
|
|
46
|
+
evidence: [], approval: { approvalId: 'test', snapshotDigest: 'a'.repeat(64) },
|
|
47
|
+
};
|
|
48
|
+
fs_1.default.writeFileSync(destination, JSON.stringify(receipt));
|
|
49
|
+
expect((0, setup_readiness_1.routingSetupGuidance)(approved, new Date('2026-09-23T19:30:00.000Z'))).toHaveLength(1);
|
|
50
|
+
receipt.capabilities.nativeSubagents = 'supported';
|
|
51
|
+
receipt.capabilities.modelOverride = 'supported';
|
|
52
|
+
receipt.capabilities.effortOverride = 'supported';
|
|
53
|
+
receipt.capabilities.observedModelEvidence = 'supported';
|
|
54
|
+
receipt.evidence = ['nativeSubagents', 'modelOverride', 'effortOverride', 'observedModelEvidence'].map(capability => ({ capability, kind: 'native-dispatch', receiptDigest: 'b'.repeat(64) }));
|
|
55
|
+
fs_1.default.writeFileSync(destination, JSON.stringify(receipt));
|
|
56
|
+
expect((0, setup_readiness_1.routingSetupGuidance)(approved, new Date('2026-09-23T19:30:00.000Z'))).toEqual([]);
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
if (previous === undefined)
|
|
60
|
+
delete process.env.AWM_HOME;
|
|
61
|
+
else
|
|
62
|
+
process.env.AWM_HOME = previous;
|
|
63
|
+
fs_1.default.rmSync(root, { recursive: true, force: true });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
it('reports sealed v2 coverage without claiming that passive diagnostics checked the current machine', () => {
|
|
67
|
+
const selection = { selector: { kind: 'model', id: 'gpt-6-sol' }, effort: { kind: 'explicit', value: 'high' } };
|
|
68
|
+
const policy = structuredClone(approved);
|
|
69
|
+
if (policy.state !== 'approved')
|
|
70
|
+
throw new Error('expected policy');
|
|
71
|
+
const mapping = policy.policy.content.mappings[0];
|
|
72
|
+
mapping.profiles = { mechanical: selection, integration: selection, judgment: selection };
|
|
73
|
+
mapping.fullCapability = selection;
|
|
74
|
+
mapping.degradation.allowMissingObservedIdentity = true;
|
|
75
|
+
const receipt = { schema: 'routing-capabilities/v2', runtime: { target: 'codex', kind: 'native', version: '0.156.1', accountScopeDigest: 'a'.repeat(64) },
|
|
76
|
+
binaryDigest: 'b'.repeat(64), configDigest: 'c'.repeat(64), recordedAt: '2026-09-22T00:00:00.000Z', claims: [{ selection,
|
|
77
|
+
mappingDigest: (0, selection_policy_digest_1.selectionPolicyDigest)(mapping, selection), eventDigest: 'd'.repeat(64), source: 'codex-turn-context', observedAt: '2026-09-22T00:00:00.000Z', actualModel: 'unverified', tokenUsage: 'unknown' }] };
|
|
78
|
+
expect((0, setup_readiness_1.routingSetupGuidance)(policy, new Date('2026-09-23T01:00:00.000Z'), { readStoredEventReceipt: (() => ({ state: 'present', receipt })) })).toEqual([
|
|
79
|
+
{ target: 'codex', runtimeKind: 'native', state: 'coverage-only' },
|
|
80
|
+
]);
|
|
81
|
+
expect((0, setup_readiness_1.routingSetupGuidance)(policy, new Date('2026-09-23T01:00:00.000Z'), { readStoredEventReceipt: (() => ({ state: 'invalid', reason: 'bad seal' })) })).toMatchObject([{ state: 'needs-evidence' }]);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -123,7 +123,7 @@ describe('Providers Routing', () => {
|
|
|
123
123
|
});
|
|
124
124
|
expect(graph['claude-code']).toEqual({
|
|
125
125
|
label: 'Claude Code',
|
|
126
|
-
configHome: { envVar:
|
|
126
|
+
configHome: { envVar: 'CLAUDE_CONFIG_DIR', dir: '.claude', resolved: path_1.default.join(tmpHome, '.claude') },
|
|
127
127
|
skill: {
|
|
128
128
|
global: path_1.default.join(tmpHome, '.claude/skills'),
|
|
129
129
|
local: '.claude/skills',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-workflow-manager",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.12.1",
|
|
4
4
|
"main": "dist/src/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"awm": "./dist/src/index.js"
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@clack/prompts": "^0.11.0",
|
|
52
52
|
"commander": "^14.0.3",
|
|
53
|
+
"js-yaml": "4.3.2",
|
|
53
54
|
"picocolors": "^1.1.1",
|
|
54
55
|
"semver": "^7.7.4",
|
|
55
56
|
"simple-git": "3.36.0"
|
|
@@ -64,7 +65,6 @@
|
|
|
64
65
|
"dependency-cruiser": "16.10.4",
|
|
65
66
|
"eslint": "10.8.1",
|
|
66
67
|
"jest": "^30.2.0",
|
|
67
|
-
"js-yaml": "4.3.2",
|
|
68
68
|
"node-gyp": "^11.5.0",
|
|
69
69
|
"ts-jest": "^29.4.6",
|
|
70
70
|
"ts-node": "^10.9.2",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|