@zaly/agent 0.0.3

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 (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -0
  3. package/dist/agent-BaD2kax9.mjs +68 -0
  4. package/dist/agent-BaD2kax9.mjs.map +1 -0
  5. package/dist/agent-GDLdDc2w.mjs +902 -0
  6. package/dist/agent-GDLdDc2w.mjs.map +1 -0
  7. package/dist/bash-QNMTQ1PD.mjs +142 -0
  8. package/dist/bash-QNMTQ1PD.mjs.map +1 -0
  9. package/dist/compactions-3AjPqjeZ.mjs +190 -0
  10. package/dist/compactions-3AjPqjeZ.mjs.map +1 -0
  11. package/dist/edit-Qxl4w1C2.mjs +170 -0
  12. package/dist/edit-Qxl4w1C2.mjs.map +1 -0
  13. package/dist/env-UUFv5Mye.mjs +30 -0
  14. package/dist/env-UUFv5Mye.mjs.map +1 -0
  15. package/dist/fetch-D8cmmA3E.mjs +111 -0
  16. package/dist/fetch-D8cmmA3E.mjs.map +1 -0
  17. package/dist/find-Bah9SKWX.mjs +87 -0
  18. package/dist/find-Bah9SKWX.mjs.map +1 -0
  19. package/dist/grep-B2Ax7ewy.mjs +244 -0
  20. package/dist/grep-B2Ax7ewy.mjs.map +1 -0
  21. package/dist/index-node-esm-D6YQRKEz.mjs +1537 -0
  22. package/dist/index-node-esm-D6YQRKEz.mjs.map +1 -0
  23. package/dist/index.d.mts +1605 -0
  24. package/dist/index.d.mts.map +1 -0
  25. package/dist/index.mjs +948 -0
  26. package/dist/index.mjs.map +1 -0
  27. package/dist/jsonl-Dw_VBp46.mjs +134 -0
  28. package/dist/jsonl-Dw_VBp46.mjs.map +1 -0
  29. package/dist/manager-D-lWBTHG.mjs +271 -0
  30. package/dist/manager-D-lWBTHG.mjs.map +1 -0
  31. package/dist/markdown-Bv4J8cg3.mjs +53 -0
  32. package/dist/markdown-Bv4J8cg3.mjs.map +1 -0
  33. package/dist/masker-Bv9KjkDF.mjs +396 -0
  34. package/dist/masker-Bv9KjkDF.mjs.map +1 -0
  35. package/dist/model-_3ZA2xqm.mjs +27 -0
  36. package/dist/model-_3ZA2xqm.mjs.map +1 -0
  37. package/dist/notify-DpG_m9iP.mjs +96 -0
  38. package/dist/notify-DpG_m9iP.mjs.map +1 -0
  39. package/dist/read-Djsx2NZl.mjs +205 -0
  40. package/dist/read-Djsx2NZl.mjs.map +1 -0
  41. package/dist/registry-CFmR5G3J.mjs +564 -0
  42. package/dist/registry-CFmR5G3J.mjs.map +1 -0
  43. package/dist/search-CRw247ES.mjs +121 -0
  44. package/dist/search-CRw247ES.mjs.map +1 -0
  45. package/dist/session/claude.d.mts +59 -0
  46. package/dist/session/claude.d.mts.map +1 -0
  47. package/dist/session/claude.mjs +455 -0
  48. package/dist/session/claude.mjs.map +1 -0
  49. package/dist/session-CUUdWFC5.mjs +450 -0
  50. package/dist/session-CUUdWFC5.mjs.map +1 -0
  51. package/dist/session-Ds5nJz5A.d.mts +346 -0
  52. package/dist/session-Ds5nJz5A.d.mts.map +1 -0
  53. package/dist/session.d.mts +37 -0
  54. package/dist/session.d.mts.map +1 -0
  55. package/dist/session.mjs +106 -0
  56. package/dist/session.mjs.map +1 -0
  57. package/dist/subagent-baqzjRMc.mjs +136 -0
  58. package/dist/subagent-baqzjRMc.mjs.map +1 -0
  59. package/dist/swarm-BJ3gQA1Z.mjs +194 -0
  60. package/dist/swarm-BJ3gQA1Z.mjs.map +1 -0
  61. package/dist/swarm-BuFx_xeY.mjs +109 -0
  62. package/dist/swarm-BuFx_xeY.mjs.map +1 -0
  63. package/dist/tasks-D8rARHZ1.mjs +65 -0
  64. package/dist/tasks-D8rARHZ1.mjs.map +1 -0
  65. package/dist/tasks-WmC270X2.mjs +615 -0
  66. package/dist/tasks-WmC270X2.mjs.map +1 -0
  67. package/dist/tools-DW1dbcCz.mjs +695 -0
  68. package/dist/tools-DW1dbcCz.mjs.map +1 -0
  69. package/dist/truncate-BSMXgiXj.mjs +102 -0
  70. package/dist/truncate-BSMXgiXj.mjs.map +1 -0
  71. package/dist/uuid-ByXP5SO5.mjs +59 -0
  72. package/dist/uuid-ByXP5SO5.mjs.map +1 -0
  73. package/dist/wakeup-BYqTnfSp.mjs +29 -0
  74. package/dist/wakeup-BYqTnfSp.mjs.map +1 -0
  75. package/dist/write-D3L-92vj.mjs +89 -0
  76. package/dist/write-D3L-92vj.mjs.map +1 -0
  77. package/package.json +63 -0
@@ -0,0 +1,346 @@
1
+ import { Emitter } from "@zaly/shared";
2
+ import { Message, ReasoningEffort } from "@zaly/ai";
3
+ //#region src/session/types.d.ts
4
+ /** A single node in the session DAG. Same shape on disk (JSONL) as in
5
+ * memory — what we persist *is* what we navigate. Session settings live ONLY on
6
+ * `session-settings` nodes as a full snapshot of the cumulative session
7
+ * settings at that point. Other node types are pure markers / payload —
8
+ * consumers reading "the settings as of node X" use `SessionNodeView`,
9
+ * which decorates raw nodes with cumulative settings computed by `Session`'s
10
+ * chain-walk forward pass. */
11
+ type SessionN = {
12
+ uuid: string;
13
+ /** Absent only on the very first node (`session-start`). */
14
+ parentUuid?: string;
15
+ /** Wall-clock millisecond timestamp when the node was created. */
16
+ ts: number;
17
+ } & ({
18
+ type: "session-start";
19
+ } | {
20
+ type: "session-resume";
21
+ } | {
22
+ type: "session-settings";
23
+ settings: SessionSettings;
24
+ } | {
25
+ type: "message";
26
+ message: Message;
27
+ } | {
28
+ type: "mask-checkpoint";
29
+ threshold: number;
30
+ messageId: string;
31
+ } | {
32
+ type: "compact";
33
+ /** Whether the loop kicked off compaction itself or the user did. */
34
+ trigger: "manual" | "auto";
35
+ /** Last known cumulative input+output tokens at compaction time. */
36
+ preTokens?: number;
37
+ /** How long the compactor took, ms. */
38
+ durationMs?: number;
39
+ /** Number of message from before compaction that will be preserved */
40
+ tail: number;
41
+ /** Frozen summary message that becomes the head of the active
42
+ * chain reconstruction. The full Message (not just text) so the
43
+ * walker stays generic and future format changes don't require
44
+ * migrating old compact nodes. */
45
+ summary: Message<"system">;
46
+ });
47
+ type SessionNodeType = SessionN["type"];
48
+ type MaskCheckpoint = {
49
+ messageId: string;
50
+ threshold: number;
51
+ };
52
+ type SessionMessage = Message & {
53
+ ts: number;
54
+ id: string;
55
+ };
56
+ type SessionNode<T extends SessionNodeType = SessionNodeType> = Extract<SessionN, {
57
+ type: T;
58
+ }>;
59
+ /** A `SessionNode` decorated with the cumulative settings as of that
60
+ * node's position in the chain. Returned by `Session.node()` and
61
+ * `Session#chain` — consumers always see a defined `settings`. */
62
+ type SessionNodeView = SessionNode & {
63
+ settings: SessionSettings;
64
+ };
65
+ type SessionView = {
66
+ messages: Message[];
67
+ nodes: Map<string, SessionNodeView>;
68
+ compact?: SessionNode<"compact">;
69
+ maskCheckpoint?: MaskCheckpoint;
70
+ };
71
+ type SessionSettings = {
72
+ version?: number;
73
+ sessionId?: string;
74
+ cwd?: string;
75
+ workspace?: string;
76
+ modelId?: string;
77
+ reasoning?: ReasoningEffort;
78
+ };
79
+ type SessionUpdate = Omit<SessionSettings, "version" | "sessionId">;
80
+ type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
81
+ type PartialNode = DistributiveOmit<SessionNode, "parentUuid" | "uuid" | "ts">;
82
+ /** Events a `Session` emits when its state changes. Subscribers fire
83
+ * synchronously; throws are routed to `onEmitError`. */
84
+ type SessionEvents = {
85
+ node: {
86
+ node: SessionNode;
87
+ };
88
+ navigate: {
89
+ head: string | undefined;
90
+ messages: readonly Message[];
91
+ };
92
+ compact: {
93
+ node: SessionNode<"compact">;
94
+ };
95
+ cwd: {
96
+ cwd: string;
97
+ prev?: string;
98
+ };
99
+ model: {
100
+ model: string;
101
+ prev?: string;
102
+ };
103
+ reasoning: {
104
+ effort: ReasoningEffort;
105
+ prev?: ReasoningEffort;
106
+ };
107
+ "session-start": {};
108
+ "session-resume": {};
109
+ };
110
+ type SessionOptions<T extends SessionStore = SessionStore> = {
111
+ store?: T;
112
+ /** JSONL file to persist the session to. If the file exists, its
113
+ * records are read into the DAG before any `add()` calls; either way
114
+ * the session opens it in append mode so subsequent commits land on
115
+ * disk in real time. Omit for in-memory sessions. */
116
+ path?: string;
117
+ /** Per-session directory for artifacts produced during this session —
118
+ * bash command logs (when output exceeds the inline cap), subagent
119
+ * traces, cached attachments, and any other side-channel data tools
120
+ * need to write somewhere session-scoped. */
121
+ dir?: string;
122
+ /** Initial session settings. Only used to fill in missing fields in the
123
+ * session's first `session-settings` node; */
124
+ defaults?: Omit<SessionSettings, "version">;
125
+ };
126
+ type SessionInit<T extends SessionStore = SessionStore> = SessionOptions & {
127
+ /** Storage backend. Required — `Session.load()` picks the right
128
+ * store based on options; direct construction passes one explicitly. */
129
+ store: T;
130
+ };
131
+ //#endregion
132
+ //#region src/session/store.d.ts
133
+ /**
134
+ * Storage backend for a `Session`'s DAG.
135
+ *
136
+ * The store is the source of truth for nodes. `Session` reads through
137
+ * the store for chain walks, and writes new nodes via `write()`.
138
+ *
139
+ * Implementations:
140
+ * - `MemoryStore` — `Map<uuid, SessionNode>`, no persistence. Used
141
+ * by tests and ephemeral / in-process sessions.
142
+ * - `JsonlStore` — append-only JSONL file. Eager-loads all records on
143
+ * `load()`; future versions may add lazy reads + LRU caching.
144
+ *
145
+ * Async by design — even `get()` may involve I/O for backends that don't
146
+ * cache the full DAG in memory. Callers that need synchronous reads
147
+ * should pre-warm via `Session`'s chain walk (which populates Session's
148
+ * own caches as it goes).
149
+ *
150
+ * `root` is the most recently appended node. Loading a store sets `root`
151
+ * from the last persisted record. Writes advance `root` synchronously
152
+ * (the in-memory state must reflect the append before `write()` resolves)
153
+ * so subsequent `root` reads see the new node — even if the underlying
154
+ * I/O completes asynchronously.
155
+ */
156
+ interface SessionStore {
157
+ /** The most recently appended node — drives chain walks. Undefined
158
+ * for an empty store. */
159
+ readonly root: SessionNode | undefined;
160
+ /** Lookup by uuid. Returns undefined for unknown ids. */
161
+ get: (id: string) => Promise<SessionNode | undefined>;
162
+ /** Append a node. Becomes the new `root`. The in-memory state must
163
+ * reflect the append synchronously (so a follow-up `root` read sees
164
+ * it) even when underlying I/O is still in flight. */
165
+ write: (node: SessionNode) => Promise<void>;
166
+ /** Optional flush + cleanup hook — called by `Session.close()`. */
167
+ close?: () => Promise<void>;
168
+ /** Optional bulk iterator for the full DAG — used by `/tree` UI and
169
+ * the masker's full-history scans. Backends with lazy reads can
170
+ * override with a more efficient bulk-scan implementation. */
171
+ all?: () => Iterable<SessionNode> | AsyncIterable<SessionNode>;
172
+ }
173
+ //#endregion
174
+ //#region src/session/jsonl.d.ts
175
+ /**
176
+ * JSONL-backed `SessionStore` — append-only file, one record per line.
177
+ *
178
+ * Current implementation reads the entire file on `load()` and keeps the
179
+ * full DAG in memory. Future optimizations (lazy reads with offset
180
+ * index, LRU cache for huge sessions) can land behind this same
181
+ * interface without changing `Session`.
182
+ *
183
+ * Crash tolerance: a truncated last line (interrupted mid-write) is
184
+ * silently dropped; any other JSON parse error mid-file throws so real
185
+ * corruption surfaces loudly.
186
+ */
187
+ declare class JsonlStore implements SessionStore {
188
+ #private;
189
+ readonly path: string;
190
+ constructor(path: string);
191
+ /** Load + open: hydrate the DAG from `path` (when the file exists),
192
+ * then open the writer in append mode. New nodes land on disk as
193
+ * they're committed. */
194
+ static load(path: string): Promise<JsonlStore>;
195
+ get root(): SessionNode | undefined;
196
+ get(id: string): Promise<SessionNode | undefined>;
197
+ write(node: SessionNode): Promise<void>;
198
+ close(): Promise<void>;
199
+ all(): AsyncIterable<SessionNode>;
200
+ }
201
+ declare class JsonlReader<T> {
202
+ #private;
203
+ readonly path: string;
204
+ constructor(path: string);
205
+ private generator;
206
+ next(): Promise<T | undefined>;
207
+ close(): Promise<void>;
208
+ }
209
+ //#endregion
210
+ //#region src/session/memory.d.ts
211
+ /**
212
+ * In-memory `SessionStore` — a `Map<uuid, SessionNode>` plus a `root`
213
+ * pointer. No persistence. Construction takes optional initial nodes
214
+ * for tests, replay tools, and the Claude session importer.
215
+ */
216
+ declare class MemoryStore implements SessionStore {
217
+ #private;
218
+ constructor(nodes?: Iterable<SessionNode>);
219
+ get root(): SessionNode | undefined;
220
+ get(id: string): Promise<SessionNode | undefined>;
221
+ write(node: SessionNode): Promise<void>;
222
+ all(): Iterable<SessionNode>;
223
+ }
224
+ //#endregion
225
+ //#region src/session/session.d.ts
226
+ /**
227
+ * Conversation primitive. Owns a DAG of message + compaction + meta
228
+ * nodes via a `SessionStore` backend; the *active* message list is
229
+ * whatever you get by walking `parentUuid` backwards from the store's
230
+ * root until you hit a `compact` node (or the start).
231
+ *
232
+ * **Meta is snapshot-based.** `session-meta` nodes carry the full
233
+ * cumulative meta as of their commit time. Other node types (start,
234
+ * resume, message, compact) don't carry meta — `Session` reconstructs
235
+ * the cumulative meta at any point by finding the most recent
236
+ * `session-meta` ancestor in a forward pass over the chain. Public
237
+ * APIs return `SessionNodeView` (raw node + decorated `meta`).
238
+ *
239
+ * Designed so the loop, the persistor, the TUI, and any replay tool
240
+ * all read from one source of truth and never mutate the DAG behind
241
+ * each other's backs:
242
+ *
243
+ * - **Run loop** (`Agent`) calls `add()` on each new message and
244
+ * `compact()` on overflow.
245
+ * - **TUI** subscribes to the `node` event for streaming render.
246
+ * - **Persistor** is the `SessionStore` — `MemoryStore` for ephemeral
247
+ * sessions, `JsonlStore` for file-backed.
248
+ *
249
+ * Construction:
250
+ * - Use `await Session.load(opts)` for the recommended path — picks
251
+ * the right store (Memory if no path, JSONL if path).
252
+ * - For tests / direct embedding, `new Session({ store })` works with
253
+ * any pre-built store.
254
+ */
255
+ declare class Session<T extends SessionStore = SessionStore> extends Emitter<SessionEvents> {
256
+ #private;
257
+ protected constructor(opts: SessionInit<T>);
258
+ /** Recommended one-step path: pick the right store backend, hydrate
259
+ * if applicable, return a ready-to-use session.
260
+ *
261
+ * - `path` provided → `JsonlStore` (file-backed, hydrates from disk
262
+ * if the file exists, opens for append either way).
263
+ * - No `path` → `MemoryStore` (ephemeral, no persistence). */
264
+ static load<T extends SessionStore = SessionStore>(opts: SessionOptions<T> & {
265
+ store: T;
266
+ }): Promise<Session<T>>;
267
+ static load(opts: SessionOptions & {
268
+ path: string;
269
+ }): Promise<Session<JsonlStore>>;
270
+ static load(opts?: SessionOptions & {}): Promise<Session<MemoryStore>>;
271
+ private static create;
272
+ /** Efficiently fetch the most recent user message by walking backward until we hit
273
+ * a user message, without reconstructing the full chain. Useful for a session picker. */
274
+ static lastMessage(opts?: SessionOptions): Promise<Message<"user"> | undefined>;
275
+ /** Active conversation — chain from current head back to the most
276
+ * recent compact (exclusive), in chronological order. This is what
277
+ * the agent sees on the next request. */
278
+ get messages(): readonly Message[];
279
+ get maskCheckpoint(): MaskCheckpoint | undefined;
280
+ get id(): string;
281
+ get dir(): string;
282
+ get path(): string | undefined;
283
+ get started(): boolean;
284
+ /** Current session settings, merged with defaults. */
285
+ get settings(): SessionSettings;
286
+ update(settings: SessionUpdate, opts?: {
287
+ force?: boolean;
288
+ }): Promise<string>;
289
+ /** Explicitly mark the session as started — writes a `session-start`
290
+ * marker on a fresh session, `session-resume` on a hydrated one.
291
+ * Idempotent; subsequent calls are no-ops. Optional `meta` is
292
+ * applied via `update()` after the marker lands. */
293
+ start(settings?: SessionUpdate): Promise<string | undefined>;
294
+ /** Look up the decorated view for a node id — raw node plus the
295
+ * cumulative meta as of that node's position. Returns the
296
+ * message-typed view, or `undefined` if the id doesn't refer to a
297
+ * message in this session. */
298
+ node(id?: string | Message): Promise<(SessionNodeView & {
299
+ type: "message";
300
+ }) | undefined>;
301
+ /** Current head uuid — the root of the store, which is the most
302
+ * recently appended node. */
303
+ get head(): string | undefined;
304
+ /** Full DAG iterator — backed by `store.all()`. Yields raw nodes
305
+ * (no meta decoration). */
306
+ nodes(): Iterable<SessionNode> | AsyncIterable<SessionNode>;
307
+ get root(): SessionNode | undefined;
308
+ /** Append a message. The new node is parented to the current head,
309
+ * head advances, and a `node` event fires. Optional `meta` carries
310
+ * usage / model / finish info — populate it for assistant turns
311
+ * the agent commits after a step. Returns the assigned uuid.
312
+ *
313
+ * If `message.id` / `message.ts` are set (e.g. round-tripped from a
314
+ * prior load), they're used as the node's uuid / timestamp; otherwise
315
+ * fresh values are generated. The committed message always carries
316
+ * both — `m.id === node.uuid` and `m.ts === node.ts`. */
317
+ add(message: Message): Promise<string>;
318
+ /** Mark a compaction boundary. Subsequent `add()` calls land after
319
+ * this node; their messages form the new active conversation. The
320
+ * pre-compact chain stays in the store but is no longer part of
321
+ * `messages`. Also commits a fresh `session-meta` snapshot right
322
+ * after the compact so post-compact lazy walks always have a nearby
323
+ * meta anchor. */
324
+ compact(opts: {
325
+ trigger?: "manual" | "auto";
326
+ preTokens?: number;
327
+ durationMs?: number;
328
+ tail: number;
329
+ summary: Message<"system">;
330
+ }): Promise<string>;
331
+ addMaskCheckpoint(opts: MaskCheckpoint): Promise<string>;
332
+ checkout(uuid: string): Promise<void>;
333
+ /** Pre-active history of the current chain — messages from before
334
+ * the most recent compact (and earlier compacts), in chronological
335
+ * order. Useful for TUI scrollback that wants to render context the
336
+ * agent itself no longer sees.
337
+ *
338
+ * `limit` truncates from the front (oldest), so the most recent
339
+ * history messages always make it through. */
340
+ history(limit?: number): Promise<readonly Message[]>;
341
+ /** Flush + close the underlying store. Subsequent writes throw. */
342
+ close(): Promise<void>;
343
+ }
344
+ //#endregion
345
+ export { SessionStore as a, SessionEvents as c, SessionNode as d, SessionNodeView as f, SessionView as g, SessionUpdate as h, JsonlStore as i, SessionInit as l, SessionSettings as m, MemoryStore as n, MaskCheckpoint as o, SessionOptions as p, JsonlReader as r, PartialNode as s, Session as t, SessionMessage as u };
346
+ //# sourceMappingURL=session-Ds5nJz5A.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-Ds5nJz5A.d.mts","names":[],"sources":["../src/session/types.ts","../src/session/store.ts","../src/session/jsonl.ts","../src/session/memory.ts","../src/session/session.ts"],"mappings":";;;;;;;;;;KAYK;EACH;;EAEA;;EAEA;;EAEI;;EACA;;EACA;EAA0B,UAAU;;EACpC;EAAiB,SAAS;;EAC1B;EAAyB;EAAmB;;EAE5C;;EAEA;;EAEA;;EAEA;;EAEA;;;;;EAKA,SAAS;;KAGV,kBAAkB;KAEX;EAAmB;EAAmB;;KAEtC,iBAAiB;EAAY;EAAY;;KAEzC,YAAY,UAAU,kBAAkB,mBAAmB,QACrE;EACE,MAAM;;;;;KAME,kBAAkB;EAAgB,UAAU;;KAE5C;EACV,UAAU;EACV,OAAO,YAAY;EACnB,UAAU;EACV,iBAAiB;;KAGP;EACV;EACA;EACA;EACA;EACA;EACA,YAAY;;KAGF,gBAAgB,KAAK;KAE5B,iBAAiB,GAAG,UAAU,eAAe,oBAAoB,KAAK,GAAG;KAElE,cAAc,iBAAiB;;;KAM/B;EACV;IAAQ,MAAM;;EACd;IAAY;IAA0B,mBAAmB;;EACzD;IAAW,MAAM;;EAEjB;IAAO;IAAa;;EACpB;IAAS;IAAe;;EACxB;IAAa,QAAQ;IAAiB,OAAO;;EAE7C;EACA;;KAKU,eAAe,UAAU,eAAe;EAClD,QAAQ;;;;;EAKR;;;;;EAKA;;;EAGA,WAAW,KAAK;;KAGN,YAAY,UAAU,eAAe,gBAAgB;;;EAG/D,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;UC7FQ;;;WAGN,MAAM;;EAGf,MAAM,eAAe,QAAQ;;;;EAK7B,QAAQ,MAAM,gBAAgB;;EAG9B,cAAc;;;;EAKd,YAAY,SAAS,eAAe,cAAc;;;;;;;;;;;;;;;;cCvBvC,sBAAsB;;WACxB;EAKT,YAAY;;;;SAQC,KAAK,eAAe,QAAQ;MAmBrC,QAAQ;EAIN,IAAI,aAAa,QAAQ;EAIzB,MAAM,MAAM,cAAc;EAS1B,SAAS;EAIR,OAAO,cAAc;;cAMjB,YAAY;;WAMF;EAArB,YAAqB;UAsBN;EAgCT,QAAQ,QAAQ;EAMhB,SAAK;;;;;;;;;cC3IA,uBAAuB;;EAIlC,YAAY,QAAQ,SAAS;MAUzB,QAAQ;EAIN,IAAI,aAAa,QAAQ;EAIzB,MAAM,MAAM,cAAc;EAK/B,OAAO,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCoBN,QAAQ,UAAU,eAAe,sBAAsB,QAAQ;;YAYjE,YAAa,MAAM,YAAY;;;;;;;SAe3B,KAAK,UAAU,eAAe,cACzC,MAAM,eAAe;IAAO,OAAO;MAClC,QAAQ,QAAQ;SACN,KAAK,MAAM;IAAmB;MAAiB,QAAQ,QAAQ;SAC/D,KAAK,OAAO,sBAAsB,QAAQ,QAAQ;iBAO1C;;;SAUR,YAAY,OAAM,iBAAsB,QAAQ;;;;MA4BzD,qBAAqB;MAIrB,kBAAkB;MAIlB;MAIA;MAIA;MAIA;;MAKA,YAAY;EAIV,OAAO,UAAU,eAAe;IAAS;MAAoB;;;;;EAe7D,MAAM,WAAW,gBAAgB;;;;;EAcjC,KAAK,cAAc,UAAU,SAAS;IAAoB;;;;MAS5D;;;EAMJ,SAAS,SAAS,eAAe,cAAc;MAI3C,QAAQ;;;;;;;;;;EAeN,IAAI,SAAS,UAAU;;;;;;;EAavB,QAAQ;IACZ;IACA;IACA;IACA;IACA,SAAS;MACP;EAmBE,kBAAkB,MAAM,iBAAiB;EAKzC,SAAS,eAAe;;;;;;;;EAaxB,QAAQ,iBAAiB,iBAAiB;;EAM1C,SAAS"}
@@ -0,0 +1,37 @@
1
+ import { a as SessionStore, c as SessionEvents, d as SessionNode, f as SessionNodeView, g as SessionView, h as SessionUpdate, i as JsonlStore, l as SessionInit, m as SessionSettings, n as MemoryStore, o as MaskCheckpoint, p as SessionOptions, r as JsonlReader, s as PartialNode, t as Session, u as SessionMessage } from "./session-Ds5nJz5A.mjs";
2
+ import { Stats } from "node:fs";
3
+ //#region src/session/manager.d.ts
4
+ type SessionInfo = {
5
+ /** uuidv7 session id. Absent for non-managed external paths until the
6
+ * session is loaded — the file's session-start node carries the
7
+ * authoritative id. */
8
+ id: string;
9
+ /** Absolute path to the session file. Typically within `zalyPaths.sessions`. */
10
+ path: string;
11
+ /** Data directory used for session artifacts */
12
+ dir: string;
13
+ /** The session's workspace containing its .zaly/ resources */
14
+ workspace: string;
15
+ /** Populated when listing with `sort: true` */
16
+ mtime?: number;
17
+ stat?: Stats;
18
+ };
19
+ type SessionFilter = {
20
+ /** (partial) uuid for a session */
21
+ id?: string;
22
+ /** sessions with this workspace */
23
+ workspace?: string;
24
+ /** glob pattern matching any workspace sessions */
25
+ pattern?: string;
26
+ };
27
+ type SessionListOpts = {
28
+ filter?: string | SessionFilter;
29
+ sort?: boolean;
30
+ };
31
+ declare function listSessions(opts?: SessionListOpts): Promise<SessionInfo[]>;
32
+ declare function resumeSession(filter: string | SessionFilter): Promise<Session | undefined>;
33
+ declare function loadSession(opts?: Partial<SessionInfo>): Promise<Session>;
34
+ declare function sessionInfo(opts?: Partial<SessionInfo>): SessionInfo;
35
+ //#endregion
36
+ export { JsonlReader, JsonlStore, type MaskCheckpoint, MemoryStore, type PartialNode, Session, type SessionEvents, SessionFilter, SessionInfo, type SessionInit, SessionListOpts, type SessionMessage, type SessionNode, type SessionNodeView, type SessionOptions, type SessionSettings, type SessionStore, type SessionUpdate, type SessionView, listSessions, loadSession, resumeSession, sessionInfo };
37
+ //# sourceMappingURL=session.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.mts","names":[],"sources":["../src/session/manager.ts"],"mappings":";;;KAUY;;;;EAIV;;EAEA;;EAEA;;EAEA;;EAEA;EACA,OAAO;;KAGG;;EAEV;;EAEA;;EAEA;;KAGU;EACV,kBAAkB;EAClB;;iBAcoB,aAAa,OAAM,kBAAoB,QAAA;iBAyCvC,cAAc,iBAAiB,gBAAgB,QAAQ;iBAKvD,YAAY,OAAM,QAAQ,eAAoB,QAAQ;iBAc5D,YAAY,OAAM,QAAQ,eAAoB"}
@@ -0,0 +1,106 @@
1
+ import { n as isUuidv7Like, r as uuidv7 } from "./uuid-ByXP5SO5.mjs";
2
+ import { n as JsonlStore, t as JsonlReader } from "./jsonl-Dw_VBp46.mjs";
3
+ import { r as MemoryStore, t as Session } from "./session-CUUdWFC5.mjs";
4
+ import { decodePath, encodePath, normPath, safeStatAsync } from "@zaly/shared";
5
+ import { basename, dirname, join, relative } from "pathe";
6
+ import { glob } from "@zaly/shared/glob";
7
+ import { mkdir, stat } from "node:fs/promises";
8
+ import { zalyPaths } from "@zaly/shared/paths";
9
+ //#region src/session/manager.ts
10
+ async function toFilter(filter) {
11
+ if (isUuidv7Like(filter)) return { id: filter };
12
+ if ((await safeStatAsync(filter))?.isDirectory()) return { workspace: filter };
13
+ return { pattern: filter };
14
+ }
15
+ function workspaceSlug(workspace) {
16
+ return encodePath(normPath(workspace));
17
+ }
18
+ async function listSessions(opts = {}) {
19
+ const filter = typeof opts.filter === "string" ? await toFilter(opts.filter) : opts.filter ?? {};
20
+ let slug = filter.workspace ? workspaceSlug(filter.workspace) : void 0;
21
+ slug ??= filter.pattern ? `*${filter.pattern}*` : void 0;
22
+ slug ??= "*";
23
+ const isGlob = slug.includes("*");
24
+ const root = isGlob ? zalyPaths.sessions : join(zalyPaths.sessions, slug);
25
+ const pattern = [];
26
+ if (isGlob) pattern.push(slug);
27
+ if (filter.id) pattern.push(filter.id.length >= 36 ? filter.id.slice(0, 36) : `${filter.id}*`);
28
+ else pattern.push("*");
29
+ pattern.push("session.jsonl");
30
+ const paths = glob(pattern.join("/"), {
31
+ cwd: root,
32
+ depth: pattern.length,
33
+ ignore: false,
34
+ type: "file"
35
+ });
36
+ const ret = [];
37
+ for await (const rel of paths) {
38
+ const path = normPath(root, rel);
39
+ ret.push(sessionInfo({ path }));
40
+ }
41
+ if (!opts.sort) return ret;
42
+ return (await Promise.all(ret.map(async (session) => {
43
+ const s = await stat(session.path).catch(() => void 0);
44
+ session.mtime = s?.mtimeMs;
45
+ session.stat = s;
46
+ return session;
47
+ }))).filter((e) => e.mtime !== void 0).toSorted((a, b) => b.mtime - a.mtime);
48
+ }
49
+ async function resumeSession(filter) {
50
+ const list = await listSessions({
51
+ filter,
52
+ sort: true
53
+ });
54
+ return list.length === 0 ? void 0 : loadSession(list[0]);
55
+ }
56
+ async function loadSession(opts = {}) {
57
+ const info = sessionInfo(opts);
58
+ await mkdir(info.dir, { recursive: true });
59
+ return Session.load({
60
+ defaults: {
61
+ cwd: normPath(),
62
+ sessionId: info.id,
63
+ workspace: info.workspace
64
+ },
65
+ dir: info.dir,
66
+ path: info.path
67
+ });
68
+ }
69
+ function sessionInfo(opts = {}) {
70
+ if (opts.path && !relative(zalyPaths.sessions, opts.path).startsWith("..")) {
71
+ const path = normPath(opts.path);
72
+ const dir = normPath(opts.dir ?? dirname(path));
73
+ const id = opts.id ?? basename(dir);
74
+ const slug = basename(dirname(dir));
75
+ return {
76
+ dir,
77
+ id,
78
+ path,
79
+ workspace: normPath(opts.workspace ?? decodePath(slug))
80
+ };
81
+ } else if (opts.path) {
82
+ const path = normPath(opts.path);
83
+ const dir = normPath(opts.dir ?? dirname(path));
84
+ const workspace = normPath(opts.workspace);
85
+ return {
86
+ dir,
87
+ id: uuidv7(),
88
+ path,
89
+ workspace
90
+ };
91
+ }
92
+ const workspace = normPath(opts.workspace);
93
+ const slug = workspaceSlug(workspace);
94
+ const id = opts.id ?? uuidv7();
95
+ const dir = opts.dir ? normPath(opts.dir) : normPath(zalyPaths.sessions, slug, id);
96
+ return {
97
+ dir,
98
+ id,
99
+ path: normPath(dir, "session.jsonl"),
100
+ workspace
101
+ };
102
+ }
103
+ //#endregion
104
+ export { JsonlReader, JsonlStore, MemoryStore, Session, listSessions, loadSession, resumeSession, sessionInfo };
105
+
106
+ //# sourceMappingURL=session.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.mjs","names":[],"sources":["../src/session/manager.ts"],"sourcesContent":["import type { Stats } from \"node:fs\"\n\nimport { decodePath, encodePath, normPath, safeStatAsync } from \"@zaly/shared\"\nimport { glob } from \"@zaly/shared/glob\"\nimport { zalyPaths } from \"@zaly/shared/paths\"\nimport { mkdir, stat } from \"node:fs/promises\"\nimport { basename, dirname, join, relative } from \"pathe\"\nimport { isUuidv7Like, uuidv7 } from \"../utils/uuid.ts\"\nimport { Session } from \"./session.ts\"\n\nexport type SessionInfo = {\n /** uuidv7 session id. Absent for non-managed external paths until the\n * session is loaded — the file's session-start node carries the\n * authoritative id. */\n id: string\n /** Absolute path to the session file. Typically within `zalyPaths.sessions`. */\n path: string\n /** Data directory used for session artifacts */\n dir: string\n /** The session's workspace containing its .zaly/ resources */\n workspace: string\n /** Populated when listing with `sort: true` */\n mtime?: number\n stat?: Stats\n}\n\nexport type SessionFilter = {\n /** (partial) uuid for a session */\n id?: string\n /** sessions with this workspace */\n workspace?: string\n /** glob pattern matching any workspace sessions */\n pattern?: string\n}\n\nexport type SessionListOpts = {\n filter?: string | SessionFilter\n sort?: boolean\n}\n\nasync function toFilter(filter: string): Promise<SessionFilter> {\n if (isUuidv7Like(filter)) return { id: filter }\n const s = await safeStatAsync(filter)\n if (s?.isDirectory()) return { workspace: filter }\n return { pattern: filter }\n}\n\nfunction workspaceSlug(workspace?: string) {\n return encodePath(normPath(workspace))\n}\n\nexport async function listSessions(opts: SessionListOpts = {}) {\n const filter = typeof opts.filter === \"string\" ? await toFilter(opts.filter) : (opts.filter ?? {})\n let slug = filter.workspace ? workspaceSlug(filter.workspace) : undefined\n slug ??= filter.pattern ? `*${filter.pattern}*` : undefined\n slug ??= \"*\"\n const isGlob = slug.includes(\"*\")\n const root = isGlob ? zalyPaths.sessions : join(zalyPaths.sessions, slug)\n\n const pattern: string[] = []\n if (isGlob) pattern.push(slug)\n\n if (filter.id) pattern.push(filter.id.length >= 36 ? filter.id.slice(0, 36) : `${filter.id}*`)\n else pattern.push(\"*\")\n\n pattern.push(\"session.jsonl\")\n\n const paths = glob(pattern.join(\"/\"), {\n cwd: root,\n depth: pattern.length,\n ignore: false,\n type: \"file\",\n })\n const ret: SessionInfo[] = []\n for await (const rel of paths) {\n const path = normPath(root, rel)\n ret.push(sessionInfo({ path }))\n }\n if (!opts.sort) return ret\n const stats = await Promise.all(\n ret.map(async (session) => {\n const s = await stat(session.path).catch(() => undefined)\n session.mtime = s?.mtimeMs\n session.stat = s\n return session\n })\n )\n return stats\n .filter((e): e is SessionInfo & { mtime: number } => e.mtime !== undefined)\n .toSorted((a, b) => b.mtime - a.mtime) // newest first\n}\n\nexport async function resumeSession(filter: string | SessionFilter): Promise<Session | undefined> {\n const list = await listSessions({ filter, sort: true })\n return list.length === 0 ? undefined : loadSession(list[0])\n}\n\nexport async function loadSession(opts: Partial<SessionInfo> = {}): Promise<Session> {\n const info = sessionInfo(opts)\n await mkdir(info.dir, { recursive: true })\n return Session.load({\n defaults: {\n cwd: normPath(),\n sessionId: info.id,\n workspace: info.workspace,\n },\n dir: info.dir,\n path: info.path,\n })\n}\n\nexport function sessionInfo(opts: Partial<SessionInfo> = {}): SessionInfo {\n if (opts.path && !relative(zalyPaths.sessions, opts.path).startsWith(\"..\")) {\n // Managed session\n const path = normPath(opts.path)\n const dir = normPath(opts.dir ?? dirname(path))\n const id = opts.id ?? basename(dir)\n const slug = basename(dirname(dir))\n const workspace = normPath(opts.workspace ?? decodePath(slug))\n return { dir, id, path, workspace }\n } else if (opts.path) {\n // Existing session, but not in a managed location\n const path = normPath(opts.path)\n const dir = normPath(opts.dir ?? dirname(path))\n const workspace = normPath(opts.workspace)\n return { dir, id: uuidv7(), path, workspace }\n }\n // New session\n const workspace = normPath(opts.workspace) // defaults to cwd\n const slug = workspaceSlug(workspace)\n const id = opts.id ?? uuidv7()\n const dir = opts.dir ? normPath(opts.dir) : normPath(zalyPaths.sessions, slug, id)\n const path = normPath(dir, \"session.jsonl\")\n return { dir, id, path, workspace }\n}\n"],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ import { r as uuidv7 } from "./uuid-ByXP5SO5.mjs";
2
+ import { join } from "pathe";
3
+ import { AiError, defineTool, stringifyContent } from "@zaly/ai";
4
+ import { Type } from "typebox";
5
+ import { tmpdir } from "node:os";
6
+ //#region src/tools/subagent.ts
7
+ const subagentTool = defineTool({
8
+ name: "subagent",
9
+ desc: "Spawn a focused subagent with the same model and permissions. Use for tasks that benefit from a clean context window: deep code exploration, multi-step research, or anything where dragging the intermediate steps through your own context would be expensive. The subagent's final answer comes back as the result; full transcript is available at the returned `sessionPath` if you need more detail.",
10
+ parallel: true,
11
+ params: Type.Object({
12
+ description: Type.String({ description: "Short description of what the subagent should do. Shown to the user in the TUI. Keep under ~10 words." }),
13
+ prompt: Type.String({ description: "System prompt for the subagent — defines its role and constraints. The subagent does NOT inherit your system prompt; spell out what it needs to know." }),
14
+ task: Type.String({ description: "The actual task the subagent should perform, as if you were sending it as a user message. Be specific about the deliverable." })
15
+ }),
16
+ async call(args, ctx) {
17
+ const parent = ctx.agent;
18
+ if (!parent) throw new AiError({
19
+ code: "MISSING_TOOL_CONTEXT",
20
+ message: "subagent requires an Agent reference on the context (set up by the agent harness)."
21
+ });
22
+ const id = uuidv7();
23
+ const sessionPath = join(tmpdir(), `zaly-subagent-${id}.jsonl`);
24
+ const startedAt = Date.now();
25
+ const { Session } = await import("./session-CUUdWFC5.mjs").then((n) => n.n);
26
+ const child = await parent.child({
27
+ prompt: [args.prompt],
28
+ session: await Session.load({ path: sessionPath })
29
+ });
30
+ const depth = child.depth;
31
+ let textBuffer = "";
32
+ let cursor = 0;
33
+ let finalResult;
34
+ let stopReason;
35
+ child.on("stream-event", ({ event }) => {
36
+ if (event.type === "text-delta" && typeof event.delta === "string") textBuffer += event.delta;
37
+ });
38
+ child.on("stop", ({ kind }) => {
39
+ stopReason = kind;
40
+ });
41
+ child.send({
42
+ content: args.task,
43
+ role: "user"
44
+ });
45
+ const runDone = child.run().catch((error) => {
46
+ stopReason = "error";
47
+ throw error;
48
+ });
49
+ const buildMeta = (running) => ({
50
+ depth,
51
+ durationMs: Date.now() - startedAt,
52
+ id,
53
+ sessionPath,
54
+ status: running ? "running" : "done",
55
+ stop: stopReason,
56
+ usage: {
57
+ input: child.totalUsage.input,
58
+ output: child.totalUsage.output
59
+ }
60
+ });
61
+ /** Pull the last assistant text out of the child's session — the
62
+ * user-visible "answer." Falls back to whatever's accumulated in the
63
+ * text buffer if the assistant hasn't committed a message yet. */
64
+ const finalText = () => {
65
+ for (let i = child.messages.length - 1; i >= 0; i--) {
66
+ const m = child.messages[i];
67
+ if (m.role !== "assistant") continue;
68
+ const text = stringifyContent(m.content).trim();
69
+ if (text !== "") return text;
70
+ }
71
+ return textBuffer.trim();
72
+ };
73
+ const buildResult = (running) => {
74
+ if (!running && finalResult) return {
75
+ ...finalResult,
76
+ running: false
77
+ };
78
+ const meta = buildMeta(running);
79
+ const slice = textBuffer.slice(cursor);
80
+ cursor = textBuffer.length;
81
+ const parts = [{
82
+ data: meta,
83
+ tag: "subagent",
84
+ type: "meta"
85
+ }];
86
+ if (running) {
87
+ if (slice !== "") parts.push({
88
+ text: slice,
89
+ type: "text"
90
+ });
91
+ } else {
92
+ const answer = finalText();
93
+ if (answer !== "") parts.push({
94
+ text: answer,
95
+ type: "text"
96
+ });
97
+ }
98
+ return {
99
+ content: parts,
100
+ isError: false,
101
+ running
102
+ };
103
+ };
104
+ return {
105
+ abort: () => {
106
+ child.stop();
107
+ },
108
+ done: runDone.then(async () => {
109
+ await child.session.close();
110
+ finalResult = buildResult(false);
111
+ }, async (error) => {
112
+ stopReason ??= "error";
113
+ await child.session.close().catch(() => void 0);
114
+ const meta = buildMeta(false);
115
+ const message = error instanceof Error ? error.message : String(error);
116
+ finalResult = {
117
+ content: [{
118
+ data: meta,
119
+ tag: "subagent",
120
+ type: "meta"
121
+ }, {
122
+ text: `subagent failed: ${message}`,
123
+ type: "text"
124
+ }],
125
+ isError: true
126
+ };
127
+ }),
128
+ hasNew: () => textBuffer.length > cursor,
129
+ poll: () => buildResult(child.status !== "idle" && child.status !== "paused")
130
+ };
131
+ }
132
+ });
133
+ //#endregion
134
+ export { subagentTool };
135
+
136
+ //# sourceMappingURL=subagent-baqzjRMc.mjs.map