zelari-code 2.1.0 → 2.1.2
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 +4 -4
- package/package.json +8 -5
- package/dist/cli/ast/engine.test.js +0 -101
- package/dist/cli/ast/engine.test.js.map +0 -1
- package/dist/cli/ast/tools.test.js +0 -124
- package/dist/cli/ast/tools.test.js.map +0 -1
- package/dist/cli/headless.test.js +0 -107
- package/dist/cli/headless.test.js.map +0 -1
- package/dist/cli/headlessE2eSession.test.js +0 -189
- package/dist/cli/headlessE2eSession.test.js.map +0 -1
- package/dist/cli/headlessHistorySeed.test.js +0 -158
- package/dist/cli/headlessHistorySeed.test.js.map +0 -1
- package/dist/cli/headlessSessionEvent.test.js +0 -83
- package/dist/cli/headlessSessionEvent.test.js.map +0 -1
- package/dist/cli/headlessSpine.test.js +0 -153
- package/dist/cli/headlessSpine.test.js.map +0 -1
- package/dist/cli/hooks/observationStore.test.js +0 -135
- package/dist/cli/hooks/observationStore.test.js.map +0 -1
- package/dist/cli/hooks/sessionSurface.test.js +0 -112
- package/dist/cli/hooks/sessionSurface.test.js.map +0 -1
- package/dist/cli/kraken/candidateRegistry.test.js +0 -211
- package/dist/cli/kraken/candidateRegistry.test.js.map +0 -1
- package/dist/cli/kraken/completionGate.test.js +0 -172
- package/dist/cli/kraken/completionGate.test.js.map +0 -1
- package/dist/cli/kraken/evidenceAnchoring.test.js +0 -92
- package/dist/cli/kraken/evidenceAnchoring.test.js.map +0 -1
- package/dist/cli/kraken/evidenceProvenance.test.js +0 -113
- package/dist/cli/kraken/evidenceProvenance.test.js.map +0 -1
- package/dist/cli/kraken/executor.workbench.test.js +0 -134
- package/dist/cli/kraken/executor.workbench.test.js.map +0 -1
- package/dist/cli/kraken/metrics.test.js +0 -145
- package/dist/cli/kraken/metrics.test.js.map +0 -1
- package/dist/cli/kraken/nativeVerification.test.js +0 -207
- package/dist/cli/kraken/nativeVerification.test.js.map +0 -1
- package/dist/cli/kraken/planner.test.js +0 -43
- package/dist/cli/kraken/planner.test.js.map +0 -1
- package/dist/cli/kraken/scriptPlanner.test.js +0 -152
- package/dist/cli/kraken/scriptPlanner.test.js.map +0 -1
- package/dist/cli/kraken/selectionPlaybook.test.js +0 -55
- package/dist/cli/kraken/selectionPlaybook.test.js.map +0 -1
- package/dist/cli/kraken/skillSuggest.test.js +0 -157
- package/dist/cli/kraken/skillSuggest.test.js.map +0 -1
- package/dist/cli/kraken/strictDefaults.test.js +0 -149
- package/dist/cli/kraken/strictDefaults.test.js.map +0 -1
- package/dist/cli/kraken/strictGatePackIndependence.test.js +0 -112
- package/dist/cli/kraken/strictGatePackIndependence.test.js.map +0 -1
- package/dist/cli/kraken/turnRuntime.test.js +0 -377
- package/dist/cli/kraken/turnRuntime.test.js.map +0 -1
- package/dist/cli/kraken/verificationBridge.session.test.js +0 -104
- package/dist/cli/kraken/verificationBridge.session.test.js.map +0 -1
- package/dist/cli/kraken/verificationBridge.test.js +0 -177
- package/dist/cli/kraken/verificationBridge.test.js.map +0 -1
- package/dist/cli/kraken/verifier.test.js +0 -232
- package/dist/cli/kraken/verifier.test.js.map +0 -1
- package/dist/cli/kraken/verifierAdvisoryLock.test.js +0 -154
- package/dist/cli/kraken/verifierAdvisoryLock.test.js.map +0 -1
- package/dist/cli/kraken/verifierLifecycle.test.js +0 -181
- package/dist/cli/kraken/verifierLifecycle.test.js.map +0 -1
- package/dist/cli/kraken/verifierRoundTrip.test.js +0 -166
- package/dist/cli/kraken/verifierRoundTrip.test.js.map +0 -1
- package/dist/cli/kraken/verifierSettings.test.js +0 -237
- package/dist/cli/kraken/verifierSettings.test.js.map +0 -1
- package/dist/cli/kraken/verifyReport.test.js +0 -111
- package/dist/cli/kraken/verifyReport.test.js.map +0 -1
- package/dist/cli/kraken/weaknessMeter.test.js +0 -212
- package/dist/cli/kraken/weaknessMeter.test.js.map +0 -1
- package/dist/cli/kraken/workbench.test.js +0 -253
- package/dist/cli/kraken/workbench.test.js.map +0 -1
- package/dist/cli/kraken/workbenchView.test.js +0 -130
- package/dist/cli/kraken/workbenchView.test.js.map +0 -1
- package/dist/cli/legacyContextIsolation.test.js +0 -65
- package/dist/cli/legacyContextIsolation.test.js.map +0 -1
- package/dist/cli/lsp/tools.test.js +0 -90
- package/dist/cli/lsp/tools.test.js.map +0 -1
- package/dist/cli/missionContinuation.test.js +0 -117
- package/dist/cli/missionContinuation.test.js.map +0 -1
- package/dist/cli/profileMatrix.test.js +0 -130
- package/dist/cli/profileMatrix.test.js.map +0 -1
- package/dist/cli/provider/capabilities.test.js +0 -46
- package/dist/cli/provider/capabilities.test.js.map +0 -1
- package/dist/cli/provider/openai-compatible.timeout.test.js +0 -72
- package/dist/cli/provider/openai-compatible.timeout.test.js.map +0 -1
- package/dist/cli/providerConfig.test.js +0 -85
- package/dist/cli/providerConfig.test.js.map +0 -1
- package/dist/cli/sessionReplayInvariant.test.js +0 -187
- package/dist/cli/sessionReplayInvariant.test.js.map +0 -1
- package/dist/cli/sessionSpine.test.js +0 -171
- package/dist/cli/sessionSpine.test.js.map +0 -1
- package/dist/cli/thinking.test.js +0 -214
- package/dist/cli/thinking.test.js.map +0 -1
- package/dist/cli/tools/inspectCommand.schema.test.js +0 -82
- package/dist/cli/tools/inspectCommand.schema.test.js.map +0 -1
- package/dist/cli/tools/inspectCommand.test.js +0 -311
- package/dist/cli/tools/inspectCommand.test.js.map +0 -1
- package/dist/cli/tools/krakenCsvFanout.test.js +0 -200
- package/dist/cli/tools/krakenCsvFanout.test.js.map +0 -1
- package/dist/cli/tools/krakenSelectTool.test.js +0 -246
- package/dist/cli/tools/krakenSelectTool.test.js.map +0 -1
- package/dist/cli/tools/observeBatch.test.js +0 -329
- package/dist/cli/tools/observeBatch.test.js.map +0 -1
- package/dist/cli/tools/taskTool.dynamicChecks.test.js +0 -156
- package/dist/cli/tools/taskTool.dynamicChecks.test.js.map +0 -1
- package/dist/cli/tools/taskTool.planSafety.test.js +0 -280
- package/dist/cli/tools/taskTool.planSafety.test.js.map +0 -1
- package/dist/cli/tools/taskTool.verifyReport.test.js +0 -140
- package/dist/cli/tools/taskTool.verifyReport.test.js.map +0 -1
- package/dist/cli/utils/contextGrowthSummary.test.js +0 -74
- package/dist/cli/utils/contextGrowthSummary.test.js.map +0 -1
- package/dist/cli/workspace/planDriftCheck.test.js +0 -146
- package/dist/cli/workspace/planDriftCheck.test.js.map +0 -1
- package/dist/cli/workspace/planStore.test.js +0 -295
- package/dist/cli/workspace/planStore.test.js.map +0 -1
- package/dist/cli/zelariMission.test.js +0 -44
- package/dist/cli/zelariMission.test.js.map +0 -1
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* headlessHistorySeed — Exit-1/E1.2 canonical model-context path.
|
|
3
|
-
*
|
|
4
|
-
* Proves: legacy `--history` is imported one-shot into a fresh spine log,
|
|
5
|
-
* prior turns are then derived from events (never re-imported), resume
|
|
6
|
-
* ignores fresh legacy input, and a disabled spine falls back to the
|
|
7
|
-
* filtered legacy seed (declared discrete fallback).
|
|
8
|
-
*/
|
|
9
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
10
|
-
import { promises as fs } from 'node:fs';
|
|
11
|
-
import path from 'node:path';
|
|
12
|
-
import os from 'node:os';
|
|
13
|
-
import { openHeadlessSpine, seedHeadlessModelHistory } from './headlessSpine.js';
|
|
14
|
-
import { readSessionLog, resolveSessionsDir } from '@zelari/core/session';
|
|
15
|
-
let tmp;
|
|
16
|
-
beforeEach(async () => {
|
|
17
|
-
tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'zelari-history-seed-'));
|
|
18
|
-
});
|
|
19
|
-
afterEach(async () => {
|
|
20
|
-
delete process.env.ZELARI_SESSION_SPINE;
|
|
21
|
-
await fs.rm(tmp, { recursive: true, force: true });
|
|
22
|
-
});
|
|
23
|
-
const legacy = [
|
|
24
|
-
{ role: 'user', content: 'build the login form' },
|
|
25
|
-
{
|
|
26
|
-
role: 'assistant',
|
|
27
|
-
content: '<think>plan</think>Done — see ---QUESTION---\ncontinue?',
|
|
28
|
-
},
|
|
29
|
-
{ role: 'system', content: 'stale system' },
|
|
30
|
-
{ role: 'tool', content: '{"ok":true}' },
|
|
31
|
-
];
|
|
32
|
-
function eventsPath(sessionId) {
|
|
33
|
-
return path.join(resolveSessionsDir({ baseDir: tmp }), sessionId, 'events.jsonl');
|
|
34
|
-
}
|
|
35
|
-
describe('seedHeadlessModelHistory', () => {
|
|
36
|
-
it('imports legacy --history one-shot and returns the derived seed', async () => {
|
|
37
|
-
const handle = await openHeadlessSpine({
|
|
38
|
-
sessionId: 'seed-1',
|
|
39
|
-
baseDir: tmp,
|
|
40
|
-
quiet: true,
|
|
41
|
-
});
|
|
42
|
-
const seed = await seedHeadlessModelHistory(handle, legacy);
|
|
43
|
-
expect(seed.source).toBe('spine-import');
|
|
44
|
-
expect(seed.importedCount).toBe(2);
|
|
45
|
-
// system/tool dropped; <think> + ---QUESTION--- preserved (binding policy)
|
|
46
|
-
expect(seed.history).toHaveLength(2);
|
|
47
|
-
expect(seed.history[0]).toEqual({ role: 'user', content: 'build the login form' });
|
|
48
|
-
expect(seed.history[1]?.role).toBe('assistant');
|
|
49
|
-
expect(seed.history[1]?.content).toContain('<think>plan</think>');
|
|
50
|
-
expect(seed.history[1]?.content).toContain('---QUESTION---');
|
|
51
|
-
// The imported turns are in the log — model-visible ⟺ logged (P1).
|
|
52
|
-
const report = await readSessionLog(eventsPath('seed-1'));
|
|
53
|
-
const texts = report.events
|
|
54
|
-
.filter((e) => e.kind === 'user.message' || e.kind === 'assistant.message')
|
|
55
|
-
.map((e) => e.data.text);
|
|
56
|
-
expect(texts).toEqual(['build the login form', seed.history[1].content]);
|
|
57
|
-
const imported = report.events.find((e) => e.kind === 'assistant.message');
|
|
58
|
-
expect((imported?.data).imported).toBe('legacy-history');
|
|
59
|
-
await handle.close('test-end');
|
|
60
|
-
});
|
|
61
|
-
it('derives from the log on resume and ignores new legacy input', async () => {
|
|
62
|
-
const first = await openHeadlessSpine({
|
|
63
|
-
sessionId: 'seed-2',
|
|
64
|
-
baseDir: tmp,
|
|
65
|
-
quiet: true,
|
|
66
|
-
});
|
|
67
|
-
const s1 = await seedHeadlessModelHistory(first, [
|
|
68
|
-
{ role: 'user', content: 'u-first' },
|
|
69
|
-
{ role: 'assistant', content: 'a-first' },
|
|
70
|
-
]);
|
|
71
|
-
expect(s1.source).toBe('spine-import');
|
|
72
|
-
await first.close('test-end');
|
|
73
|
-
const resumed = await openHeadlessSpine({
|
|
74
|
-
sessionId: 'seed-2',
|
|
75
|
-
baseDir: tmp,
|
|
76
|
-
quiet: true,
|
|
77
|
-
});
|
|
78
|
-
const s2 = await seedHeadlessModelHistory(resumed, [
|
|
79
|
-
{ role: 'user', content: 'u-second-should-be-ignored' },
|
|
80
|
-
]);
|
|
81
|
-
expect(s2.source).toBe('spine');
|
|
82
|
-
expect(s2.importedCount).toBe(0);
|
|
83
|
-
expect(s2.history.map((m) => m.content)).toEqual(['u-first', 'a-first']);
|
|
84
|
-
await resumed.close('test-end');
|
|
85
|
-
});
|
|
86
|
-
it('falls back to the filtered legacy seed when the spine is disabled', async () => {
|
|
87
|
-
process.env.ZELARI_SESSION_SPINE = '0';
|
|
88
|
-
const handle = await openHeadlessSpine({
|
|
89
|
-
sessionId: 'seed-3',
|
|
90
|
-
baseDir: tmp,
|
|
91
|
-
quiet: true,
|
|
92
|
-
});
|
|
93
|
-
const seed = await seedHeadlessModelHistory(handle, legacy);
|
|
94
|
-
expect(seed.source).toBe('legacy-fallback');
|
|
95
|
-
expect(seed.importedCount).toBe(0);
|
|
96
|
-
expect(seed.history.map((m) => m.role)).toEqual(['user', 'assistant']);
|
|
97
|
-
await handle.close('test-end');
|
|
98
|
-
});
|
|
99
|
-
it('returns an empty seed for a fresh log with no legacy history', async () => {
|
|
100
|
-
const handle = await openHeadlessSpine({
|
|
101
|
-
sessionId: 'seed-4',
|
|
102
|
-
baseDir: tmp,
|
|
103
|
-
quiet: true,
|
|
104
|
-
});
|
|
105
|
-
const seed = await seedHeadlessModelHistory(handle);
|
|
106
|
-
expect(seed).toEqual({ history: [], importedCount: 0, source: 'spine' });
|
|
107
|
-
await handle.close('test-end');
|
|
108
|
-
});
|
|
109
|
-
it('keeps model-surface events in conversation order (invariant)', async () => {
|
|
110
|
-
const handle = await openHeadlessSpine({
|
|
111
|
-
sessionId: 'seed-5',
|
|
112
|
-
baseDir: tmp,
|
|
113
|
-
quiet: true,
|
|
114
|
-
});
|
|
115
|
-
const plain = [
|
|
116
|
-
{ role: 'user', content: 'plain user' },
|
|
117
|
-
{ role: 'assistant', content: 'plain assistant' },
|
|
118
|
-
];
|
|
119
|
-
const seed = await seedHeadlessModelHistory(handle, plain);
|
|
120
|
-
expect(seed.source).toBe('spine-import');
|
|
121
|
-
const report = await readSessionLog(eventsPath('seed-5'));
|
|
122
|
-
const kinds = report.events.map((e) => e.kind);
|
|
123
|
-
expect(kinds.indexOf('user.message')).toBeLessThan(kinds.indexOf('assistant.message'));
|
|
124
|
-
// Clean text round-trips byte-identical through import → derive.
|
|
125
|
-
expect(seed.history).toEqual(plain);
|
|
126
|
-
await handle.close('test-end');
|
|
127
|
-
});
|
|
128
|
-
it('derivedModelSeed: compacted → user, tool results dropped (shared policy)', async () => {
|
|
129
|
-
const handle = await openHeadlessSpine({
|
|
130
|
-
sessionId: 'seed-6',
|
|
131
|
-
baseDir: tmp,
|
|
132
|
-
quiet: true,
|
|
133
|
-
});
|
|
134
|
-
await seedHeadlessModelHistory(handle, [{ role: 'user', content: 'u1' }]);
|
|
135
|
-
// A compaction event lands on the spine (TUI /compact or budget policy).
|
|
136
|
-
handle.spine.mirrorBrainEvent({
|
|
137
|
-
type: 'session_compacted',
|
|
138
|
-
summary: 'sum-of-old-turns',
|
|
139
|
-
});
|
|
140
|
-
await handle.spine.flush();
|
|
141
|
-
const afterCompact = await seedHeadlessModelHistory(handle, []);
|
|
142
|
-
expect(afterCompact.source).toBe('spine');
|
|
143
|
-
expect(afterCompact.history.map((m) => `${m.role}:${m.content}`)).toContain('user:sum-of-old-turns');
|
|
144
|
-
// Tool results derive as orphans (no assistant tool_calls block) and
|
|
145
|
-
// must NOT reach the model seed.
|
|
146
|
-
handle.spine.mirrorBrainEvent({
|
|
147
|
-
type: 'tool_execution_end',
|
|
148
|
-
toolCallId: 'call-1',
|
|
149
|
-
result: 'raw tool output',
|
|
150
|
-
isError: false,
|
|
151
|
-
});
|
|
152
|
-
await handle.spine.flush();
|
|
153
|
-
const afterTool = await seedHeadlessModelHistory(handle, []);
|
|
154
|
-
expect(afterTool.history.some((m) => m.role === 'tool')).toBe(false);
|
|
155
|
-
await handle.close('test-end');
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
//# sourceMappingURL=headlessHistorySeed.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"headlessHistorySeed.test.js","sourceRoot":"","sources":["../../src/cli/headlessHistorySeed.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* headlessSessionEvent — Exit-1/E1.4 desktop resume-from-spine contract.
|
|
3
|
-
*
|
|
4
|
-
* Proves the `session_started` NDJSON event advertised by every headless
|
|
5
|
-
* dispatch mode carries the spine session id hosts (Desktop) must replay
|
|
6
|
-
* via `--resume`: turn 1 announces a fresh id, turn 2 resumes the SAME id
|
|
7
|
-
* (seq continues), and the kill-switch announces `disabled` so hosts know
|
|
8
|
-
* the spine will not back the conversation.
|
|
9
|
-
*/
|
|
10
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
11
|
-
import { promises as fs } from 'node:fs';
|
|
12
|
-
import path from 'node:path';
|
|
13
|
-
import os from 'node:os';
|
|
14
|
-
import { openHeadlessSpine, sessionStartedEvent, } from './headlessSpine.js';
|
|
15
|
-
import { readSessionLog, resolveSessionsDir } from '@zelari/core/session';
|
|
16
|
-
let tmp;
|
|
17
|
-
beforeEach(async () => {
|
|
18
|
-
tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'zelari-session-event-'));
|
|
19
|
-
});
|
|
20
|
-
afterEach(async () => {
|
|
21
|
-
delete process.env.ZELARI_SESSION_SPINE;
|
|
22
|
-
await fs.rm(tmp, { recursive: true, force: true });
|
|
23
|
-
});
|
|
24
|
-
function eventsPath(sessionId) {
|
|
25
|
-
return path.join(resolveSessionsDir({ baseDir: tmp }), sessionId, 'events.jsonl');
|
|
26
|
-
}
|
|
27
|
-
describe('sessionStartedEvent (E1.4)', () => {
|
|
28
|
-
it('advertises the spine session id with status ok', async () => {
|
|
29
|
-
const handle = await openHeadlessSpine({
|
|
30
|
-
sessionId: 'desk-turn-1',
|
|
31
|
-
baseDir: tmp,
|
|
32
|
-
quiet: true,
|
|
33
|
-
});
|
|
34
|
-
expect(sessionStartedEvent(handle)).toEqual({
|
|
35
|
-
type: 'session_started',
|
|
36
|
-
sessionId: 'desk-turn-1',
|
|
37
|
-
spine: 'active',
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
it('round-trips: resuming the advertised id continues the same log (seq)', async () => {
|
|
41
|
-
// Turn 1: host captures the advertised session id.
|
|
42
|
-
const turn1 = await openHeadlessSpine({
|
|
43
|
-
sessionId: 'desk-conversation',
|
|
44
|
-
baseDir: tmp,
|
|
45
|
-
quiet: true,
|
|
46
|
-
});
|
|
47
|
-
const announced = sessionStartedEvent(turn1);
|
|
48
|
-
turn1.userMessage('build the login form');
|
|
49
|
-
await turn1.close('turn-1-done');
|
|
50
|
-
// Turn 2: host replays the same id (--resume semantics: adopt, not new).
|
|
51
|
-
const turn2 = await openHeadlessSpine({
|
|
52
|
-
sessionId: announced.sessionId,
|
|
53
|
-
baseDir: tmp,
|
|
54
|
-
quiet: true,
|
|
55
|
-
});
|
|
56
|
-
expect(sessionStartedEvent(turn2).sessionId).toBe(announced.sessionId);
|
|
57
|
-
turn2.userMessage('procedi');
|
|
58
|
-
await turn2.close('turn-2-done');
|
|
59
|
-
// The spine log is ONE conversation: user turns in order, seq continues.
|
|
60
|
-
const report = await readSessionLog(eventsPath(announced.sessionId));
|
|
61
|
-
const events = report.events;
|
|
62
|
-
const userTurns = events
|
|
63
|
-
.filter((e) => e.kind === 'user.message')
|
|
64
|
-
.map((e) => e.data.text);
|
|
65
|
-
expect(userTurns).toEqual(['build the login form', 'procedi']);
|
|
66
|
-
const seqs = events.map((e) => e.seq);
|
|
67
|
-
expect(seqs).toEqual([...seqs].sort((a, b) => a - b));
|
|
68
|
-
});
|
|
69
|
-
it('announces disabled under the kill-switch (host keeps history fallback)', async () => {
|
|
70
|
-
process.env.ZELARI_SESSION_SPINE = '0';
|
|
71
|
-
const handle = await openHeadlessSpine({
|
|
72
|
-
sessionId: 'desk-killswitch',
|
|
73
|
-
baseDir: tmp,
|
|
74
|
-
quiet: true,
|
|
75
|
-
});
|
|
76
|
-
expect(sessionStartedEvent(handle)).toEqual({
|
|
77
|
-
type: 'session_started',
|
|
78
|
-
sessionId: 'desk-killswitch',
|
|
79
|
-
spine: 'disabled',
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
//# sourceMappingURL=headlessSessionEvent.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"headlessSessionEvent.test.js","sourceRoot":"","sources":["../../src/cli/headlessSessionEvent.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* headlessSpine + parseHeadlessFlags 2.0 host wiring.
|
|
3
|
-
*
|
|
4
|
-
* Covers: profile defaults, flag parse/validation, dual-write user.message,
|
|
5
|
-
* interrupt without session.ended, resume seq continuation, portable export.
|
|
6
|
-
*/
|
|
7
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
8
|
-
import { promises as fs } from 'node:fs';
|
|
9
|
-
import path from 'node:path';
|
|
10
|
-
import os from 'node:os';
|
|
11
|
-
import { parseHeadlessFlags, defaultProfileForMode } from './headless.js';
|
|
12
|
-
import { openHeadlessSpine, resolveHeadlessProfileId, exportSessionById, missionStateFromSpine, } from './headlessSpine.js';
|
|
13
|
-
import { readSessionLog } from '@zelari/core/session';
|
|
14
|
-
let tmp;
|
|
15
|
-
beforeEach(async () => {
|
|
16
|
-
tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'zelari-headless-spine-'));
|
|
17
|
-
});
|
|
18
|
-
afterEach(async () => {
|
|
19
|
-
await fs.rm(tmp, { recursive: true, force: true });
|
|
20
|
-
});
|
|
21
|
-
describe('defaultProfileForMode / resolveHeadlessProfileId', () => {
|
|
22
|
-
it('maps mode → profile and lets an explicit id win', () => {
|
|
23
|
-
expect(defaultProfileForMode('kraken')).toBe('kraken/v1');
|
|
24
|
-
expect(defaultProfileForMode('council')).toBe('council/v1');
|
|
25
|
-
expect(defaultProfileForMode('zelari')).toBe('mission/v1');
|
|
26
|
-
expect(resolveHeadlessProfileId('kraken')).toBe('kraken/v1');
|
|
27
|
-
expect(resolveHeadlessProfileId('kraken', 'minimal/v1')).toBe('minimal/v1');
|
|
28
|
-
});
|
|
29
|
-
it('throws on an unknown explicit profile', () => {
|
|
30
|
-
expect(() => resolveHeadlessProfileId('kraken', 'nope/v9')).toThrow(/Unknown profile/);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
describe('parseHeadlessFlags 2.0 flags', () => {
|
|
34
|
-
it('accepts --profile / --resume / --export-session / --strict-done', () => {
|
|
35
|
-
const res = parseHeadlessFlags([
|
|
36
|
-
'--headless',
|
|
37
|
-
'--task',
|
|
38
|
-
'do the thing',
|
|
39
|
-
'--profile',
|
|
40
|
-
'minimal/v1',
|
|
41
|
-
'--resume',
|
|
42
|
-
'sess-abc',
|
|
43
|
-
'--export-session',
|
|
44
|
-
'-',
|
|
45
|
-
'--strict-done',
|
|
46
|
-
]);
|
|
47
|
-
expect(res.error).toBeUndefined();
|
|
48
|
-
expect(res.options).toMatchObject({
|
|
49
|
-
task: 'do the thing',
|
|
50
|
-
profile: 'minimal/v1',
|
|
51
|
-
resumeSessionId: 'sess-abc',
|
|
52
|
-
exportSessionPath: '-',
|
|
53
|
-
strictDone: true,
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
it('rejects an unknown --profile at parse time', () => {
|
|
57
|
-
const res = parseHeadlessFlags(['--headless', '--task', 'x', '--profile', 'ghost/v1']);
|
|
58
|
-
expect(res.options).toBeNull();
|
|
59
|
-
expect(res.error).toMatch(/Unknown profile/);
|
|
60
|
-
});
|
|
61
|
-
it('--resume without an id is a user error', () => {
|
|
62
|
-
const res = parseHeadlessFlags(['--headless', '--task', 'x', '--resume']);
|
|
63
|
-
expect(res.options).toBeNull();
|
|
64
|
-
expect(res.error).toMatch(/--resume requires/);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
describe('openHeadlessSpine', () => {
|
|
68
|
-
it('records profile + user.message and closes with session.ended', async () => {
|
|
69
|
-
const handle = await openHeadlessSpine({
|
|
70
|
-
sessionId: 'h-a',
|
|
71
|
-
mode: 'kraken',
|
|
72
|
-
profile: 'minimal/v1',
|
|
73
|
-
workspace: tmp,
|
|
74
|
-
baseDir: tmp,
|
|
75
|
-
quiet: true,
|
|
76
|
-
});
|
|
77
|
-
expect(handle.profileId).toBe('minimal/v1');
|
|
78
|
-
handle.userMessage('write a test');
|
|
79
|
-
handle.observe({
|
|
80
|
-
type: 'message_delta',
|
|
81
|
-
messageId: 'm1',
|
|
82
|
-
delta: 'ok',
|
|
83
|
-
id: 'e1',
|
|
84
|
-
ts: 1,
|
|
85
|
-
sessionId: 'h-a',
|
|
86
|
-
});
|
|
87
|
-
handle.observe({
|
|
88
|
-
type: 'message_end',
|
|
89
|
-
messageId: 'm1',
|
|
90
|
-
totalLength: 2,
|
|
91
|
-
finishReason: 'stop',
|
|
92
|
-
id: 'e2',
|
|
93
|
-
ts: 2,
|
|
94
|
-
sessionId: 'h-a',
|
|
95
|
-
});
|
|
96
|
-
await handle.close('completed');
|
|
97
|
-
const report = await readSessionLog(path.join(tmp, 'h-a', 'events.jsonl'));
|
|
98
|
-
const kinds = report.events.map((e) => e.kind);
|
|
99
|
-
expect(kinds[0]).toBe('session.started');
|
|
100
|
-
expect(kinds).toContain('user.message');
|
|
101
|
-
expect(kinds).toContain('assistant.message');
|
|
102
|
-
expect(kinds.at(-1)).toBe('session.ended');
|
|
103
|
-
expect(report.events[0].data.profile).toBe('minimal/v1');
|
|
104
|
-
});
|
|
105
|
-
it('interrupt releases the lock WITHOUT session.ended (resumable)', async () => {
|
|
106
|
-
const handle = await openHeadlessSpine({
|
|
107
|
-
sessionId: 'h-b',
|
|
108
|
-
mode: 'zelari',
|
|
109
|
-
baseDir: tmp,
|
|
110
|
-
quiet: true,
|
|
111
|
-
});
|
|
112
|
-
handle.userMessage('long mission');
|
|
113
|
-
handle.missionPhase('build', 'impl-1');
|
|
114
|
-
await handle.interrupt('SIGINT');
|
|
115
|
-
const report = await readSessionLog(path.join(tmp, 'h-b', 'events.jsonl'));
|
|
116
|
-
expect(report.events.some((e) => e.kind === 'session.ended')).toBe(false);
|
|
117
|
-
expect(report.events.some((e) => e.kind === 'mission.phase')).toBe(true);
|
|
118
|
-
const state = await missionStateFromSpine('h-b', tmp);
|
|
119
|
-
expect(state).not.toBeNull();
|
|
120
|
-
expect(state.interrupted).toBe(true);
|
|
121
|
-
expect(state.phase).toBe('build');
|
|
122
|
-
const resumed = await openHeadlessSpine({
|
|
123
|
-
sessionId: 'h-b',
|
|
124
|
-
mode: 'zelari',
|
|
125
|
-
baseDir: tmp,
|
|
126
|
-
quiet: true,
|
|
127
|
-
});
|
|
128
|
-
resumed.userMessage('continue');
|
|
129
|
-
await resumed.close('completed');
|
|
130
|
-
const again = await readSessionLog(path.join(tmp, 'h-b', 'events.jsonl'));
|
|
131
|
-
expect(again.events.some((e) => e.kind === 'session.resumed')).toBe(true);
|
|
132
|
-
again.events.forEach((e, i) => expect(e.seq).toBe(i + 1));
|
|
133
|
-
});
|
|
134
|
-
it('exportSessionById produces zelari-session-export/1', async () => {
|
|
135
|
-
const handle = await openHeadlessSpine({
|
|
136
|
-
sessionId: 'h-c',
|
|
137
|
-
mode: 'council',
|
|
138
|
-
baseDir: tmp,
|
|
139
|
-
quiet: true,
|
|
140
|
-
});
|
|
141
|
-
handle.userMessage('design this');
|
|
142
|
-
await handle.close('completed');
|
|
143
|
-
const exported = await exportSessionById('h-c', tmp);
|
|
144
|
-
expect(exported.ok).toBe(true);
|
|
145
|
-
if (!exported.ok)
|
|
146
|
-
return;
|
|
147
|
-
const parsed = JSON.parse(exported.json);
|
|
148
|
-
expect(parsed.format).toBe('zelari-session-export');
|
|
149
|
-
expect(parsed.version).toBe(1);
|
|
150
|
-
expect(parsed.sessionId).toBe('h-c');
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
//# sourceMappingURL=headlessSpine.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"headlessSpine.test.js","sourceRoot":"","sources":["../../src/cli/headlessSpine.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* observationStore + retrieve_observation — Fase 2 acceptance.
|
|
3
|
-
*/
|
|
4
|
-
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import { promises as fs } from 'node:fs';
|
|
6
|
-
import os from 'node:os';
|
|
7
|
-
import path from 'node:path';
|
|
8
|
-
import { SessionJsonlWriter } from '@zelari/core/harness';
|
|
9
|
-
import { createBrainEvent } from '@zelari/core/events';
|
|
10
|
-
import { getObservationBySeq, getSeqForToolCallId, indexEventsForTests, ingestLiveEvent, invalidateObservationIndex, loadObservationIndex, } from './observationStore.js';
|
|
11
|
-
import { formatObservationStub } from './sessionSurface.js';
|
|
12
|
-
import { createRetrieveObservationTool, parseSeqRef } from '../tools/retrieveObservation.js';
|
|
13
|
-
const abort = new AbortController().signal;
|
|
14
|
-
function ctx(sessionId) {
|
|
15
|
-
return {
|
|
16
|
-
signal: abort,
|
|
17
|
-
cwd: process.cwd(),
|
|
18
|
-
sessionId,
|
|
19
|
-
audit: () => undefined,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
describe('parseSeqRef', () => {
|
|
23
|
-
it('accepts number, #N and ref=#N', () => {
|
|
24
|
-
expect(parseSeqRef(12)).toBe(12);
|
|
25
|
-
expect(parseSeqRef('#12')).toBe(12);
|
|
26
|
-
expect(parseSeqRef('ref=#12')).toBe(12);
|
|
27
|
-
expect(parseSeqRef('OBSERVATION ref=#3')).toBe(3);
|
|
28
|
-
expect(parseSeqRef('nope')).toBeNull();
|
|
29
|
-
expect(parseSeqRef(0)).toBeNull();
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
describe('observationStore from JSONL', () => {
|
|
33
|
-
let dir;
|
|
34
|
-
afterEach(async () => {
|
|
35
|
-
invalidateObservationIndex();
|
|
36
|
-
if (dir)
|
|
37
|
-
await fs.rm(dir, { recursive: true, force: true });
|
|
38
|
-
});
|
|
39
|
-
it('assigns monotonic 1-based seq in file order and rematerializes', async () => {
|
|
40
|
-
dir = await fs.mkdtemp(path.join(os.tmpdir(), 'zelari-obs-'));
|
|
41
|
-
const sid = 'sess-a';
|
|
42
|
-
const w = new SessionJsonlWriter(sid, { baseDir: dir, flushIntervalMs: 60_000 });
|
|
43
|
-
const start1 = createBrainEvent('tool_execution_start', sid, {
|
|
44
|
-
toolCallId: 'c1',
|
|
45
|
-
toolName: 'read_file',
|
|
46
|
-
args: { path: 'a.ts' },
|
|
47
|
-
});
|
|
48
|
-
const end1 = createBrainEvent('tool_execution_end', sid, {
|
|
49
|
-
toolCallId: 'c1',
|
|
50
|
-
result: 'FILE-ONE-BODY',
|
|
51
|
-
isError: false,
|
|
52
|
-
durationMs: 11,
|
|
53
|
-
});
|
|
54
|
-
const start2 = createBrainEvent('tool_execution_start', sid, {
|
|
55
|
-
toolCallId: 'c2',
|
|
56
|
-
toolName: 'grep_content',
|
|
57
|
-
args: { pattern: 'x' },
|
|
58
|
-
});
|
|
59
|
-
const end2 = createBrainEvent('tool_execution_end', sid, {
|
|
60
|
-
toolCallId: 'c2',
|
|
61
|
-
result: 'FILE-TWO-BODY',
|
|
62
|
-
isError: false,
|
|
63
|
-
durationMs: 22,
|
|
64
|
-
});
|
|
65
|
-
void w.append(start1);
|
|
66
|
-
void w.append(end1);
|
|
67
|
-
void w.append(start2);
|
|
68
|
-
void w.append(end2);
|
|
69
|
-
await w.flush();
|
|
70
|
-
const index = await loadObservationIndex(sid, dir);
|
|
71
|
-
expect(index.bySeq.size).toBe(2);
|
|
72
|
-
expect(await getSeqForToolCallId(sid, 'c2', dir)).toBe(2);
|
|
73
|
-
const rec = await getObservationBySeq(sid, 1, dir);
|
|
74
|
-
expect(rec?.result).toBe('FILE-ONE-BODY');
|
|
75
|
-
expect(rec?.toolName).toBe('read_file');
|
|
76
|
-
const tool = createRetrieveObservationTool({ sessionId: sid, baseDir: dir });
|
|
77
|
-
const hit = await tool.execute({ seq: '#2' }, ctx(sid));
|
|
78
|
-
expect(hit.ok).toBe(true);
|
|
79
|
-
if (hit.ok) {
|
|
80
|
-
expect(hit.value.result).toBe('FILE-TWO-BODY');
|
|
81
|
-
expect(hit.value.tool).toBe('grep_content');
|
|
82
|
-
expect(hit.value.seq).toBe(2);
|
|
83
|
-
}
|
|
84
|
-
const miss = await tool.execute({ seq: 99 }, ctx(sid));
|
|
85
|
-
expect(miss.ok).toBe(false);
|
|
86
|
-
await w.close();
|
|
87
|
-
});
|
|
88
|
-
it('ingestLiveEvent is idempotent and retrieve works before flush', async () => {
|
|
89
|
-
const sid = 'live-sess';
|
|
90
|
-
const start = createBrainEvent('tool_execution_start', sid, {
|
|
91
|
-
toolCallId: 'live-1',
|
|
92
|
-
toolName: 'list_files',
|
|
93
|
-
args: {},
|
|
94
|
-
});
|
|
95
|
-
const end = createBrainEvent('tool_execution_end', sid, {
|
|
96
|
-
toolCallId: 'live-1',
|
|
97
|
-
result: 'LIVE-BODY',
|
|
98
|
-
isError: false,
|
|
99
|
-
durationMs: 5,
|
|
100
|
-
});
|
|
101
|
-
ingestLiveEvent(sid, start);
|
|
102
|
-
ingestLiveEvent(sid, end);
|
|
103
|
-
ingestLiveEvent(sid, end); // idempotent
|
|
104
|
-
const rec = await getObservationBySeq(sid, 1);
|
|
105
|
-
expect(rec?.result).toBe('LIVE-BODY');
|
|
106
|
-
expect(await getSeqForToolCallId(sid, 'live-1')).toBe(1);
|
|
107
|
-
});
|
|
108
|
-
it('refuses to rematerialize a stub that leaked into the log', async () => {
|
|
109
|
-
const sid = 'stub-sess';
|
|
110
|
-
const stub = formatObservationStub({ seq: 1, tool: 'read_file', bytes: 10 });
|
|
111
|
-
indexEventsForTests(sid, [
|
|
112
|
-
createBrainEvent('tool_execution_end', sid, {
|
|
113
|
-
toolCallId: 's1',
|
|
114
|
-
result: stub,
|
|
115
|
-
isError: false,
|
|
116
|
-
durationMs: 1,
|
|
117
|
-
}),
|
|
118
|
-
]);
|
|
119
|
-
const tool = createRetrieveObservationTool({ sessionId: sid, baseDir: os.tmpdir() });
|
|
120
|
-
const res = await tool.execute({ seq: 1 }, ctx(sid));
|
|
121
|
-
expect(res.ok).toBe(false);
|
|
122
|
-
if (!res.ok)
|
|
123
|
-
expect(res.meta?.warnings).toContain('STUB_IN_LOG');
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
describe('retrieve_observation session guard', () => {
|
|
127
|
-
it('fails clearly without a real session id', async () => {
|
|
128
|
-
const tool = createRetrieveObservationTool();
|
|
129
|
-
const res = await tool.execute({ seq: 1 }, ctx('cli'));
|
|
130
|
-
expect(res.ok).toBe(false);
|
|
131
|
-
if (!res.ok)
|
|
132
|
-
expect(res.meta?.warnings).toContain('NO_SESSION');
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
//# sourceMappingURL=observationStore.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"observationStore.test.js","sourceRoot":"","sources":["../../../src/cli/hooks/observationStore.test.ts"],"names":[],"mappings":"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"}
|