@x-code-cli/core 0.1.10 → 0.2.0

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.
Files changed (111) hide show
  1. package/dist/agent/api-errors.d.ts.map +1 -1
  2. package/dist/agent/api-errors.js +18 -0
  3. package/dist/agent/api-errors.js.map +1 -1
  4. package/dist/agent/diff.d.ts +35 -0
  5. package/dist/agent/diff.d.ts.map +1 -0
  6. package/dist/agent/diff.js +83 -0
  7. package/dist/agent/diff.js.map +1 -0
  8. package/dist/agent/loop-state.d.ts +45 -3
  9. package/dist/agent/loop-state.d.ts.map +1 -1
  10. package/dist/agent/loop-state.js +24 -3
  11. package/dist/agent/loop-state.js.map +1 -1
  12. package/dist/agent/loop.d.ts +10 -6
  13. package/dist/agent/loop.d.ts.map +1 -1
  14. package/dist/agent/loop.js +212 -30
  15. package/dist/agent/loop.js.map +1 -1
  16. package/dist/agent/plan-storage.d.ts +55 -0
  17. package/dist/agent/plan-storage.d.ts.map +1 -0
  18. package/dist/agent/plan-storage.js +156 -0
  19. package/dist/agent/plan-storage.js.map +1 -0
  20. package/dist/agent/session-store.d.ts +114 -0
  21. package/dist/agent/session-store.d.ts.map +1 -0
  22. package/dist/agent/session-store.js +415 -0
  23. package/dist/agent/session-store.js.map +1 -0
  24. package/dist/agent/sub-agents/built-in.d.ts +3 -0
  25. package/dist/agent/sub-agents/built-in.d.ts.map +1 -0
  26. package/dist/agent/sub-agents/built-in.js +98 -0
  27. package/dist/agent/sub-agents/built-in.js.map +1 -0
  28. package/dist/agent/sub-agents/index.d.ts +7 -0
  29. package/dist/agent/sub-agents/index.d.ts.map +1 -0
  30. package/dist/agent/sub-agents/index.js +5 -0
  31. package/dist/agent/sub-agents/index.js.map +1 -0
  32. package/dist/agent/sub-agents/loader.d.ts +5 -0
  33. package/dist/agent/sub-agents/loader.d.ts.map +1 -0
  34. package/dist/agent/sub-agents/loader.js +117 -0
  35. package/dist/agent/sub-agents/loader.js.map +1 -0
  36. package/dist/agent/sub-agents/registry.d.ts +14 -0
  37. package/dist/agent/sub-agents/registry.d.ts.map +1 -0
  38. package/dist/agent/sub-agents/registry.js +37 -0
  39. package/dist/agent/sub-agents/registry.js.map +1 -0
  40. package/dist/agent/sub-agents/runner.d.ts +26 -0
  41. package/dist/agent/sub-agents/runner.d.ts.map +1 -0
  42. package/dist/agent/sub-agents/runner.js +287 -0
  43. package/dist/agent/sub-agents/runner.js.map +1 -0
  44. package/dist/agent/sub-agents/types.d.ts +63 -0
  45. package/dist/agent/sub-agents/types.d.ts.map +1 -0
  46. package/dist/agent/sub-agents/types.js +2 -0
  47. package/dist/agent/sub-agents/types.js.map +1 -0
  48. package/dist/agent/system-prompt.d.ts +15 -0
  49. package/dist/agent/system-prompt.d.ts.map +1 -1
  50. package/dist/agent/system-prompt.js +161 -0
  51. package/dist/agent/system-prompt.js.map +1 -1
  52. package/dist/agent/tool-execution.d.ts +4 -3
  53. package/dist/agent/tool-execution.d.ts.map +1 -1
  54. package/dist/agent/tool-execution.js +316 -14
  55. package/dist/agent/tool-execution.js.map +1 -1
  56. package/dist/agent/tool-result-sanitize.d.ts +12 -0
  57. package/dist/agent/tool-result-sanitize.d.ts.map +1 -1
  58. package/dist/agent/tool-result-sanitize.js +70 -0
  59. package/dist/agent/tool-result-sanitize.js.map +1 -1
  60. package/dist/config/index.d.ts +6 -0
  61. package/dist/config/index.d.ts.map +1 -1
  62. package/dist/config/index.js.map +1 -1
  63. package/dist/index.d.ts +11 -5
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +10 -3
  66. package/dist/index.js.map +1 -1
  67. package/dist/knowledge/session.d.ts +4 -7
  68. package/dist/knowledge/session.d.ts.map +1 -1
  69. package/dist/knowledge/session.js +20 -55
  70. package/dist/knowledge/session.js.map +1 -1
  71. package/dist/permissions/index.d.ts +18 -3
  72. package/dist/permissions/index.d.ts.map +1 -1
  73. package/dist/permissions/index.js +20 -2
  74. package/dist/permissions/index.js.map +1 -1
  75. package/dist/tools/ask-user.d.ts.map +1 -1
  76. package/dist/tools/ask-user.js +8 -6
  77. package/dist/tools/ask-user.js.map +1 -1
  78. package/dist/tools/enter-plan-mode.d.ts +25 -0
  79. package/dist/tools/enter-plan-mode.d.ts.map +1 -0
  80. package/dist/tools/enter-plan-mode.js +120 -0
  81. package/dist/tools/enter-plan-mode.js.map +1 -0
  82. package/dist/tools/exit-plan-mode.d.ts +13 -0
  83. package/dist/tools/exit-plan-mode.d.ts.map +1 -0
  84. package/dist/tools/exit-plan-mode.js +22 -0
  85. package/dist/tools/exit-plan-mode.js.map +1 -0
  86. package/dist/tools/grep.d.ts +1 -1
  87. package/dist/tools/index.d.ts +20 -4
  88. package/dist/tools/index.d.ts.map +1 -1
  89. package/dist/tools/index.js +7 -1
  90. package/dist/tools/index.js.map +1 -1
  91. package/dist/tools/save-knowledge.d.ts +2 -2
  92. package/dist/tools/shell-provider.d.ts +4 -0
  93. package/dist/tools/shell-provider.d.ts.map +1 -1
  94. package/dist/tools/shell-provider.js +2 -0
  95. package/dist/tools/shell-provider.js.map +1 -1
  96. package/dist/tools/task.d.ts +14 -0
  97. package/dist/tools/task.d.ts.map +1 -0
  98. package/dist/tools/task.js +95 -0
  99. package/dist/tools/task.js.map +1 -0
  100. package/dist/tools/todo-write.d.ts +21 -0
  101. package/dist/tools/todo-write.d.ts.map +1 -0
  102. package/dist/tools/todo-write.js +117 -0
  103. package/dist/tools/todo-write.js.map +1 -0
  104. package/dist/types/index.d.ts +103 -0
  105. package/dist/types/index.d.ts.map +1 -1
  106. package/dist/types/index.js.map +1 -1
  107. package/package.json +1 -1
  108. package/dist/knowledge/session-usage.d.ts +0 -24
  109. package/dist/knowledge/session-usage.d.ts.map +0 -1
  110. package/dist/knowledge/session-usage.js +0 -86
  111. package/dist/knowledge/session-usage.js.map +0 -1
@@ -0,0 +1,415 @@
1
+ // @x-code-cli/core — Per-session JSONL transcript store.
2
+ //
3
+ // One file per session: `.x-code/sessions/<slug>-<sessionId>.jsonl` (slug is
4
+ // the same human-readable token used by plan files; falls back to
5
+ // timestamp-only naming when the user's first message has no ASCII content).
6
+ // The file is append-only; everything we record about a session — header,
7
+ // each ModelMessage, periodic token-usage snapshots, compaction boundaries,
8
+ // abort markers — lives as one JSON object per line.
9
+ //
10
+ // Why JSONL and not a single rewritten JSON document:
11
+ // - Crash-safe. A killed process or full-disk error at most loses the line
12
+ // currently being written; everything before it is intact.
13
+ // - Cheap appends. Each turn appends a few hundred bytes; never rewrites.
14
+ // - Mirrors Claude Code's `~/.claude/<project>/<uuid>.jsonl` exactly,
15
+ // including the `compact_boundary` semantics (see `loadSession` below).
16
+ //
17
+ // This module replaces the old per-session `<id>.usage.json` and
18
+ // `<id>.json` (LLM summary) files — both are now meta entries inside the
19
+ // jsonl. /usage history and /resume both source from the same file.
20
+ import { createHash } from 'node:crypto';
21
+ import { readFile } from 'node:fs/promises';
22
+ import fs from 'node:fs/promises';
23
+ import path from 'node:path';
24
+ import { XCODE_DIR } from '../utils.js';
25
+ import { createLoopState } from './loop-state.js';
26
+ const SESSIONS_SUBDIR = 'sessions';
27
+ function sessionsDir(cwd = process.cwd()) {
28
+ return path.join(cwd, XCODE_DIR, SESSIONS_SUBDIR);
29
+ }
30
+ /** Build the on-disk filename for a session. Same shape as plan files
31
+ * (`<slug>-<id>.<ext>`) so `ls .x-code/sessions/` and `ls .x-code/plans/`
32
+ * scan the same way. Empty slug (CJK-only first message) collapses to
33
+ * pure-timestamp naming, matching the plan-file fallback. */
34
+ export function getSessionFilePath(state, cwd = process.cwd()) {
35
+ const base = state.taskSlug ? `${state.taskSlug}-${state.sessionId}` : state.sessionId;
36
+ return path.join(sessionsDir(cwd), `${base}.jsonl`);
37
+ }
38
+ // ── Append helpers (fire-and-forget; never throw) ───────────────────────
39
+ async function appendLine(filePath, entry) {
40
+ try {
41
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
42
+ await fs.appendFile(filePath, JSON.stringify(entry) + '\n', 'utf-8');
43
+ }
44
+ catch {
45
+ // Persistence is best-effort — never block the agent loop on FS errors.
46
+ }
47
+ }
48
+ /** Try to read the current git branch from `.git/HEAD`. Cheap, fully sync
49
+ * on the calling promise; absent / detached-HEAD / non-git all map to
50
+ * undefined silently. */
51
+ async function readGitBranch(cwd) {
52
+ try {
53
+ const head = await readFile(path.join(cwd, '.git', 'HEAD'), 'utf-8');
54
+ const m = head.match(/^ref: refs\/heads\/(.+)$/m);
55
+ return m ? m[1].trim() : undefined;
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
60
+ }
61
+ /** Write the session header. Idempotent: if the file already exists (resume
62
+ * path), we skip — the original header is preserved so picker metadata
63
+ * stays stable across resumes. */
64
+ export async function appendHeader(state, modelId, firstPrompt, cwd = process.cwd()) {
65
+ const filePath = getSessionFilePath(state, cwd);
66
+ try {
67
+ await fs.access(filePath);
68
+ return; // file already exists — header preserved from original session
69
+ }
70
+ catch {
71
+ // File doesn't exist — fall through and write the header.
72
+ }
73
+ const gitBranch = await readGitBranch(cwd);
74
+ const entry = {
75
+ t: 'meta',
76
+ kind: 'header',
77
+ cwd,
78
+ gitBranch,
79
+ modelId,
80
+ startedAt: state.startedAt,
81
+ firstPrompt: firstPrompt.slice(0, 500),
82
+ taskSlug: state.taskSlug,
83
+ sessionId: state.sessionId,
84
+ };
85
+ await appendLine(filePath, entry);
86
+ }
87
+ /** Flush every message in `state.messages` past `state.persistedMessageCount`
88
+ * to the jsonl file. The diff-based design keeps the writer decoupled from
89
+ * the many places in the agent loop that mutate state.messages directly
90
+ * (collectTurnResponse, processToolCalls, length-finish nudge, etc.) — we
91
+ * catch them all by sweeping at turn boundaries.
92
+ *
93
+ * After deep / light compaction the in-memory array shrinks. Callers must
94
+ * call `markBoundaryAndReflush` (below) instead of this — that path writes
95
+ * a compact-boundary marker so the loader can correctly truncate-on-load
96
+ * and then re-appends the trimmed messages so post-boundary jsonl content
97
+ * matches the new in-memory state. */
98
+ export async function flushPendingMessages(state) {
99
+ if (state.persistedMessageCount >= state.messages.length)
100
+ return;
101
+ const filePath = getSessionFilePath(state);
102
+ const ts = new Date().toISOString();
103
+ const lines = [];
104
+ for (let i = state.persistedMessageCount; i < state.messages.length; i++) {
105
+ const message = state.messages[i];
106
+ if (!message)
107
+ continue;
108
+ const entry = { t: 'msg', message, ts };
109
+ lines.push(JSON.stringify(entry));
110
+ }
111
+ if (lines.length === 0)
112
+ return;
113
+ try {
114
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
115
+ await fs.appendFile(filePath, lines.join('\n') + '\n', 'utf-8');
116
+ state.persistedMessageCount = state.messages.length;
117
+ }
118
+ catch {
119
+ // best-effort
120
+ }
121
+ }
122
+ /** Append a usage snapshot for the current turn. Called from the agent loop
123
+ * after `collectTurnResponse` accepts the provider's `usage` object. The
124
+ * picker reads only the LAST usage line (tail scan) to display per-session
125
+ * totals — no need to keep older snapshots around any more efficiently. */
126
+ export async function appendUsage(state, modelId) {
127
+ const filePath = getSessionFilePath(state);
128
+ const entry = {
129
+ t: 'meta',
130
+ kind: 'usage',
131
+ usage: { ...state.tokenUsage },
132
+ modelId,
133
+ turn: state.turnCount,
134
+ ts: new Date().toISOString(),
135
+ };
136
+ await appendLine(filePath, entry);
137
+ }
138
+ /** Mark a compaction event and re-flush the (just-shrunk) message array.
139
+ * After this returns, the jsonl post-last-boundary content equals
140
+ * `state.messages` exactly — `loadSession` reconstructs the same in-memory
141
+ * state on resume.
142
+ *
143
+ * Why we re-append instead of relying on the pre-boundary messages: our
144
+ * `compressMessages` keeps a `recent N` slice verbatim, but those slices
145
+ * were already persisted before the boundary; the loader's
146
+ * "everything-after-last-boundary wins" rule would otherwise drop them.
147
+ * Duplicating ~6 messages on disk is cheap and keeps the load logic
148
+ * trivial.
149
+ *
150
+ * Light compaction (loop-guard pruning) calls this with `summary=undefined`
151
+ * — the trimmed messages still need a boundary so the loader doesn't
152
+ * resurrect the dropped loop-guard pairs. */
153
+ export async function markBoundaryAndReflush(state, summary) {
154
+ const filePath = getSessionFilePath(state);
155
+ const ts = new Date().toISOString();
156
+ const boundary = { t: 'meta', kind: 'compact-boundary', ts };
157
+ if (summary !== undefined)
158
+ boundary.summary = summary;
159
+ const lines = [JSON.stringify(boundary)];
160
+ for (const message of state.messages) {
161
+ const entry = { t: 'msg', message, ts };
162
+ lines.push(JSON.stringify(entry));
163
+ }
164
+ try {
165
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
166
+ await fs.appendFile(filePath, lines.join('\n') + '\n', 'utf-8');
167
+ state.persistedMessageCount = state.messages.length;
168
+ }
169
+ catch {
170
+ // best-effort
171
+ }
172
+ }
173
+ /** Append an `interrupted` marker. Purely informational — the loader
174
+ * ignores it for state reconstruction; the picker can show "interrupted"
175
+ * next to sessions that ended mid-turn so users know what they're
176
+ * resuming into. */
177
+ export async function appendInterrupted(state) {
178
+ if (!state.sessionId)
179
+ return;
180
+ const filePath = getSessionFilePath(state);
181
+ const entry = { t: 'meta', kind: 'interrupted', ts: new Date().toISOString() };
182
+ await appendLine(filePath, entry);
183
+ }
184
+ const EMPTY_USAGE = {
185
+ inputTokens: 0,
186
+ outputTokens: 0,
187
+ totalTokens: 0,
188
+ cacheReadTokens: 0,
189
+ cacheCreationTokens: 0,
190
+ currentContextTokens: 0,
191
+ };
192
+ /** Walk a session jsonl and reconstruct a LoadedSession.
193
+ *
194
+ * Compact-boundary semantics (matches Claude Code): every time we see a
195
+ * `compact-boundary` line, the message accumulator is cleared. So the
196
+ * returned `messages` reflects only what's after the LAST boundary —
197
+ * which by construction equals the in-memory state at the point of
198
+ * compaction (see `markBoundaryAndReflush`).
199
+ *
200
+ * Trailing tool_call / tool_result orphans are trimmed (the next API
201
+ * request would otherwise reject the message array) — see
202
+ * `sanitizeMessageTail` for the exact rule. */
203
+ export async function loadSession(filePath) {
204
+ let raw;
205
+ try {
206
+ raw = await readFile(filePath, 'utf-8');
207
+ }
208
+ catch {
209
+ return null;
210
+ }
211
+ let header = null;
212
+ let lastUsage = null;
213
+ let messages = [];
214
+ for (const line of raw.split('\n')) {
215
+ if (!line.trim())
216
+ continue;
217
+ let entry;
218
+ try {
219
+ entry = JSON.parse(line);
220
+ }
221
+ catch {
222
+ continue; // skip malformed lines silently
223
+ }
224
+ if (entry.t === 'meta') {
225
+ if (entry.kind === 'header') {
226
+ header = entry;
227
+ }
228
+ else if (entry.kind === 'usage') {
229
+ lastUsage = entry;
230
+ }
231
+ else if (entry.kind === 'compact-boundary') {
232
+ messages = [];
233
+ }
234
+ // 'interrupted' is informational only — doesn't affect state
235
+ }
236
+ else if (entry.t === 'msg') {
237
+ messages.push(entry.message);
238
+ }
239
+ }
240
+ if (!header)
241
+ return null;
242
+ return {
243
+ sessionId: header.sessionId,
244
+ taskSlug: header.taskSlug,
245
+ startedAt: header.startedAt,
246
+ modelId: header.modelId,
247
+ cwd: header.cwd,
248
+ gitBranch: header.gitBranch,
249
+ firstPrompt: header.firstPrompt,
250
+ messages: sanitizeMessageTail(messages),
251
+ tokenUsage: lastUsage?.usage ?? EMPTY_USAGE,
252
+ turnCount: lastUsage?.turn ?? 0,
253
+ filePath,
254
+ };
255
+ }
256
+ /** Drop trailing assistant tool_calls that have no matching tool_result
257
+ * later in the array. Providers reject any orphan with "tool_use without
258
+ * tool_result", so resuming a session that ended mid-tool-execution must
259
+ * trim back to the last fully-resolved boundary.
260
+ *
261
+ * Algorithm: collect every toolCallId that has a tool_result somewhere,
262
+ * then walk back from the end and drop any assistant message whose
263
+ * tool_call parts include an unresolved id. Stops at the first clean
264
+ * message (text-only assistant, or assistant whose every tool_call IS
265
+ * resolved). */
266
+ function sanitizeMessageTail(messages) {
267
+ const resolvedIds = new Set();
268
+ for (const msg of messages) {
269
+ if (msg.role !== 'tool' || !Array.isArray(msg.content))
270
+ continue;
271
+ for (const part of msg.content) {
272
+ if (part?.type === 'tool-result' && typeof part.toolCallId === 'string') {
273
+ resolvedIds.add(part.toolCallId);
274
+ }
275
+ }
276
+ }
277
+ let cutAt = messages.length;
278
+ for (let i = messages.length - 1; i >= 0; i--) {
279
+ const msg = messages[i];
280
+ if (!msg) {
281
+ cutAt = i;
282
+ continue;
283
+ }
284
+ if (msg.role !== 'assistant') {
285
+ // Bare 'tool' or 'user' at the tail without an upstream tool_call is
286
+ // legal — keep walking; the cut is driven only by orphan tool_calls.
287
+ break;
288
+ }
289
+ const content = msg.content;
290
+ if (typeof content === 'string')
291
+ break; // text-only assistant — clean tail
292
+ if (!Array.isArray(content))
293
+ break;
294
+ const hasOrphan = content.some((p) => p?.type === 'tool-call' && typeof p.toolCallId === 'string' && !resolvedIds.has(p.toolCallId));
295
+ if (hasOrphan) {
296
+ cutAt = i;
297
+ continue;
298
+ }
299
+ break;
300
+ }
301
+ return cutAt < messages.length ? messages.slice(0, cutAt) : messages;
302
+ }
303
+ /** Enumerate every session jsonl in the current project, newest first.
304
+ * Reads only the head (~8KB, for the header line) and tail (~4KB, for
305
+ * the last usage line) of each file — no full-file load — so the picker
306
+ * is responsive even with hundreds of historical sessions. Files
307
+ * without a parseable header are dropped silently. */
308
+ export async function listSessions(cwd = process.cwd()) {
309
+ const dir = sessionsDir(cwd);
310
+ let entries;
311
+ try {
312
+ entries = await fs.readdir(dir);
313
+ }
314
+ catch {
315
+ return [];
316
+ }
317
+ const jsonlFiles = entries.filter((f) => f.endsWith('.jsonl'));
318
+ const results = await Promise.all(jsonlFiles.map(async (f) => {
319
+ const filePath = path.join(dir, f);
320
+ try {
321
+ const stat = await fs.stat(filePath);
322
+ const head = await readRange(filePath, 0, Math.min(8 * 1024, stat.size));
323
+ const headerLine = head.split('\n').find((l) => l.includes('"kind":"header"'));
324
+ if (!headerLine)
325
+ return null;
326
+ let header;
327
+ try {
328
+ header = JSON.parse(headerLine);
329
+ }
330
+ catch {
331
+ return null;
332
+ }
333
+ const tailStart = Math.max(0, stat.size - 4 * 1024);
334
+ const tail = await readRange(filePath, tailStart, stat.size - tailStart);
335
+ let tokenUsage = null;
336
+ const tailLines = tail.split('\n').reverse();
337
+ for (const l of tailLines) {
338
+ if (!l.trim())
339
+ continue;
340
+ if (l.includes('"kind":"usage"')) {
341
+ try {
342
+ const e = JSON.parse(l);
343
+ tokenUsage = e.usage;
344
+ break;
345
+ }
346
+ catch {
347
+ // Malformed line — keep scanning earlier lines.
348
+ }
349
+ }
350
+ }
351
+ return {
352
+ filePath,
353
+ sessionId: header.sessionId,
354
+ taskSlug: header.taskSlug,
355
+ firstPrompt: header.firstPrompt,
356
+ startedAt: header.startedAt,
357
+ modelId: header.modelId,
358
+ mtime: stat.mtimeMs,
359
+ tokenUsage,
360
+ };
361
+ }
362
+ catch {
363
+ return null;
364
+ }
365
+ }));
366
+ return results.filter((r) => r !== null).sort((a, b) => b.mtime - a.mtime);
367
+ }
368
+ /** Read [offset, offset+length) bytes of a file as utf-8. Used by
369
+ * `listSessions` to grab head/tail without slurping the full file. */
370
+ async function readRange(filePath, offset, length) {
371
+ if (length <= 0)
372
+ return '';
373
+ const fh = await fs.open(filePath, 'r');
374
+ try {
375
+ const buf = Buffer.alloc(length);
376
+ const { bytesRead } = await fh.read(buf, 0, length, offset);
377
+ return buf.subarray(0, bytesRead).toString('utf-8');
378
+ }
379
+ finally {
380
+ await fh.close();
381
+ }
382
+ }
383
+ /** Pick the most recently modified session file in the current project, or
384
+ * null if none exist. Used by `xc --continue` / `-c` to skip the picker
385
+ * and resume the latest session unconditionally. */
386
+ export async function pickLatestSession(cwd = process.cwd()) {
387
+ const all = await listSessions(cwd);
388
+ return all[0] ?? null;
389
+ }
390
+ /** Stable identifier for a session in picker UI. We can't use the filename
391
+ * directly (it can collide visually when multiple sessions share a slug)
392
+ * and the sessionId alone isn't unique across renames — but the file path
393
+ * is, by definition. Hashed to keep the choice label compact. */
394
+ export function shortIdFor(filePath) {
395
+ return createHash('sha1').update(filePath).digest('hex').slice(0, 8);
396
+ }
397
+ /** Build a LoopState seeded from a previously-saved session. The agent
398
+ * loop accepts `existingState` and will continue appending to the same
399
+ * jsonl file (filename derives from `sessionId` + `taskSlug`, both
400
+ * preserved here). `persistedMessageCount` is set to the loaded length
401
+ * so the very first flush after the next user submit only appends NEW
402
+ * messages — the loaded tail is already on disk. */
403
+ export function hydrateLoopState(loaded, initialMode = 'default') {
404
+ const state = createLoopState(initialMode);
405
+ state.sessionId = loaded.sessionId;
406
+ state.taskSlug = loaded.taskSlug;
407
+ state.startedAt = loaded.startedAt;
408
+ state.messages = loaded.messages.slice();
409
+ state.tokenUsage = { ...loaded.tokenUsage };
410
+ state.lastInputTokens = loaded.tokenUsage.inputTokens;
411
+ state.turnCount = loaded.turnCount;
412
+ state.persistedMessageCount = loaded.messages.length;
413
+ return state;
414
+ }
415
+ //# sourceMappingURL=session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/agent/session-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SubAgentDefinition } from './types.js';
2
+ export declare const builtInAgents: SubAgentDefinition[];
3
+ //# sourceMappingURL=built-in.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"built-in.d.ts","sourceRoot":"","sources":["../../../src/agent/sub-agents/built-in.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAapD,eAAO,MAAM,aAAa,EAAE,kBAAkB,EA0F7C,CAAA"}
@@ -0,0 +1,98 @@
1
+ const SHELL_DENY_KEYWORDS = [
2
+ 'rm ', 'rm\t', 'rmdir', 'del ', 'rd ',
3
+ 'mv ', 'move ', 'ren ',
4
+ 'git commit', 'git push', 'git merge', 'git rebase', 'git reset',
5
+ 'git checkout -b', 'git branch -d', 'git branch -D',
6
+ '>', '>>', 'tee ', 'tee\t',
7
+ 'chmod', 'chown',
8
+ 'npm publish', 'pnpm publish', 'yarn publish',
9
+ 'docker rm', 'docker rmi',
10
+ ];
11
+ export const builtInAgents = [
12
+ {
13
+ name: 'explore',
14
+ description: 'Read-only codebase exploration. Use for "where is X defined", "find all callers of Y", or any pure-read research question.',
15
+ prompt: `You are a read-only codebase explorer. Your job is to find information, trace code paths, and report findings clearly.
16
+
17
+ Guidelines:
18
+ - Search broadly first (glob, grep), then read specific files
19
+ - Report file paths and line numbers so the parent agent can reference them
20
+ - If the codebase is large, prioritize the most relevant files
21
+ - Do NOT suggest code changes — just report what you find
22
+
23
+ CRITICAL — your final message is ALL the parent agent sees. It will NOT re-read files you've already read. Your output must be comprehensive enough that the parent can act on it directly:
24
+ - Include key code snippets (function signatures, type definitions, important logic) — not just file paths
25
+ - For architecture questions, describe the data flow and module relationships
26
+ - For "find all X" questions, list every match with file:line and a brief context line
27
+ - When exploring project structure, include dependency lists, entry points, and config details
28
+ - Never say "see file X for details" — the parent CANNOT see file X. Inline the relevant details.`,
29
+ tools: ['readFile', 'glob', 'grep', 'listDir', 'shell'],
30
+ shellRestrictions: SHELL_DENY_KEYWORDS,
31
+ maxTurns: 25,
32
+ source: 'built-in',
33
+ },
34
+ {
35
+ name: 'general-purpose',
36
+ description: 'Multi-step research and investigation. Use for open-ended questions that may need 3+ tool calls and you don\'t want noise in the main context.',
37
+ prompt: `You are a general-purpose research assistant. You can read files, search code, and run shell commands to investigate questions.
38
+
39
+ Guidelines:
40
+ - Be thorough but efficient — minimize unnecessary tool calls
41
+ - Synthesize findings into a clear, actionable summary
42
+ - Include file paths and line numbers for key references
43
+ - If you find issues or patterns, describe them concisely
44
+
45
+ CRITICAL — your final message is ALL the parent agent sees. It will NOT re-read files you've already read. Your output must be self-contained:
46
+ - Include key code snippets, not just references — the parent cannot read the files
47
+ - For multi-file investigations, summarize each file's role and relevant content
48
+ - When the parent needs to modify code, include the exact current code that needs changing`,
49
+ tools: ['readFile', 'glob', 'grep', 'listDir', 'shell'],
50
+ maxTurns: 40,
51
+ source: 'built-in',
52
+ },
53
+ {
54
+ name: 'plan',
55
+ description: 'Design an implementation plan. Returns step-by-step plans, identifies critical files, considers tradeoffs.',
56
+ prompt: `You are a planning assistant. Given a task description, explore the codebase and produce a detailed implementation plan.
57
+
58
+ Your plan should include:
59
+ 1. **Context** — what problem is being solved and why
60
+ 2. **Critical files** — which files need to change, with paths
61
+ 3. **Step-by-step approach** — ordered implementation steps
62
+ 4. **Existing code to reuse** — functions, patterns, utilities already in the repo
63
+ 5. **Risks and tradeoffs** — edge cases, breaking changes, alternatives considered
64
+ 6. **Verification** — how to test the changes
65
+
66
+ Guidelines:
67
+ - Read the relevant code before planning — don't guess at file structure
68
+ - Reference existing patterns in the codebase (don't reinvent)
69
+ - Keep the plan concise enough to execute, detailed enough to be unambiguous`,
70
+ tools: ['readFile', 'glob', 'grep', 'listDir'],
71
+ maxTurns: 30,
72
+ source: 'built-in',
73
+ },
74
+ {
75
+ name: 'code-reviewer',
76
+ description: 'Review pending changes (or specific files) for bugs, security issues, and style violations. Returns a punch list.',
77
+ prompt: `You are a code reviewer. Examine the specified files or pending changes and produce a structured review.
78
+
79
+ Your review should cover:
80
+ - **Bugs** — logic errors, off-by-one, null/undefined hazards, race conditions
81
+ - **Security** — injection, XSS, secrets in code, unsafe deserialization
82
+ - **Style** — naming, consistency with surrounding code, dead code
83
+ - **Performance** — unnecessary allocations, O(n^2) where O(n) suffices
84
+ - **Missing edge cases** — error handling, empty inputs, concurrent access
85
+
86
+ Output format: a numbered punch list, each item with severity (critical/warning/nit), file:line, and a one-line description. Group by file.
87
+
88
+ Guidelines:
89
+ - Use git diff (shell) to see pending changes when reviewing uncommitted work
90
+ - Read surrounding code for context — don't flag patterns that are idiomatic in this codebase
91
+ - Be specific: "line 42: array index not bounds-checked" not "consider adding validation"`,
92
+ tools: ['readFile', 'glob', 'grep', 'listDir', 'shell'],
93
+ shellRestrictions: SHELL_DENY_KEYWORDS,
94
+ maxTurns: 25,
95
+ source: 'built-in',
96
+ },
97
+ ];
98
+ //# sourceMappingURL=built-in.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"built-in.js","sourceRoot":"","sources":["../../../src/agent/sub-agents/built-in.ts"],"names":[],"mappings":"AAGA,MAAM,mBAAmB,GAAG;IAC1B,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK;IACrC,KAAK,EAAE,OAAO,EAAE,MAAM;IACtB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW;IAChE,iBAAiB,EAAE,eAAe,EAAE,eAAe;IACnD,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO;IAC1B,OAAO,EAAE,OAAO;IAChB,aAAa,EAAE,cAAc,EAAE,cAAc;IAC7C,WAAW,EAAE,YAAY;CAC1B,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAyB;IACjD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EACT,4HAA4H;QAC9H,MAAM,EAAE;;;;;;;;;;;;;kGAasF;QAC9F,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC;QACvD,iBAAiB,EAAE,mBAAmB;QACtC,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,UAAU;KACnB;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,WAAW,EACT,gJAAgJ;QAClJ,MAAM,EAAE;;;;;;;;;;;2FAW+E;QACvF,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC;QACvD,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,UAAU;KACnB;IACD;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EACT,4GAA4G;QAC9G,MAAM,EAAE;;;;;;;;;;;;;6EAaiE;QACzE,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;QAC9C,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,UAAU;KACnB;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EACT,mHAAmH;QACrH,MAAM,EAAE;;;;;;;;;;;;;;0FAc8E;QACtF,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC;QACvD,iBAAiB,EAAE,mBAAmB;QACtC,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,UAAU;KACnB;CACF,CAAA"}
@@ -0,0 +1,7 @@
1
+ export type { SubAgentDefinition, SubAgentTrace, SubAgentEvent } from './types.js';
2
+ export { builtInAgents } from './built-in.js';
3
+ export { loadCustomAgents } from './loader.js';
4
+ export { SubAgentRegistry, createSubAgentRegistry, createBuiltInRegistry } from './registry.js';
5
+ export { runSubAgent } from './runner.js';
6
+ export type { RunSubAgentArgs, RunSubAgentResult } from './runner.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/sub-agents/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,5 @@
1
+ export { builtInAgents } from './built-in.js';
2
+ export { loadCustomAgents } from './loader.js';
3
+ export { SubAgentRegistry, createSubAgentRegistry, createBuiltInRegistry } from './registry.js';
4
+ export { runSubAgent } from './runner.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/agent/sub-agents/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,5 @@
1
+ import type { SubAgentDefinition } from './types.js';
2
+ /** Load custom sub-agents from global + project directories.
3
+ * Environment variable `XC_AGENTS_DIR` overrides paths (testing only). */
4
+ export declare function loadCustomAgents(): Promise<SubAgentDefinition[]>;
5
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/agent/sub-agents/loader.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAiHpD;2EAC2E;AAC3E,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAatE"}