@kenkaiiii/gg-boss 4.3.96

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 (78) hide show
  1. package/LICENSE +21 -0
  2. package/dist/banner.d.ts +11 -0
  3. package/dist/banner.d.ts.map +1 -0
  4. package/dist/banner.js +25 -0
  5. package/dist/banner.js.map +1 -0
  6. package/dist/boot-banner.d.ts +15 -0
  7. package/dist/boot-banner.d.ts.map +1 -0
  8. package/dist/boot-banner.js +61 -0
  9. package/dist/boot-banner.js.map +1 -0
  10. package/dist/boss-footer.d.ts +16 -0
  11. package/dist/boss-footer.d.ts.map +1 -0
  12. package/dist/boss-footer.js +60 -0
  13. package/dist/boss-footer.js.map +1 -0
  14. package/dist/boss-store.d.ts +202 -0
  15. package/dist/boss-store.d.ts.map +1 -0
  16. package/dist/boss-store.js +560 -0
  17. package/dist/boss-store.js.map +1 -0
  18. package/dist/boss-system-prompt.d.ts +3 -0
  19. package/dist/boss-system-prompt.d.ts.map +1 -0
  20. package/dist/boss-system-prompt.js +52 -0
  21. package/dist/boss-system-prompt.js.map +1 -0
  22. package/dist/branding.d.ts +18 -0
  23. package/dist/branding.d.ts.map +1 -0
  24. package/dist/branding.js +33 -0
  25. package/dist/branding.js.map +1 -0
  26. package/dist/cli.d.ts +3 -0
  27. package/dist/cli.d.ts.map +1 -0
  28. package/dist/cli.js +163 -0
  29. package/dist/cli.js.map +1 -0
  30. package/dist/discover.d.ts +13 -0
  31. package/dist/discover.d.ts.map +1 -0
  32. package/dist/discover.js +92 -0
  33. package/dist/discover.js.map +1 -0
  34. package/dist/event-queue.d.ts +16 -0
  35. package/dist/event-queue.d.ts.map +1 -0
  36. package/dist/event-queue.js +39 -0
  37. package/dist/event-queue.js.map +1 -0
  38. package/dist/index.d.ts +6 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +5 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/link-command.d.ts +2 -0
  43. package/dist/link-command.d.ts.map +1 -0
  44. package/dist/link-command.js +120 -0
  45. package/dist/link-command.js.map +1 -0
  46. package/dist/links.d.ts +11 -0
  47. package/dist/links.d.ts.map +1 -0
  48. package/dist/links.js +22 -0
  49. package/dist/links.js.map +1 -0
  50. package/dist/orchestrator-app.d.ts +15 -0
  51. package/dist/orchestrator-app.d.ts.map +1 -0
  52. package/dist/orchestrator-app.js +248 -0
  53. package/dist/orchestrator-app.js.map +1 -0
  54. package/dist/orchestrator.d.ts +79 -0
  55. package/dist/orchestrator.d.ts.map +1 -0
  56. package/dist/orchestrator.js +405 -0
  57. package/dist/orchestrator.js.map +1 -0
  58. package/dist/sessions.d.ts +21 -0
  59. package/dist/sessions.d.ts.map +1 -0
  60. package/dist/sessions.js +122 -0
  61. package/dist/sessions.js.map +1 -0
  62. package/dist/slash-commands.d.ts +19 -0
  63. package/dist/slash-commands.d.ts.map +1 -0
  64. package/dist/slash-commands.js +54 -0
  65. package/dist/slash-commands.js.map +1 -0
  66. package/dist/tools.d.ts +10 -0
  67. package/dist/tools.d.ts.map +1 -0
  68. package/dist/tools.js +81 -0
  69. package/dist/tools.js.map +1 -0
  70. package/dist/types.d.ts +32 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +2 -0
  73. package/dist/types.js.map +1 -0
  74. package/dist/worker.d.ts +40 -0
  75. package/dist/worker.d.ts.map +1 -0
  76. package/dist/worker.js +113 -0
  77. package/dist/worker.js.map +1 -0
  78. package/package.json +47 -0
@@ -0,0 +1,405 @@
1
+ import { Agent, isAbortError } from "@kenkaiiii/gg-agent";
2
+ import { AuthStorage, compact, getContextWindow, shouldCompact } from "@kenkaiiii/ggcoder";
3
+ import { Worker } from "./worker.js";
4
+ import { EventQueue } from "./event-queue.js";
5
+ import { createBossTools } from "./tools.js";
6
+ import { buildBossSystemPrompt } from "./boss-system-prompt.js";
7
+ import { bossStore } from "./boss-store.js";
8
+ import { appendMessages, createSession, getMostRecent, getSessionById, loadSession, } from "./sessions.js";
9
+ /**
10
+ * The orchestrator. Owns N workers, a single shared event queue, and the boss Agent.
11
+ * Each loop iteration: pop one event, format it as a user message, run the boss for
12
+ * one full prompt (which may dispatch tool calls to workers), then await the next event.
13
+ *
14
+ * UI state is mirrored into bossStore — components subscribe via useBossState().
15
+ */
16
+ export class GGBoss {
17
+ workers = new Map();
18
+ lastSummaries = new Map();
19
+ queue = new EventQueue();
20
+ bossAgent;
21
+ ac = new AbortController();
22
+ /** Per-turn AbortController so ESC can cancel the current LLM call without killing workers. */
23
+ turnAc = null;
24
+ running = false;
25
+ pendingUserMessages = 0;
26
+ opts;
27
+ authStorage = new AuthStorage();
28
+ /** Path to the boss's per-session jsonl log under ~/.gg/boss/sessions/. */
29
+ sessionPath = "";
30
+ /** Last index in the boss's messages array we've persisted to disk. */
31
+ lastPersistedIndex = 0;
32
+ constructor(opts) {
33
+ this.opts = opts;
34
+ }
35
+ async initialize() {
36
+ await this.authStorage.load();
37
+ const loggedInProviders = (await this.authStorage.listProviders());
38
+ bossStore.init({
39
+ bossProvider: this.opts.bossProvider,
40
+ bossModel: this.opts.bossModel,
41
+ workerProvider: this.opts.workerProvider,
42
+ workerModel: this.opts.workerModel,
43
+ loggedInProviders,
44
+ workers: this.opts.projects.map((p) => ({ name: p.name, cwd: p.cwd })),
45
+ });
46
+ await Promise.all(this.opts.projects.map(async (p) => {
47
+ const worker = new Worker({
48
+ name: p.name,
49
+ cwd: p.cwd,
50
+ provider: this.opts.workerProvider,
51
+ model: this.opts.workerModel,
52
+ thinkingLevel: this.opts.workerThinkingLevel,
53
+ signal: this.ac.signal,
54
+ queue: this.queue,
55
+ });
56
+ await worker.initialize();
57
+ this.workers.set(p.name, worker);
58
+ }));
59
+ const creds = await this.authStorage.resolveCredentials(this.opts.bossProvider);
60
+ const tools = createBossTools({
61
+ workers: this.workers,
62
+ lastSummaries: this.lastSummaries,
63
+ });
64
+ // Either resume a prior session (load messages from jsonl), or create a
65
+ // new one. Either way we end up with `sessionPath` to persist into.
66
+ let priorMessages;
67
+ if (this.opts.resumeSessionId) {
68
+ const info = await getSessionById(this.opts.resumeSessionId);
69
+ if (info) {
70
+ this.sessionPath = info.path;
71
+ priorMessages = (await loadSession(info.path)).filter((m) => m.role !== "system");
72
+ }
73
+ }
74
+ else if (this.opts.continueRecent) {
75
+ const recent = await getMostRecent();
76
+ if (recent) {
77
+ this.sessionPath = recent.path;
78
+ priorMessages = (await loadSession(recent.path)).filter((m) => m.role !== "system");
79
+ }
80
+ }
81
+ if (!this.sessionPath) {
82
+ const session = await createSession();
83
+ this.sessionPath = session.filePath;
84
+ }
85
+ // Rebuild the visible TUI history from the loaded messages so the chat
86
+ // shows the prior conversation, not just the agent's hidden context.
87
+ if (priorMessages && priorMessages.length > 0) {
88
+ bossStore.restoreHistory(priorMessages);
89
+ }
90
+ this.bossAgent = new Agent({
91
+ provider: this.opts.bossProvider,
92
+ model: this.opts.bossModel,
93
+ system: buildBossSystemPrompt(this.opts.projects),
94
+ tools,
95
+ apiKey: creds.accessToken,
96
+ accountId: creds.accountId,
97
+ signal: this.ac.signal,
98
+ cacheRetention: "short",
99
+ priorMessages,
100
+ });
101
+ // Mark every loaded message as already persisted so we only append NEW
102
+ // turns going forward. The system message is added by Agent's constructor
103
+ // and we never want to write the system prompt to disk (it's rebuilt each
104
+ // session from current project list) — so subtract one for it.
105
+ this.lastPersistedIndex = this.bossAgent.getMessages().length;
106
+ }
107
+ enqueueUserMessage(text) {
108
+ this.pendingUserMessages++;
109
+ bossStore.setPendingMessages(this.pendingUserMessages);
110
+ this.queue.push({
111
+ kind: "user_message",
112
+ text,
113
+ timestamp: new Date().toISOString(),
114
+ });
115
+ }
116
+ /**
117
+ * Abort the boss's current LLM call (e.g. user pressed ESC). Workers and the
118
+ * orchestrator's run loop keep going. The next event in the queue gets a
119
+ * fresh AbortController.
120
+ */
121
+ abort() {
122
+ this.turnAc?.abort();
123
+ }
124
+ /**
125
+ * Swap the boss's LLM model. Preserves message history so the conversation
126
+ * continues seamlessly under the new model.
127
+ */
128
+ async switchBossModel(provider, model) {
129
+ const tools = createBossTools({
130
+ workers: this.workers,
131
+ lastSummaries: this.lastSummaries,
132
+ });
133
+ const creds = await this.authStorage.resolveCredentials(provider);
134
+ // Capture history minus the system message — Agent re-adds system from options.
135
+ const oldMessages = this.bossAgent.getMessages().filter((m) => m.role !== "system");
136
+ this.opts.bossProvider = provider;
137
+ this.opts.bossModel = model;
138
+ this.bossAgent = new Agent({
139
+ provider,
140
+ model,
141
+ system: buildBossSystemPrompt(this.opts.projects),
142
+ tools,
143
+ apiKey: creds.accessToken,
144
+ accountId: creds.accountId,
145
+ signal: this.ac.signal,
146
+ cacheRetention: "short",
147
+ priorMessages: oldMessages,
148
+ });
149
+ bossStore.setBossModel(provider, model);
150
+ }
151
+ /** Swap every worker's model. Workers keep their per-project sessions. */
152
+ async switchWorkerModel(provider, model) {
153
+ await Promise.all([...this.workers.values()].map((w) => w.switchModel(provider, model)));
154
+ this.opts.workerProvider = provider;
155
+ this.opts.workerModel = model;
156
+ bossStore.setWorkerModel(provider, model);
157
+ }
158
+ /**
159
+ * Run a manual compaction now (driven by /compact). Will compact even if the
160
+ * threshold isn't reached yet — useful for trimming context before a long task.
161
+ */
162
+ async manualCompact() {
163
+ await this.runCompaction(true);
164
+ }
165
+ /** Compact only when threshold (default 80%) is exceeded. */
166
+ async runCompaction(force) {
167
+ const messages = this.bossAgent.getMessages();
168
+ const contextWindow = getContextWindow(this.opts.bossModel);
169
+ const tokens = bossStore.getInputTokens();
170
+ if (!force && !shouldCompact(messages, contextWindow, 0.8, tokens))
171
+ return;
172
+ bossStore.startCompaction();
173
+ try {
174
+ const creds = await this.authStorage.resolveCredentials(this.opts.bossProvider);
175
+ const { messages: compactedMessages, result } = await compact(messages, {
176
+ provider: this.opts.bossProvider,
177
+ model: this.opts.bossModel,
178
+ apiKey: creds.accessToken,
179
+ contextWindow,
180
+ signal: this.ac.signal,
181
+ });
182
+ await this.replaceBossMessages(compactedMessages);
183
+ // Start a new session file so `ggboss continue` resumes the COMPACTED
184
+ // history, not the full original. Mirrors ggcoder/AgentSession.compact.
185
+ const session = await createSession();
186
+ this.sessionPath = session.filePath;
187
+ this.lastPersistedIndex = 0;
188
+ await this.persistNewMessages();
189
+ bossStore.setBossInputTokens(0);
190
+ bossStore.endCompaction(result.originalCount, result.newCount);
191
+ }
192
+ catch (err) {
193
+ bossStore.cancelCompaction();
194
+ if (!isAbortError(err)) {
195
+ const message = err instanceof Error ? err.message : String(err);
196
+ bossStore.appendInfo(`Compaction failed: ${message}`, "error");
197
+ }
198
+ }
199
+ }
200
+ /**
201
+ * Append any boss messages that haven't been written yet to the session log.
202
+ * Skips the system message (regenerated each session from current project list).
203
+ */
204
+ async persistNewMessages() {
205
+ if (!this.sessionPath)
206
+ return;
207
+ const all = this.bossAgent.getMessages();
208
+ const newOnes = all.slice(this.lastPersistedIndex).filter((m) => m.role !== "system");
209
+ if (newOnes.length === 0)
210
+ return;
211
+ try {
212
+ await appendMessages(this.sessionPath, newOnes);
213
+ this.lastPersistedIndex = all.length;
214
+ }
215
+ catch {
216
+ // Persistence is best-effort — never crash the run loop on disk errors.
217
+ }
218
+ }
219
+ /** Recreate bossAgent with a new message history (used by compact + /clear). */
220
+ async replaceBossMessages(newMessages) {
221
+ const tools = createBossTools({
222
+ workers: this.workers,
223
+ lastSummaries: this.lastSummaries,
224
+ });
225
+ const creds = await this.authStorage.resolveCredentials(this.opts.bossProvider);
226
+ // Strip system — Agent re-adds it from `system`.
227
+ const priorMessages = newMessages.filter((m) => m.role !== "system");
228
+ this.bossAgent = new Agent({
229
+ provider: this.opts.bossProvider,
230
+ model: this.opts.bossModel,
231
+ system: buildBossSystemPrompt(this.opts.projects),
232
+ tools,
233
+ apiKey: creds.accessToken,
234
+ accountId: creds.accountId,
235
+ signal: this.ac.signal,
236
+ cacheRetention: "short",
237
+ priorMessages,
238
+ });
239
+ }
240
+ /**
241
+ * Start a brand-new boss session — fresh agent with no message history,
242
+ * fresh session file on disk so `ggboss continue` picks up the new chat.
243
+ * Workers are unaffected.
244
+ */
245
+ async newSession() {
246
+ const session = await createSession();
247
+ this.sessionPath = session.filePath;
248
+ this.lastPersistedIndex = 0;
249
+ await this.replaceBossMessages([]);
250
+ bossStore.setBossInputTokens(0);
251
+ // Mark the post-construction message count (just system) as persisted so
252
+ // we don't try to write it.
253
+ this.lastPersistedIndex = this.bossAgent.getMessages().length;
254
+ }
255
+ /** Alias kept for the existing /clear path which used "reset" terminology. */
256
+ async resetConversation() {
257
+ return this.newSession();
258
+ }
259
+ async run() {
260
+ this.running = true;
261
+ while (this.running) {
262
+ const event = await this.queue.next();
263
+ if (!this.running)
264
+ break;
265
+ if (event.kind === "user_message") {
266
+ this.pendingUserMessages = Math.max(0, this.pendingUserMessages - 1);
267
+ bossStore.setPendingMessages(this.pendingUserMessages);
268
+ }
269
+ if (event.kind === "worker_turn_complete") {
270
+ this.lastSummaries.set(event.summary.project, event.summary);
271
+ }
272
+ // Auto-compact when over 80% of context — mirrors AgentSession.runLoop.
273
+ // Workers handle their own compaction independently (via AgentSession).
274
+ await this.runCompaction(false);
275
+ const text = formatEventForBoss(event);
276
+ bossStore.startStreaming();
277
+ // Fresh AbortController for this turn so ESC can cancel just this call.
278
+ this.turnAc = new AbortController();
279
+ this.bossAgent.setSignal(this.turnAc.signal);
280
+ try {
281
+ const stream = this.bossAgent.prompt(text);
282
+ for await (const e of stream) {
283
+ switch (e.type) {
284
+ case "text_delta":
285
+ bossStore.appendStreamText(e.text);
286
+ break;
287
+ case "thinking_delta":
288
+ bossStore.appendStreamThinking(e.text);
289
+ break;
290
+ case "tool_call_start":
291
+ // Flush any preceding text so chronological order is preserved
292
+ // in scrollback (text → tool → text → tool, not text-block then tool-block).
293
+ bossStore.flushPendingText();
294
+ bossStore.startTool(e.toolCallId, e.name, e.args);
295
+ bossStore.setActivityPhase("tools");
296
+ break;
297
+ case "tool_call_end":
298
+ bossStore.endTool(e.toolCallId, e.isError, e.durationMs, e.result, e.details);
299
+ break;
300
+ case "turn_end":
301
+ // Latest turn's input tokens IS the current context size (each turn
302
+ // re-sends the whole conversation), so just track the most recent.
303
+ if (e.usage?.inputTokens != null) {
304
+ bossStore.setBossInputTokens(e.usage.inputTokens);
305
+ }
306
+ // Flush trailing text from this turn. Subsequent turns may add more.
307
+ bossStore.flushPendingText();
308
+ break;
309
+ case "retry":
310
+ if (!e.silent) {
311
+ bossStore.setRetryInfo({
312
+ reason: e.reason,
313
+ attempt: e.attempt,
314
+ maxAttempts: e.maxAttempts,
315
+ delayMs: e.delayMs,
316
+ });
317
+ }
318
+ break;
319
+ case "error":
320
+ bossStore.appendInfo(formatProviderError(e.error.message), "error");
321
+ break;
322
+ default:
323
+ break;
324
+ }
325
+ }
326
+ }
327
+ catch (err) {
328
+ if (isAbortError(err)) {
329
+ // Mirror ggcoder's onAborted: convert any in-flight tools to
330
+ // "Stopped." entries so the user sees the same visual feedback.
331
+ bossStore.interruptStreaming();
332
+ if (!this.running) {
333
+ bossStore.finishStreaming();
334
+ return;
335
+ }
336
+ bossStore.appendInfo("Interrupted by user.", "warning");
337
+ bossStore.finishStreaming();
338
+ await this.persistNewMessages();
339
+ continue;
340
+ }
341
+ const message = err instanceof Error ? err.message : String(err);
342
+ bossStore.appendInfo(formatProviderError(message), "error");
343
+ }
344
+ bossStore.finishStreaming();
345
+ await this.persistNewMessages();
346
+ }
347
+ }
348
+ async dispose() {
349
+ this.running = false;
350
+ this.ac.abort();
351
+ // Wake the queue if it's blocked on next() so the run loop can exit.
352
+ this.queue.push({
353
+ kind: "user_message",
354
+ text: "[shutdown]",
355
+ timestamp: new Date().toISOString(),
356
+ });
357
+ await Promise.all([...this.workers.values()].map((w) => w.dispose()));
358
+ }
359
+ }
360
+ function formatEventForBoss(event) {
361
+ if (event.kind === "user_message") {
362
+ return event.text;
363
+ }
364
+ if (event.kind === "worker_turn_complete") {
365
+ const s = event.summary;
366
+ const tools = s.toolsUsed.length > 0
367
+ ? s.toolsUsed.map((t) => `${t.ok ? "✓" : "✗"}${t.name}`).join(", ")
368
+ : "(none)";
369
+ return `[event:worker_turn_complete] project="${s.project}" turn=${s.turnIndex} timestamp=${s.timestamp}
370
+ tools_used: ${tools}
371
+ final_text:
372
+ ${s.finalText || "(empty)"}`;
373
+ }
374
+ return `[event:worker_error] project="${event.project}" timestamp=${event.timestamp}
375
+ ${event.message}`;
376
+ }
377
+ /**
378
+ * Map raw provider error text to a human-friendly hint. Mirrors ggcoder's
379
+ * pattern in App.tsx so users see the same diagnostic phrasing.
380
+ */
381
+ function formatProviderError(message) {
382
+ const lower = message.toLowerCase();
383
+ if (lower.includes("overloaded") || lower.includes("engine_overloaded")) {
384
+ return `${message}\nHint: provider is under heavy load — try again in a moment.`;
385
+ }
386
+ if (lower.includes("insufficient balance") ||
387
+ lower.includes("quota exceeded") ||
388
+ lower.includes("recharge")) {
389
+ return `${message}\nHint: billing or quota issue — check your account balance.`;
390
+ }
391
+ if (lower.includes("rate limit") ||
392
+ lower.includes("too many requests") ||
393
+ lower.includes("429")) {
394
+ return `${message}\nHint: provider rate limit — wait a moment before retrying.`;
395
+ }
396
+ if (lower.includes("timeout") || lower.includes("timed out")) {
397
+ return `${message}\nHint: provider timed out — their servers may be slow.`;
398
+ }
399
+ if (lower.includes("does not recognize the requested model") ||
400
+ (lower.includes("model") && (lower.includes("not exist") || lower.includes("not found")))) {
401
+ return `${message}\nHint: use /model to switch, or check that your account has access.`;
402
+ }
403
+ return message;
404
+ }
405
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { Message } from "@kenkaiiii/gg-ai";
2
+ export interface BossSessionInfo {
3
+ id: string;
4
+ path: string;
5
+ createdAt: number;
6
+ lastModified: number;
7
+ messageCount: number;
8
+ /** First user-message text — useful as a session title. */
9
+ firstUserMessage?: string;
10
+ }
11
+ export declare function ensureSessionsDir(): Promise<string>;
12
+ export declare function createSession(): Promise<{
13
+ id: string;
14
+ filePath: string;
15
+ }>;
16
+ export declare function appendMessages(filePath: string, msgs: Message[]): Promise<void>;
17
+ export declare function loadSession(filePath: string): Promise<Message[]>;
18
+ export declare function listSessions(): Promise<BossSessionInfo[]>;
19
+ export declare function getMostRecent(): Promise<BossSessionInfo | null>;
20
+ export declare function getSessionById(id: string): Promise<BossSessionInfo | null>;
21
+ //# sourceMappingURL=sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAqBhD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAIzD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAO/E;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAIrF;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAgBtE;AAoCD,wBAAsB,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAiB/D;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAGrE;AAED,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAGhF"}
@@ -0,0 +1,122 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import crypto from "node:crypto";
4
+ import { getAppPaths } from "@kenkaiiii/ggcoder";
5
+ /**
6
+ * Lightweight per-session log for the boss orchestrator. Each session is one
7
+ * `<id>.jsonl` file under `~/.gg/boss/sessions/`, append-only, one Message per
8
+ * line. Mirrors how ggcoder/AgentSession persists conversations — but kept
9
+ * simple (no DAG / branches / project encoding) since the boss only ever has
10
+ * one in-flight conversation per process.
11
+ */
12
+ const BOSS_SUBDIR = "boss";
13
+ const SESSIONS_SUBDIR = "sessions";
14
+ function getBossDir() {
15
+ return path.join(getAppPaths().agentDir, BOSS_SUBDIR);
16
+ }
17
+ function getSessionsDir() {
18
+ return path.join(getBossDir(), SESSIONS_SUBDIR);
19
+ }
20
+ export async function ensureSessionsDir() {
21
+ const dir = getSessionsDir();
22
+ await fs.mkdir(dir, { recursive: true, mode: 0o700 });
23
+ return dir;
24
+ }
25
+ export async function createSession() {
26
+ await ensureSessionsDir();
27
+ // Time-prefixed id keeps sessions naturally chronological in `ls`.
28
+ const id = `${Date.now()}-${crypto.randomBytes(4).toString("hex")}`;
29
+ const filePath = path.join(getSessionsDir(), `${id}.jsonl`);
30
+ await fs.writeFile(filePath, "", "utf-8");
31
+ return { id, filePath };
32
+ }
33
+ export async function appendMessages(filePath, msgs) {
34
+ if (msgs.length === 0)
35
+ return;
36
+ const lines = msgs.map((m) => JSON.stringify(m)).join("\n") + "\n";
37
+ await fs.appendFile(filePath, lines, "utf-8");
38
+ }
39
+ export async function loadSession(filePath) {
40
+ try {
41
+ const content = await fs.readFile(filePath, "utf-8");
42
+ const lines = content.split("\n").filter((l) => l.length > 0);
43
+ const messages = [];
44
+ for (const line of lines) {
45
+ try {
46
+ messages.push(JSON.parse(line));
47
+ }
48
+ catch {
49
+ // Skip corrupt lines rather than failing the whole resume.
50
+ }
51
+ }
52
+ return messages;
53
+ }
54
+ catch {
55
+ return [];
56
+ }
57
+ }
58
+ async function inspectSession(filePath, id) {
59
+ try {
60
+ const stat = await fs.stat(filePath);
61
+ const content = await fs.readFile(filePath, "utf-8");
62
+ const lines = content.split("\n").filter((l) => l.length > 0);
63
+ let firstUserMessage;
64
+ for (const line of lines) {
65
+ try {
66
+ const msg = JSON.parse(line);
67
+ if (msg.role === "user") {
68
+ const text = typeof msg.content === "string" ? msg.content : "";
69
+ if (text) {
70
+ const cleaned = text.replace(/^\[scope:[^\]]+\]\s*/, "");
71
+ firstUserMessage = cleaned.slice(0, 80);
72
+ break;
73
+ }
74
+ }
75
+ }
76
+ catch {
77
+ // skip
78
+ }
79
+ }
80
+ return {
81
+ id,
82
+ path: filePath,
83
+ createdAt: stat.birthtimeMs || stat.ctimeMs,
84
+ lastModified: stat.mtimeMs,
85
+ messageCount: lines.length,
86
+ firstUserMessage,
87
+ };
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ }
93
+ export async function listSessions() {
94
+ await ensureSessionsDir();
95
+ let entries;
96
+ try {
97
+ entries = await fs.readdir(getSessionsDir());
98
+ }
99
+ catch {
100
+ return [];
101
+ }
102
+ const infos = [];
103
+ for (const name of entries) {
104
+ if (!name.endsWith(".jsonl"))
105
+ continue;
106
+ const id = name.replace(/\.jsonl$/, "");
107
+ const info = await inspectSession(path.join(getSessionsDir(), name), id);
108
+ if (info)
109
+ infos.push(info);
110
+ }
111
+ infos.sort((a, b) => b.lastModified - a.lastModified);
112
+ return infos;
113
+ }
114
+ export async function getMostRecent() {
115
+ const all = await listSessions();
116
+ return all[0] ?? null;
117
+ }
118
+ export async function getSessionById(id) {
119
+ const filePath = path.join(getSessionsDir(), `${id}.jsonl`);
120
+ return inspectSession(filePath, id);
121
+ }
122
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { SlashCommandInfo } from "@kenkaiiii/ggcoder/ui";
2
+ /**
3
+ * Slash commands the boss CLI recognizes. Shape matches ggcoder's
4
+ * SlashCommandInfo so the existing SlashCommandMenu in InputArea renders them.
5
+ *
6
+ * The actual handlers live in BossApp's handleSubmit — we just declare the
7
+ * surface here so the menu is in one place.
8
+ */
9
+ export declare const BOSS_SLASH_COMMANDS: SlashCommandInfo[];
10
+ export declare function isSlashCommand(value: string): boolean;
11
+ export interface ParsedSlashCommand {
12
+ name: string;
13
+ args: string;
14
+ }
15
+ export declare function parseSlash(value: string): ParsedSlashCommand | null;
16
+ /** Resolve aliases to the canonical command name. */
17
+ export declare function canonicalName(name: string): string | null;
18
+ export declare function buildHelpText(): string;
19
+ //# sourceMappingURL=slash-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slash-commands.d.ts","sourceRoot":"","sources":["../src/slash-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,gBAAgB,EASjD,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAOnE;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMzD;AAED,wBAAgB,aAAa,IAAI,MAAM,CAYtC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Slash commands the boss CLI recognizes. Shape matches ggcoder's
3
+ * SlashCommandInfo so the existing SlashCommandMenu in InputArea renders them.
4
+ *
5
+ * The actual handlers live in BossApp's handleSubmit — we just declare the
6
+ * surface here so the menu is in one place.
7
+ */
8
+ export const BOSS_SLASH_COMMANDS = [
9
+ { name: "help", aliases: ["?"], description: "Show available commands" },
10
+ { name: "model-boss", aliases: [], description: "Switch the orchestrator's model" },
11
+ { name: "model-workers", aliases: [], description: "Switch every worker's model" },
12
+ { name: "compact", aliases: [], description: "Compact the boss's context now" },
13
+ { name: "new", aliases: ["n"], description: "Start a fresh boss session" },
14
+ { name: "clear", aliases: [], description: "Clear chat history (workers untouched)" },
15
+ { name: "workers", aliases: ["w"], description: "List linked workers and their status" },
16
+ { name: "quit", aliases: ["q", "exit"], description: "Exit gg-boss" },
17
+ ];
18
+ export function isSlashCommand(value) {
19
+ return value.startsWith("/") && !value.startsWith("//");
20
+ }
21
+ export function parseSlash(value) {
22
+ if (!isSlashCommand(value))
23
+ return null;
24
+ const rest = value.slice(1).trim();
25
+ if (!rest)
26
+ return null;
27
+ const space = rest.indexOf(" ");
28
+ if (space === -1)
29
+ return { name: rest.toLowerCase(), args: "" };
30
+ return { name: rest.slice(0, space).toLowerCase(), args: rest.slice(space + 1).trim() };
31
+ }
32
+ /** Resolve aliases to the canonical command name. */
33
+ export function canonicalName(name) {
34
+ for (const cmd of BOSS_SLASH_COMMANDS) {
35
+ if (cmd.name === name)
36
+ return cmd.name;
37
+ if (cmd.aliases.includes(name))
38
+ return cmd.name;
39
+ }
40
+ return null;
41
+ }
42
+ export function buildHelpText() {
43
+ const lines = ["**gg-boss commands**", ""];
44
+ for (const cmd of BOSS_SLASH_COMMANDS) {
45
+ const aliases = cmd.aliases.length > 0 ? ` (${cmd.aliases.map((a) => "/" + a).join(", ")})` : "";
46
+ lines.push(`- \`/${cmd.name}\`${aliases} — ${cmd.description}`);
47
+ }
48
+ lines.push("");
49
+ lines.push("**Keys**");
50
+ lines.push("- `Esc` — interrupt the boss while it's running");
51
+ lines.push("- `Ctrl+C` (twice) — exit");
52
+ return lines.join("\n");
53
+ }
54
+ //# sourceMappingURL=slash-commands.js.map