[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
135
infrastructure/ai/harness/sessionState.test.ts
Normal file
135
infrastructure/ai/harness/sessionState.test.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { SessionStateStore } from './sessionState.ts';
|
||||
|
||||
test('SessionStateStore tracks terminal commands and reinjection text', () => {
|
||||
const store = new SessionStateStore();
|
||||
store.mergeFromUserGoal('chat-1', 'Fix nginx upstream timeout');
|
||||
store.updateFromToolResult(
|
||||
'chat-1',
|
||||
'terminal_execute',
|
||||
{ sessionId: 'sess-1', command: 'tail -n 100 /var/log/nginx/error.log' },
|
||||
'upstream timed out',
|
||||
false,
|
||||
);
|
||||
|
||||
const text = store.toReinjectionText('chat-1');
|
||||
assert.ok(text?.includes('Fix nginx upstream timeout'));
|
||||
assert.ok(text?.includes('sess-1'));
|
||||
assert.ok(text?.includes('tail -n 100'));
|
||||
});
|
||||
|
||||
test('SessionStateStore records tool errors as blockers', () => {
|
||||
const store = new SessionStateStore();
|
||||
store.updateFromToolResult(
|
||||
'chat-1',
|
||||
'terminal_execute',
|
||||
{ sessionId: 'sess-1', command: 'systemctl restart nginx' },
|
||||
'{ "error": "Job failed" }',
|
||||
true,
|
||||
);
|
||||
const text = store.toReinjectionText('chat-1');
|
||||
assert.ok(text?.includes('Open blockers'));
|
||||
});
|
||||
|
||||
test('SessionStateStore restores active background jobs and poll cursors', () => {
|
||||
const store = new SessionStateStore();
|
||||
store.updateFromToolResult(
|
||||
'chat-1',
|
||||
'terminal_start',
|
||||
{ sessionId: 'sess-1', command: 'npm run dev' },
|
||||
JSON.stringify({ ok: true, jobId: 'job-1', status: 'running', nextOffset: 0 }),
|
||||
);
|
||||
store.updateFromToolResult(
|
||||
'chat-1',
|
||||
'terminal_poll',
|
||||
{ jobId: 'job-1', offset: 0 },
|
||||
JSON.stringify({ ok: true, jobId: 'job-1', status: 'running', nextOffset: 420 }),
|
||||
);
|
||||
|
||||
const state = store.get('chat-1');
|
||||
assert.equal(state.version, 1);
|
||||
assert.equal(state.activeJobs['job-1'].nextOffset, 420);
|
||||
const text = store.toReinjectionText('chat-1') ?? '';
|
||||
assert.match(text, /job-1/);
|
||||
assert.match(text, /offset=420/);
|
||||
assert.match(text, /poll the existing job/i);
|
||||
assert.match(text, /do not restart/i);
|
||||
assert.match(text, /unverified after compaction/i);
|
||||
});
|
||||
|
||||
test('SessionStateStore drops a remembered job after poll reports it missing', () => {
|
||||
const store = new SessionStateStore();
|
||||
store.updateFromToolResult(
|
||||
'chat-1', 'terminal_start', { sessionId: 'sess-1', command: 'npm run dev' },
|
||||
JSON.stringify({ jobId: 'job-lost', status: 'running' }), false,
|
||||
);
|
||||
store.updateFromToolResult(
|
||||
'chat-1', 'terminal_poll', { jobId: 'job-lost', offset: 0 },
|
||||
JSON.stringify({ error: 'Job not found' }), true,
|
||||
);
|
||||
assert.equal(store.get('chat-1').activeJobs['job-lost'], undefined);
|
||||
assert.doesNotMatch(store.toReinjectionText('chat-1') ?? '', /Remembered terminal jobs/);
|
||||
});
|
||||
|
||||
test('SessionStateStore preserves a running job after a transient poll error', () => {
|
||||
const store = new SessionStateStore();
|
||||
store.updateFromToolResult(
|
||||
'chat-1', 'terminal_start', { sessionId: 'sess-1', command: 'npm run dev' },
|
||||
JSON.stringify({ jobId: 'job-running', status: 'running', nextOffset: 420 }), false,
|
||||
);
|
||||
store.updateFromToolResult(
|
||||
'chat-1', 'terminal_poll', { jobId: 'job-running', offset: 420 },
|
||||
JSON.stringify({ error: 'temporary IPC timeout' }), true,
|
||||
);
|
||||
|
||||
const job = store.get('chat-1').activeJobs['job-running'];
|
||||
assert.equal(job.status, 'unverified');
|
||||
assert.equal(job.nextOffset, 420);
|
||||
assert.match(store.toReinjectionText('chat-1') ?? '', /job-running/);
|
||||
assert.match(store.toReinjectionText('chat-1') ?? '', /do not restart/i);
|
||||
});
|
||||
|
||||
test('SessionStateStore drops a job after poll confirms cancellation', () => {
|
||||
const store = new SessionStateStore();
|
||||
store.updateFromToolResult(
|
||||
'chat-1', 'terminal_start', { sessionId: 'sess-1', command: 'npm run dev' },
|
||||
JSON.stringify({ jobId: 'job-cancelled', status: 'running' }), false,
|
||||
);
|
||||
store.updateFromToolResult(
|
||||
'chat-1', 'terminal_poll', { jobId: 'job-cancelled', offset: 0 },
|
||||
JSON.stringify({ jobId: 'job-cancelled', status: 'cancelled', error: 'Cancelled' }), true,
|
||||
);
|
||||
|
||||
assert.equal(store.get('chat-1').activeJobs['job-cancelled'], undefined);
|
||||
});
|
||||
|
||||
test('SessionStateStore records the last terminal screen range read', () => {
|
||||
const store = new SessionStateStore();
|
||||
store.updateFromToolResult(
|
||||
'chat-1',
|
||||
'terminal_read_context',
|
||||
{ sessionId: 'sess-1', range: 'tail', startLine: 80, maxLines: 20 },
|
||||
JSON.stringify({ ok: true, sessionId: 'sess-1', startLine: 80, endLine: 99 }),
|
||||
);
|
||||
|
||||
assert.deepEqual(store.get('chat-1').terminalReadCursors['sess-1'], {
|
||||
range: 'tail',
|
||||
startLine: 80,
|
||||
endLine: 99,
|
||||
});
|
||||
});
|
||||
|
||||
test('SessionStateStore reinjects edited files and unfinished plan items', () => {
|
||||
const store = new SessionStateStore();
|
||||
store.mergeFileChanges('chat-1', ['/repo/src/a.ts', '/repo/src/b.ts']);
|
||||
store.mergePlan('chat-1', [
|
||||
{ text: 'inspect failure', completed: true },
|
||||
{ text: 'run regression tests', completed: false },
|
||||
]);
|
||||
|
||||
const text = store.toReinjectionText('chat-1') ?? '';
|
||||
assert.match(text, /\/repo\/src\/a\.ts/);
|
||||
assert.match(text, /\[done\] inspect failure/);
|
||||
assert.match(text, /\[todo\] run regression tests/);
|
||||
});
|
||||
Reference in New Issue
Block a user