| feat(gateway): hot-reload extension changes without transcript replay
Temporarily ignore project-local YAML so global config stays authoritative while cached sessions can pick up config and plugin or skill updates on the next turn without rereading transcripts.
Co-authored-by: Cursor <cursoragent@cursor.com>
| 19 天前 |
| fix: cross-platform Windows compatibility for core runtime
- paths.ts: normalize Windows backslashes and strip drive letters in project IDs
- createBackup/restoreBackup: guard fs.chmod on Windows (no Unix permissions)
- ProjectSessionStorage: sanitize illegal Windows filename characters (:, <, >, ", |, ?, *)
- JsonlTranscriptWriter: use path.join for subagent paths instead of hardcoded /
- BackgroundTaskRuntime: remove platform guard, let Windows use the same runtime
- commandRunner: Windows-compatible process termination (taskkill vs SIGTERM)
- listProjects: platform-aware project ID resolution
- createLocalGateway: sanitize session keys for browser screenshot paths
- pilotPaths.js: sync createLegacyProjectId with paths.ts normalization
- package.json: cross-platform build script using Node.js fs module
Co-authored-by: Cursor <cursoragent@cursor.com>
| 9 天前 |
| feat(session): close 6 deferred gates — parent chain, compact boundary, metadata, listing/search
Closes session deferred gates per docs/politdeck-session-refactor-development-guide.md §11:
1. session-parent-chain — new TranscriptChain.ts buildConversationChain()
builds a DAG from entryId/parentEntryId links and picks the longest
root→leaf path. Falls back to sequence order for pre-chain transcripts.
Orphans (missing parentEntryId) are appended at the end of the chain
(partial parity with legacy recoverOrphanedParallelToolResults).
2. session-compact-boundary — already resolved in Phase 1.5 (control_boundary
schema + findLastCompactBoundaryIndex + TranscriptReplay slicing). Doc
status updated from deferred to resolved.
3. session-metadata-store — SessionMetadataStore.restoreFromReplay() seeds
the in-memory snapshot from replayed metadata without writing to the
transcript. reappendTail() re-appends the full metadata snapshot at the
transcript tail so readSessionLite() (head/tail reader) can see the
latest title/tag without scanning the whole file. resumeAgentSession()
now returns metadata and uses restoreFromReplay.
4. session-listing + session-lite-reader — listAllSessions({ politHome })
scans all projects under {politHome}/projects/*/chats/*.jsonl.
searchSessionsByTitle({ projectRoot, politHome, query }) does
case-insensitive substring match against customTitle / aiTitle /
firstPrompt. Both return results sorted by lastModified descending.
Tests:
- tests/session/transcript/chain.test.ts (5 cases): linear chain, longest
branch selection, orphan recovery, no-entryId fallback, empty input.
- tests/session/metadata/metadata-store.test.ts (4 cases): restoreFromReplay,
reappendTail writes, empty no-op, restore+save merge.
- tests/session/storage/list-all-sessions.test.ts (6 cases): cross-project
listing, limit/offset pagination, missing dir, title search match,
firstPrompt fallback match, case-insensitive search.
Docs:
- §3 adds implementation progress table (6 features resolved).
- §9 Feature Matrix: 5 rows upgraded from deferred/partial to compare.
- §11 Deferred Register: 6 gates marked resolved with resolution notes.
Regression: 301 / 297 pass / 4 skipped (real-API e2e) / 0 fail.
Co-authored-by: Cursor <cursoragent@cursor.com>
| 24 天前 |
| feat(deferred-features): wave 4 — C2 subagent fork + C3 sidechain transcript
C2 subagent fork full:
- src/agent/sub/{builtinSubagentTypes,buildForkedMessages,filterIncompleteToolCalls,
contextInheritance,SubAgentSession,types,index}
- 3 built-in presets: general-purpose / explore / plan with shared S3 prompt
prefix and per-preset tool allow-lists (* / read+grep+glob+bash / read+grep+glob)
- buildForkedMessages: parent assistant verbatim + synthetic tool_result with
byte-stable FORK_PLACEHOLDER_RESULT for cache hit (S1, S2)
- buildChildMessage: <politdeck-fork> boilerplate with 10 rules + 5-field output
format (S3)
- filterIncompleteToolCalls: drops orphan tool_use blocks (S4)
- cloneReadFileState + applySystemPromptFilters: claudeMd/git-status filtering
for explore/plan (S5, S7, S8)
- SubAgentSession runs a real AgentLoop with scoped registry, system prompt
inheritance, abortSignal cascade, and 5-field summary parsing
- AgentLoop wires PolitDeckSubagentForkApi onto every tool runtime context;
agent tool reroutes to fork mode when context.subagent is wired, falls back
to legacy single-shot model call otherwise
- subagentDepth + maxSubagentDepth (default 1) blocks nested forks
C3 sidechain transcript:
- AgentSubagentStartedTranscriptEntry / AgentSubagentCompletedTranscriptEntry
+ truncatePreview() for 1KB prompt / 4KB summary byte caps
- JsonlTranscriptWriter: recordSubagentStarted / recordSubagentCompleted /
forSubagent (independent sidechain writer) / relativeSubagentPath
- ProjectSessionStorage: subagentsDir + subagentTranscriptPath; default sidechain
layout <sessionId>/subagents/<subagentId>.jsonl
- AgentRuntimeDependencies.subagentTranscript hooks (lazy: when present,
AgentLoop.fork records started/completed in parent + threads sidechain
writer into SubAgentSession)
- TranscriptReplay skips subagent_* entries (lazy load)
- replaySubagentTranscript() helper for explicit sidechain inspection
tests:
- 22 new C2 tests (build-forked-messages / filter-incomplete /
context-inheritance / subagent-session / depth-guard)
- 12 new C3 tests (subagent-sidechain / replay-subagent /
subagent-transcript-integration)
- full suite: 475 tests, 471 pass, 4 skipped, 0 fail
Co-authored-by: Cursor <cursoragent@cursor.com>
| 24 天前 |
| fix(transcript): restore sequence counter on resume to prevent message interleaving
The JsonlTranscriptWriter's sequence counter reset to 0 on each
resume, producing duplicate sequence values in the same JSONL file.
readTranscript sorted only by sequence with no tie-breaker, causing
messages from different turns to interleave after reopen.
- Add restoreState() to JsonlTranscriptWriter for re-seeding counters
- Call restoreState in resumeAgentSession after reading existing entries
- Add createdAt tie-breaker to readTranscript sort for corrupted files
Co-authored-by: Cursor <cursoragent@cursor.com>
| 20 天前 |
| fix(model): deep-clone nested content in cloneMessages
cloneMessages used spread to shallow-copy content blocks, leaving
CanonicalToolResultBlock.content and CanonicalToolCallBlock.input
as shared references between original and clone. Extract a shared
clone utility that deep-copies these nested structures and replace
three duplicate private implementations.
Co-authored-by: Cursor <cursoragent@cursor.com>
| 8 天前 |
| feat(gateway): hot-reload extension changes without transcript replay
Temporarily ignore project-local YAML so global config stays authoritative while cached sessions can pick up config and plugin or skill updates on the next turn without rereading transcripts.
Co-authored-by: Cursor <cursoragent@cursor.com>
| 19 天前 |
| feat(deferred-features): wave 4 — C2 subagent fork + C3 sidechain transcript
C2 subagent fork full:
- src/agent/sub/{builtinSubagentTypes,buildForkedMessages,filterIncompleteToolCalls,
contextInheritance,SubAgentSession,types,index}
- 3 built-in presets: general-purpose / explore / plan with shared S3 prompt
prefix and per-preset tool allow-lists (* / read+grep+glob+bash / read+grep+glob)
- buildForkedMessages: parent assistant verbatim + synthetic tool_result with
byte-stable FORK_PLACEHOLDER_RESULT for cache hit (S1, S2)
- buildChildMessage: <politdeck-fork> boilerplate with 10 rules + 5-field output
format (S3)
- filterIncompleteToolCalls: drops orphan tool_use blocks (S4)
- cloneReadFileState + applySystemPromptFilters: claudeMd/git-status filtering
for explore/plan (S5, S7, S8)
- SubAgentSession runs a real AgentLoop with scoped registry, system prompt
inheritance, abortSignal cascade, and 5-field summary parsing
- AgentLoop wires PolitDeckSubagentForkApi onto every tool runtime context;
agent tool reroutes to fork mode when context.subagent is wired, falls back
to legacy single-shot model call otherwise
- subagentDepth + maxSubagentDepth (default 1) blocks nested forks
C3 sidechain transcript:
- AgentSubagentStartedTranscriptEntry / AgentSubagentCompletedTranscriptEntry
+ truncatePreview() for 1KB prompt / 4KB summary byte caps
- JsonlTranscriptWriter: recordSubagentStarted / recordSubagentCompleted /
forSubagent (independent sidechain writer) / relativeSubagentPath
- ProjectSessionStorage: subagentsDir + subagentTranscriptPath; default sidechain
layout <sessionId>/subagents/<subagentId>.jsonl
- AgentRuntimeDependencies.subagentTranscript hooks (lazy: when present,
AgentLoop.fork records started/completed in parent + threads sidechain
writer into SubAgentSession)
- TranscriptReplay skips subagent_* entries (lazy load)
- replaySubagentTranscript() helper for explicit sidechain inspection
tests:
- 22 new C2 tests (build-forked-messages / filter-incomplete /
context-inheritance / subagent-session / depth-guard)
- 12 new C3 tests (subagent-sidechain / replay-subagent /
subagent-transcript-integration)
- full suite: 475 tests, 471 pass, 4 skipped, 0 fail
Co-authored-by: Cursor <cursoragent@cursor.com>
| 24 天前 |