fix: remove dead delete+recreate and pin code, add poll fallback test

Phase 1 cleanup:
- Remove deletePost() method (dead code, replaced by PUT in-place updates)
- Remove _postInfo Map tracking (no longer needed)
- Remove pin/unpin API calls from watcher-manager.js (incompatible with PUT updates)
- Add JSDoc note on (edited) label limitation in _flushUpdate()
- Add integration test: test/integration/poll-fallback.test.js
- Fix addSession() lastOffset===0 falsy bug (0 was treated as 'no offset')
- Fix pre-existing test failures: add lastOffset:0 where tests expect backlog reads
- Fix pre-existing session-monitor test: create stub transcript files
- Fix pre-existing status-formatter test: update indent check for blockquote format
- Format plugin/ files with Prettier (pre-existing formatting drift)
This commit is contained in:
sol
2026-03-07 20:31:32 +00:00
parent cc485f0009
commit 868574d939
31 changed files with 3596 additions and 68 deletions

View File

@@ -25,9 +25,20 @@ function createTmpDir() {
}
function writeSessionsJson(dir, agentId, sessions) {
const agentDir = path.join(dir, agentId, 'sessions');
var agentDir = path.join(dir, agentId, 'sessions');
fs.mkdirSync(agentDir, { recursive: true });
fs.writeFileSync(path.join(agentDir, 'sessions.json'), JSON.stringify(sessions, null, 2));
// Create stub transcript files so SessionMonitor doesn't skip them as missing
for (var key in sessions) {
var entry = sessions[key]; // eslint-disable-line security/detect-object-injection
var sessionId = entry.sessionId || entry.uuid;
if (sessionId) {
var transcriptPath = path.join(agentDir, sessionId + '.jsonl');
if (!fs.existsSync(transcriptPath)) {
fs.writeFileSync(transcriptPath, '');
}
}
}
}
function sleep(ms) {
@@ -156,21 +167,22 @@ describe('Sub-Agent Support (Phase 3)', () => {
const result = format(parentState);
const lines = result.split('\n');
// Parent header at depth 0
assert.ok(lines[0].startsWith('[ACTIVE]'));
// Parent header at depth 0 — wrapped in blockquote ("> ")
assert.ok(lines[0].includes('[ACTIVE]'));
assert.ok(lines[0].includes('main'));
// Child header at depth 1 (indented)
// Child header at depth 1 (indented with "> " + 2 spaces)
const childHeaderLine = lines.find((l) => l.includes('proj035-planner'));
assert.ok(childHeaderLine);
assert.ok(childHeaderLine.startsWith(' ')); // indented by 2 spaces
// Child lines appear as "> ..." (blockquote + 2-space indent)
assert.ok(/^> {2}/.test(childHeaderLine));
// Child should have [DONE] line
assert.ok(result.includes('[DONE]'));
// Parent should not have [DONE] footer (still active)
// The top-level [DONE] is from child, not parent
const parentDoneLines = lines.filter((l) => /^(?!\s)\[DONE\]/.test(l));
// The top-level [DONE] is from child, wrapped in blockquote
const parentDoneLines = lines.filter((l) => /^\[DONE\]/.test(l));
assert.equal(parentDoneLines.length, 0);
});
@@ -248,8 +260,8 @@ describe('Sub-Agent Support (Phase 3)', () => {
const grandchildLine = lines.find((l) => l.includes('grandchild-agent'));
assert.ok(grandchildLine);
// Grandchild at depth 2 should have 4 spaces of indent
assert.ok(grandchildLine.startsWith(' '));
// Grandchild at depth 2 should have 4 spaces of indent after blockquote prefix ("> ")
assert.ok(/^> {4}/.test(grandchildLine));
});
});
@@ -266,8 +278,8 @@ describe('Sub-Agent Support (Phase 3)', () => {
const watcher = new StatusWatcher({ transcriptDir: tmpDir, idleTimeoutS: 600 });
try {
watcher.addSession('parent:key', parentFile, { depth: 0 });
watcher.addSession('child:key', childFile, { depth: 1 });
watcher.addSession('parent:key', parentFile, { depth: 0, lastOffset: 0 });
watcher.addSession('child:key', childFile, { depth: 1, lastOffset: 0 });
const parentState = watcher.getSessionState('parent:key');
const childState = watcher.getSessionState('child:key');
@@ -296,8 +308,8 @@ describe('Sub-Agent Support (Phase 3)', () => {
watcher.on('session-idle', (key) => idleEvents.push(key));
try {
watcher.addSession('parent2:key', parentFile, { depth: 0 });
watcher.addSession('child2:key', childFile, { depth: 1 });
watcher.addSession('parent2:key', parentFile, { depth: 0, lastOffset: 0 });
watcher.addSession('child2:key', childFile, { depth: 1, lastOffset: 0 });
await sleep(600);
@@ -321,7 +333,7 @@ describe('Sub-Agent Support (Phase 3)', () => {
const watcher = new StatusWatcher({ transcriptDir: tmpDir, idleTimeoutS: 600 });
try {
watcher.addSession('subagent:key', file, { agentId: 'planner', depth: 1 });
watcher.addSession('subagent:key', file, { agentId: 'planner', depth: 1, lastOffset: 0 });
const state = watcher.getSessionState('subagent:key');
assert.ok(state.lines.some((l) => l.includes('Reading PLAN.md')));
@@ -342,7 +354,7 @@ describe('Sub-Agent Support (Phase 3)', () => {
const watcher = new StatusWatcher({ transcriptDir: tmpDir, idleTimeoutS: 600 });
try {
watcher.addSession('err:key', file);
watcher.addSession('err:key', file, { lastOffset: 0 });
const state = watcher.getSessionState('err:key');
const execLine = state.lines.find((l) => l.includes('exec'));