@kenkaiiii/gg-boss 4.10.1 → 4.10.2

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.
package/dist/cli.js CHANGED
@@ -32,6 +32,7 @@ import {
32
32
  color,
33
33
  createAutoUpdater,
34
34
  dim,
35
+ discoverProjects,
35
36
  formatHistoryWrite,
36
37
  getAppPaths,
37
38
  getBossState,
@@ -76,7 +77,7 @@ import {
76
77
  use_input_default,
77
78
  use_stdout_default,
78
79
  wrapPlain
79
- } from "./chunk-EV37X3XL.js";
80
+ } from "./chunk-UH3DA72U.js";
80
81
  import "./chunk-JEGMYLRS.js";
81
82
  import {
82
83
  source_default
@@ -88,7 +89,7 @@ import {
88
89
 
89
90
  // src/cli.ts
90
91
  init_esm_shims();
91
- import path5 from "path";
92
+ import path4 from "path";
92
93
 
93
94
  // src/links.ts
94
95
  init_esm_shims();
@@ -118,246 +119,6 @@ var import_react2 = __toESM(require_react(), 1);
118
119
 
119
120
  // src/discover.ts
120
121
  init_esm_shims();
121
- import fs2 from "fs/promises";
122
- import { createReadStream } from "fs";
123
- import readline from "readline";
124
- import os from "os";
125
- import path2 from "path";
126
- async function discoverProjects() {
127
- const [gg, cc, cx] = await Promise.all([
128
- discoverGgcoderProjects(),
129
- discoverClaudeProjects(),
130
- discoverCodexProjects()
131
- ]);
132
- const byPath = /* @__PURE__ */ new Map();
133
- for (const p of [...gg, ...cc, ...cx]) {
134
- const existing = byPath.get(p.path);
135
- if (!existing) {
136
- byPath.set(p.path, p);
137
- continue;
138
- }
139
- byPath.set(p.path, {
140
- name: existing.name,
141
- path: existing.path,
142
- lastActiveMs: Math.max(existing.lastActiveMs, p.lastActiveMs),
143
- lastActiveDisplay: "",
144
- // recomputed below
145
- sources: mergeSources(existing.sources, p.sources)
146
- });
147
- }
148
- const merged = Array.from(byPath.values()).map((p) => ({
149
- ...p,
150
- lastActiveDisplay: formatRelativeTime(p.lastActiveMs)
151
- }));
152
- merged.sort((a, b) => b.lastActiveMs - a.lastActiveMs);
153
- return merged;
154
- }
155
- var SOURCE_ORDER = {
156
- ggcoder: 0,
157
- "claude-code": 1,
158
- codex: 2
159
- };
160
- function mergeSources(a, b) {
161
- const set = /* @__PURE__ */ new Set([...a, ...b]);
162
- return Array.from(set).sort((x, y) => SOURCE_ORDER[x] - SOURCE_ORDER[y]);
163
- }
164
- async function discoverGgcoderProjects() {
165
- const sessionsDir = getAppPaths().sessionsDir;
166
- let entries;
167
- try {
168
- entries = await fs2.readdir(sessionsDir);
169
- } catch {
170
- return [];
171
- }
172
- const results = [];
173
- for (const entry of entries) {
174
- const dir = path2.join(sessionsDir, entry);
175
- const mtime = await maxJsonlMtime(dir);
176
- if (mtime === null) continue;
177
- const decoded = "/" + entry.replace(/_/g, "/");
178
- if (!await isDirectory(decoded)) continue;
179
- results.push({
180
- name: path2.basename(decoded),
181
- path: decoded,
182
- lastActiveMs: mtime,
183
- lastActiveDisplay: formatRelativeTime(mtime),
184
- sources: ["ggcoder"]
185
- });
186
- }
187
- return results;
188
- }
189
- async function discoverClaudeProjects() {
190
- const projectsDir = path2.join(os.homedir(), ".claude", "projects");
191
- let entries;
192
- try {
193
- entries = await fs2.readdir(projectsDir);
194
- } catch {
195
- return [];
196
- }
197
- const results = await Promise.all(
198
- entries.map(async (entry) => {
199
- const dir = path2.join(projectsDir, entry);
200
- const mtime = await maxJsonlMtime(dir);
201
- if (mtime === null) return null;
202
- const cwd = await readFirstFromJsonlDir(dir, claudeCwdExtractor) ?? fallbackDashDecode(entry);
203
- if (!cwd) return null;
204
- if (!await isDirectory(cwd)) return null;
205
- return {
206
- name: path2.basename(cwd),
207
- path: cwd,
208
- lastActiveMs: mtime,
209
- lastActiveDisplay: formatRelativeTime(mtime),
210
- sources: ["claude-code"]
211
- };
212
- })
213
- );
214
- return results.filter((p) => p !== null);
215
- }
216
- async function discoverCodexProjects() {
217
- const sessionsDir = path2.join(os.homedir(), ".codex", "sessions");
218
- if (!await isDirectory(sessionsDir)) return [];
219
- const files = await collectJsonlFiles(sessionsDir, 4);
220
- if (files.length === 0) return [];
221
- files.sort((a, b) => b.mtime - a.mtime);
222
- const byCwd = /* @__PURE__ */ new Map();
223
- for (const f of files) {
224
- const cwd = await readFirstFromFile(f.path, codexCwdExtractor);
225
- if (!cwd) continue;
226
- const prev = byCwd.get(cwd);
227
- if (prev === void 0 || f.mtime > prev) byCwd.set(cwd, f.mtime);
228
- }
229
- const results = [];
230
- for (const [cwd, mtime] of byCwd) {
231
- if (!await isDirectory(cwd)) continue;
232
- results.push({
233
- name: path2.basename(cwd),
234
- path: cwd,
235
- lastActiveMs: mtime,
236
- lastActiveDisplay: formatRelativeTime(mtime),
237
- sources: ["codex"]
238
- });
239
- }
240
- return results;
241
- }
242
- async function isDirectory(p) {
243
- try {
244
- const s = await fs2.stat(p);
245
- return s.isDirectory();
246
- } catch {
247
- return false;
248
- }
249
- }
250
- async function maxJsonlMtime(dir) {
251
- if (!await isDirectory(dir)) return null;
252
- const files = await collectJsonlFiles(dir, 2);
253
- if (files.length === 0) return null;
254
- let max = 0;
255
- for (const f of files) if (f.mtime > max) max = f.mtime;
256
- return max > 0 ? max : null;
257
- }
258
- async function collectJsonlFiles(dir, maxDepth) {
259
- const out = [];
260
- await walk(dir, 0);
261
- return out;
262
- async function walk(current, depth) {
263
- let entries;
264
- try {
265
- entries = await fs2.readdir(current, { withFileTypes: true });
266
- } catch {
267
- return;
268
- }
269
- for (const e of entries) {
270
- const full = path2.join(current, e.name);
271
- if (e.isFile() && e.name.endsWith(".jsonl")) {
272
- try {
273
- const s = await fs2.stat(full);
274
- out.push({ path: full, mtime: s.mtimeMs });
275
- } catch {
276
- }
277
- } else if (e.isDirectory() && depth < maxDepth) {
278
- await walk(full, depth + 1);
279
- }
280
- }
281
- }
282
- }
283
- var claudeCwdExtractor = (line) => {
284
- try {
285
- const parsed = JSON.parse(line);
286
- if (typeof parsed.cwd === "string" && parsed.cwd.startsWith("/")) return parsed.cwd;
287
- } catch {
288
- }
289
- return null;
290
- };
291
- var CODEX_CWD_RE = /<cwd>([^<]+)<\/cwd>/;
292
- var codexCwdExtractor = (line) => {
293
- try {
294
- const parsed = JSON.parse(line);
295
- const cwd = parsed.payload?.cwd;
296
- if (typeof cwd === "string" && cwd.startsWith("/")) return cwd;
297
- } catch {
298
- }
299
- const m = CODEX_CWD_RE.exec(line);
300
- if (m && m[1] && m[1].startsWith("/")) return m[1];
301
- return null;
302
- };
303
- async function readFirstFromJsonlDir(dir, extractor) {
304
- const files = await collectJsonlFiles(dir, 2);
305
- if (files.length === 0) return null;
306
- files.sort((a, b) => b.mtime - a.mtime);
307
- for (const f of files) {
308
- const v = await readFirstFromFile(f.path, extractor);
309
- if (v) return v;
310
- }
311
- return null;
312
- }
313
- async function readFirstFromFile(file, extractor) {
314
- return new Promise((resolve) => {
315
- const stream = createReadStream(file, { encoding: "utf-8" });
316
- const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
317
- let lines = 0;
318
- let done = false;
319
- const MAX_LINES = 200;
320
- const finish = (value) => {
321
- if (done) return;
322
- done = true;
323
- resolve(value);
324
- rl.close();
325
- stream.destroy();
326
- };
327
- rl.on("line", (line) => {
328
- if (done) return;
329
- lines++;
330
- if (lines > MAX_LINES) {
331
- finish(null);
332
- return;
333
- }
334
- const v = extractor(line);
335
- if (v) finish(v);
336
- });
337
- rl.on("close", () => finish(null));
338
- rl.on("error", () => finish(null));
339
- stream.on("error", () => finish(null));
340
- });
341
- }
342
- function fallbackDashDecode(entry) {
343
- if (!entry.startsWith("-")) return null;
344
- return "/" + entry.slice(1).replace(/-/g, "/");
345
- }
346
- function formatRelativeTime(ms) {
347
- if (ms === 0) return "\u2014";
348
- const diff = Date.now() - ms;
349
- if (diff < 6e4) return "just now";
350
- const min = 6e4;
351
- const hour = 60 * min;
352
- const day = 24 * hour;
353
- const week = 7 * day;
354
- const month = 30 * day;
355
- if (diff < hour) return `${Math.floor(diff / min)}m ago`;
356
- if (diff < day) return `${Math.floor(diff / hour)}h ago`;
357
- if (diff < week) return `${Math.floor(diff / day)}d ago`;
358
- if (diff < month) return `${Math.floor(diff / week)}w ago`;
359
- return `${Math.floor(diff / month)}mo ago`;
360
- }
361
122
 
362
123
  // src/banner.tsx
363
124
  init_esm_shims();
@@ -369,7 +130,7 @@ init_esm_shims();
369
130
  // package.json
370
131
  var package_default = {
371
132
  name: "@kenkaiiii/gg-boss",
372
- version: "4.10.1",
133
+ version: "4.10.2",
373
134
  type: "module",
374
135
  description: "Orchestrator agent that drives multiple ggcoder sessions across projects from a single chat",
375
136
  license: "MIT",
@@ -649,7 +410,7 @@ async function runLinkCommand() {
649
410
  process.stdout.write(source_default.hex(COLORS.textDim)("\nCancelled. No changes saved.\n"));
650
411
  return;
651
412
  }
652
- const linked = result.selected.map((path6) => projects.find((p) => p.path === path6)).filter((p) => Boolean(p)).map((p) => ({ name: p.name, cwd: p.path }));
413
+ const linked = result.selected.map((path5) => projects.find((p) => p.path === path5)).filter((p) => Boolean(p)).map((p) => ({ name: p.name, cwd: p.path }));
653
414
  await saveLinks({ projects: linked });
654
415
  process.stdout.write("\n");
655
416
  if (linked.length === 0) {
@@ -676,14 +437,14 @@ async function runLinkCommand() {
676
437
 
677
438
  // src/serve-mode.ts
678
439
  init_esm_shims();
679
- import path3 from "path";
680
- import fs3 from "fs/promises";
440
+ import path2 from "path";
441
+ import fs2 from "fs/promises";
681
442
  function getTelegramConfigPath() {
682
- return path3.join(getAppPaths().agentDir, "boss", "telegram.json");
443
+ return path2.join(getAppPaths().agentDir, "boss", "telegram.json");
683
444
  }
684
445
  async function loadBossTelegramConfig() {
685
446
  try {
686
- const raw = await fs3.readFile(getTelegramConfigPath(), "utf-8");
447
+ const raw = await fs2.readFile(getTelegramConfigPath(), "utf-8");
687
448
  const data = JSON.parse(raw);
688
449
  if (data.botToken && data.userId) return data;
689
450
  return null;
@@ -693,8 +454,8 @@ async function loadBossTelegramConfig() {
693
454
  }
694
455
  async function saveBossTelegramConfig(config) {
695
456
  const file = getTelegramConfigPath();
696
- await fs3.mkdir(path3.dirname(file), { recursive: true });
697
- await fs3.writeFile(file, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
457
+ await fs2.mkdir(path2.dirname(file), { recursive: true });
458
+ await fs2.writeFile(file, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
698
459
  }
699
460
  function formatItemForTelegram(item) {
700
461
  switch (item.kind) {
@@ -1146,7 +907,7 @@ function printBanner(opts) {
1146
907
 
1147
908
  // src/telegram-setup.ts
1148
909
  init_esm_shims();
1149
- import readline2 from "readline/promises";
910
+ import readline from "readline/promises";
1150
911
  async function runBossTelegramSetup() {
1151
912
  process.stdout.write("\x1B[2J\x1B[H");
1152
913
  printSetupBanner();
@@ -1160,7 +921,7 @@ async function runBossTelegramSetup() {
1160
921
  `)
1161
922
  );
1162
923
  }
1163
- const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
924
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1164
925
  try {
1165
926
  console.log(
1166
927
  source_default.hex(COLORS.accent)(" Step 1: Bot Token\n") + source_default.hex(COLORS.textDim)(" 1. Open BotFather: ") + source_default.hex(COLORS.primary).underline("https://t.me/BotFather") + "\n" + source_default.hex(COLORS.textDim)(" 2. Send /newbot and follow the prompts\n") + source_default.hex(COLORS.textDim)(" 3. Copy the bot token\n")
@@ -3001,11 +2762,11 @@ function renderRoundNoticeBox(lines, context, borderColor) {
3001
2762
 
3002
2763
  // src/auto-update.ts
3003
2764
  init_esm_shims();
3004
- import path4 from "path";
3005
- import os2 from "os";
2765
+ import path3 from "path";
2766
+ import os from "os";
3006
2767
  var updater = createAutoUpdater({
3007
2768
  packageName: "@kenkaiiii/gg-boss",
3008
- stateFilePath: () => path4.join(os2.homedir(), ".gg", "boss", "update-state.json"),
2769
+ stateFilePath: () => path3.join(os.homedir(), ".gg", "boss", "update-state.json"),
3009
2770
  periodicMessage: ({ currentVersion, latestVersion, updateCommand }) => `Ken just pushed a fresh update \u2014 ${currentVersion} \u2192 ${latestVersion}! Restart ggboss to grab it (or run ${updateCommand} if you can't wait).`
3010
2771
  });
3011
2772
  var checkAndAutoUpdate = updater.checkAndAutoUpdate;
@@ -3558,11 +3319,11 @@ function parseProjectSpec(raw) {
3558
3319
  const eq = raw.indexOf("=");
3559
3320
  if (eq > 0) {
3560
3321
  const name = raw.slice(0, eq);
3561
- const cwd2 = path5.resolve(raw.slice(eq + 1));
3322
+ const cwd2 = path4.resolve(raw.slice(eq + 1));
3562
3323
  return { name, cwd: cwd2 };
3563
3324
  }
3564
- const cwd = path5.resolve(raw);
3565
- return { name: path5.basename(cwd), cwd };
3325
+ const cwd = path4.resolve(raw);
3326
+ return { name: path4.basename(cwd), cwd };
3566
3327
  }
3567
3328
  function parseArgs(argv) {
3568
3329
  const args = {