@8gi-foundation/8gent-code 0.20.15 → 0.20.17

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
@@ -41468,8 +41468,6 @@ var init_allowlist = __esm(() => {
41468
41468
  "node",
41469
41469
  "npm",
41470
41470
  "npx",
41471
- "pnpm",
41472
- "yarn",
41473
41471
  "deno",
41474
41472
  "python",
41475
41473
  "python3",
@@ -41477,9 +41475,6 @@ var init_allowlist = __esm(() => {
41477
41475
  "pip3",
41478
41476
  "uv",
41479
41477
  "git",
41480
- "go",
41481
- "cargo",
41482
- "rustc",
41483
41478
  "tsc",
41484
41479
  "gh",
41485
41480
  "docker",
@@ -41504,20 +41499,18 @@ var init_allowlist = __esm(() => {
41504
41499
  "biome",
41505
41500
  "eslint",
41506
41501
  "prettier",
41507
- "vite"
41502
+ "vite",
41503
+ "8gent"
41508
41504
  ]);
41509
41505
  SHORT_VERSION = {
41510
41506
  node: "-v",
41511
41507
  bun: "-v",
41512
41508
  npm: "-v",
41513
- pnpm: "-v",
41514
- yarn: "-v",
41515
41509
  deno: "-V",
41516
41510
  python: "-V",
41517
41511
  python3: "-V",
41518
41512
  ffmpeg: "-version",
41519
- ffprobe: "-version",
41520
- go: "version"
41513
+ ffprobe: "-version"
41521
41514
  };
41522
41515
  SECRET_ARG = /(^|\/)\.env(\.[\w.-]+)?$|(^|\/)\.env\b|id_rsa|id_ed25519|id_ecdsa|(^|\/)\.ssh(\/|$)|\.aws\/|credentials|\.netrc|\.npmrc|\.git-credentials|keychain|\.pem$|\.key$|\.p12$/;
41523
41516
  REDIR_RE2 = /(?<![<>&\d])(\d?|&)(>>?|<)(\|?)\s*(&\d+|[^\s;|&<>()]+)/g;
@@ -46102,8 +46095,31 @@ function emptyReplyStall(toolCalls) {
46102
46095
  function isEmptyReplyStall(line) {
46103
46096
  return line.startsWith(EMPTY_REPLY_STALL_PREFIX);
46104
46097
  }
46105
- function emptyReplyNote(toolCalls) {
46106
- return `[harness] No reply: ${emptyReplyStall(toolCalls)}.`;
46098
+ function refusedCalls(log, max = 3) {
46099
+ const out = [];
46100
+ let total = 0;
46101
+ for (const e of log) {
46102
+ const m = /^\[[^\]]*\b(?:BLOCKED|DENIED)\b[^\]]*\]\s*([^\n]*)/.exec((e.result ?? "").trimStart());
46103
+ if (!m)
46104
+ continue;
46105
+ total++;
46106
+ if (out.length >= max)
46107
+ continue;
46108
+ const a = e.args;
46109
+ const first = typeof a?.command === "string" ? a.command.trim().split(/\s+/)[0] ?? "" : "";
46110
+ const bin = /^[A-Za-z][\w.+-]{0,40}$/.test(first) ? ` ${first}` : "";
46111
+ const why = /declin/i.test(m[1]) ? "declined" : "blocked by policy";
46112
+ out.push(`${e.name}${bin}: ${why}`);
46113
+ }
46114
+ return { total, shown: out };
46115
+ }
46116
+ function emptyReplyNote(toolCalls, log = []) {
46117
+ const base = `[harness] No reply: ${emptyReplyStall(toolCalls)}.`;
46118
+ const { total, shown } = refusedCalls(log);
46119
+ if (total === 0)
46120
+ return base;
46121
+ const more = total > shown.length ? ` (and ${total - shown.length} more)` : "";
46122
+ return `${base} ${total} of the calls were refused, so they did not run: ${shown.join("; ")}${more}.`;
46107
46123
  }
46108
46124
  function isEmptyReplyNote(reply) {
46109
46125
  return reply.startsWith("[harness] No reply:");
@@ -46196,7 +46212,7 @@ ${summary}`;
46196
46212
  if (unverified.length === 0)
46197
46213
  return { content, rounds, toolLog, unverified: [] };
46198
46214
  const notes = [
46199
- empty ? emptyReplyNote(toolLog.length) : content.trimEnd(),
46215
+ empty ? emptyReplyNote(toolLog.length, toolLog) : content.trimEnd(),
46200
46216
  unfulfilled.length > 0 ? formatHarnessNote(unfulfilled) : ""
46201
46217
  ].filter((n) => n.trim() !== "");
46202
46218
  return { content: notes.join(`
@@ -536850,7 +536866,7 @@ onboarding preferences skip animations adhd quarantine toolshed skills design ev
536850
536866
  resume history continue compact chat agent github debug music dj pet export fork rewind branch cron deploy
536851
536867
  vercel telegram router rename spawn settings quiet term create-app hands eyes handeyes goal subgoal build
536852
536868
  notes ideas btw questions projects terminal reload exit
536853
- copy hotkeys tree import update route privacy consult bug me allow-read`.split(/\s+/));
536869
+ copy hotkeys tree import update route privacy consult bug me allow-read mode`.split(/\s+/));
536854
536870
  });
536855
536871
 
536856
536872
  // packages/extensions/prompts.ts
@@ -545345,7 +545361,9 @@ function defaultSessionsDir2() {
545345
545361
 
545346
545362
  class SessionWriter {
545347
545363
  filePath;
545348
- fd;
545364
+ fd = -1;
545365
+ dev = -1;
545366
+ ino = -1;
545349
545367
  persist;
545350
545368
  seq = 0;
545351
545369
  sessionId;
@@ -545377,15 +545395,47 @@ class SessionWriter {
545377
545395
  fs76.mkdirSync(dir, { recursive: true });
545378
545396
  }
545379
545397
  this.filePath = path105.join(dir, `${sessionId}.jsonl`);
545380
- this.fd = fs76.openSync(this.filePath, "a");
545398
+ this.open();
545399
+ }
545400
+ open() {
545401
+ const c = fs76.constants;
545402
+ const fd = fs76.openSync(this.filePath, c.O_WRONLY | c.O_APPEND | c.O_CREAT | (c.O_NOFOLLOW ?? 0), 384);
545403
+ const st = fs76.fstatSync(fd);
545404
+ if (!st.isFile()) {
545405
+ fs76.closeSync(fd);
545406
+ throw new Error(`${this.filePath} is not a regular file`);
545407
+ }
545408
+ this.fd = fd;
545409
+ this.dev = st.dev;
545410
+ this.ino = st.ino;
545411
+ }
545412
+ fdIsOurs() {
545413
+ if (this.fd < 0)
545414
+ return false;
545415
+ try {
545416
+ const st = fs76.fstatSync(this.fd);
545417
+ return st.dev === this.dev && st.ino === this.ino;
545418
+ } catch {
545419
+ return false;
545420
+ }
545381
545421
  }
545382
545422
  write(entry) {
545383
545423
  if (!this.persist)
545384
545424
  return;
545385
545425
  const line = `${JSON.stringify(entry)}
545386
545426
  `;
545387
- fs76.writeSync(this.fd, line);
545427
+ try {
545428
+ if (!this.fdIsOurs())
545429
+ this.open();
545430
+ fs76.writeSync(this.fd, line);
545431
+ } catch (err) {
545432
+ this.fd = -1;
545433
+ this.skippedWrites++;
545434
+ this.lastWriteError = `session log not written: ${err instanceof Error ? err.message : String(err)}`;
545435
+ }
545388
545436
  }
545437
+ lastWriteError = null;
545438
+ skippedWrites = 0;
545389
545439
  nextSeq() {
545390
545440
  return this.seq++;
545391
545441
  }
@@ -545595,8 +545645,9 @@ class SessionWriter {
545595
545645
  reportId: reportId ?? null
545596
545646
  }
545597
545647
  });
545598
- if (this.persist)
545648
+ if (this.persist && this.fdIsOurs())
545599
545649
  fs76.closeSync(this.fd);
545650
+ this.fd = -1;
545600
545651
  }
545601
545652
  getFilePath() {
545602
545653
  return this.filePath;
@@ -545737,6 +545788,12 @@ var init_slash_commands = __esm(() => {
545737
545788
  description: "Enable infinite mode (autonomous until done)",
545738
545789
  usage: "/infinite [task]"
545739
545790
  },
545791
+ {
545792
+ name: "mode",
545793
+ aliases: [],
545794
+ description: "Set this tab's permission mode: plan, ask, guarded or infinite (same as Shift+Tab)",
545795
+ usage: "/mode <plan|ask|guarded|infinite>"
545796
+ },
545740
545797
  {
545741
545798
  name: "onboarding",
545742
545799
  aliases: ["onboard", "setup", "intro"],
@@ -549347,6 +549404,52 @@ var init_planning_gate = __esm(() => {
549347
549404
  PLANNING_KEYWORDS = /\b(build|create|implement|fix|refactor|add|setup|configure|migrate|convert|redesign|scaffold|deploy|integrate)\b/i;
549348
549405
  });
549349
549406
 
549407
+ // packages/eight/small-talk.ts
549408
+ function flatten(text) {
549409
+ return text.toLowerCase().replace(/^\[mode: [^\]]*\]\s*/, "").replace(/['\u2019]/g, "").replace(/[^a-z0-9 ]+/g, " ").replace(/\s+/g, " ").trim();
549410
+ }
549411
+ function isSmallTalk(text) {
549412
+ const flat = flatten(text);
549413
+ return flat.length > 0 && flat.length <= 40 && GREETING.test(flat);
549414
+ }
549415
+ function isGreeting(text) {
549416
+ return isSmallTalk(text) && !THANKS.test(flatten(text));
549417
+ }
549418
+ var CORE, GREETING, THANKS, SMALL_TALK_NOTE = "[SMALL TALK] The person said hello and asked for nothing. Reply in one or two plain sentences and ask what they want to work on. No tools this turn: do not look around, list files or describe their folders.";
549419
+ var init_small_talk = __esm(() => {
549420
+ CORE = [
549421
+ "h+i+",
549422
+ "h+e+y+",
549423
+ "h+e+l+o+",
549424
+ "hiya",
549425
+ "howdy",
549426
+ "y+o+",
549427
+ "sup",
549428
+ "wa+s+s?u+p+",
549429
+ "w?h?a+t?s? ?u+p+",
549430
+ "wh?a+t+s? go+d+",
549431
+ "good (?:morning|afternoon|evening|night)",
549432
+ "gm",
549433
+ "gn",
549434
+ "morning",
549435
+ "evening",
549436
+ "how are you(?: doing| today)?",
549437
+ "how are things",
549438
+ "hows it going",
549439
+ "how you doing",
549440
+ "you there",
549441
+ "anyone there",
549442
+ "ping",
549443
+ "thanks(?: a lot| so much)?",
549444
+ "thank you(?: so much)?",
549445
+ "thx",
549446
+ "ty",
549447
+ "cheers"
549448
+ ].join("|");
549449
+ GREETING = new RegExp(`^(?:(?:hi+|hey+|hello+|yo+|hiya|howdy) )?(?:${CORE})(?: (?:there|again|everyone|all|team|mate|man|bro|friend|8gent|eight))?$`);
549450
+ THANKS = /^(?:thanks|thank you|thx|ty|cheers)\b/;
549451
+ });
549452
+
549350
549453
  // packages/eight/verify-gate.ts
549351
549454
  function isVerifyGateEnabled(env = process.env) {
549352
549455
  const v = (env.EIGHT_VERIFY_GATE ?? "").trim().toLowerCase();
@@ -549389,6 +549492,412 @@ var init_verify_gate = __esm(() => {
549389
549492
  `);
549390
549493
  });
549391
549494
 
549495
+ // package.json
549496
+ var package_default;
549497
+ var init_package = __esm(() => {
549498
+ package_default = {
549499
+ name: "@8gi-foundation/8gent-code",
549500
+ version: "0.20.17",
549501
+ private: false,
549502
+ engines: {
549503
+ node: ">=22.5"
549504
+ },
549505
+ description: "Autonomous coding agent. Runs locally on Ollama. Zero API cost. Your code stays on your machine. Open source.",
549506
+ type: "module",
549507
+ bin: {
549508
+ "8": "./bin/8gent-run.js",
549509
+ "8gent": "./bin/8gent-run.js",
549510
+ "8gent-code": "./bin/8gent-run.js"
549511
+ },
549512
+ files: [
549513
+ "dist/cli.js",
549514
+ "dist/tui.js",
549515
+ "dist/pty-bridge.cjs",
549516
+ "dist/node/cli.js",
549517
+ "dist/node/tui.js",
549518
+ "dist/node/pty-bridge.cjs",
549519
+ "dist/skills",
549520
+ "dist/sounds",
549521
+ "bin/8gent-run.js",
549522
+ "bin/node-version.js",
549523
+ "bin/termux-exec.js",
549524
+ "packages/decide/calibration",
549525
+ "packages/daemon/VESSEL-CONTEXT.md",
549526
+ "bin/bunfig.empty.toml",
549527
+ "scripts/postinstall.js",
549528
+ "README.md",
549529
+ "CHANGELOG.md",
549530
+ "LICENSE"
549531
+ ],
549532
+ scripts: {
549533
+ start: "bun --config=bin/bunfig.empty.toml run packages/eight/index.ts",
549534
+ agent: "bun --config=bin/bunfig.empty.toml run packages/eight/index.ts",
549535
+ daemon: "bun --config=bin/bunfig.empty.toml run packages/daemon/index.ts",
549536
+ "daemon:local": "bun --config=bin/bunfig.empty.toml run packages/daemon/scripts/start-local.ts",
549537
+ tui: "bun --config=bin/bunfig.empty.toml run apps/tui/src/index.tsx",
549538
+ pet: "bash apps/lil-eight/build.sh && open 'apps/lil-eight/build/Lil Eight.app'",
549539
+ "pet:build": "bash apps/lil-eight/build.sh",
549540
+ "pet:open": "open 'apps/lil-eight/build/Lil Eight.app'",
549541
+ "pet:kill": "pkill -f LilEight",
549542
+ "pet:log": "tail -f ~/.8gent/lil-eight.log",
549543
+ "install-wizard": "bun --config=bin/bunfig.empty.toml run scripts/install-wizard.tsx",
549544
+ "install:apple-foundation": "bun --config=bin/bunfig.empty.toml run scripts/install-apple-foundation.ts",
549545
+ "build:eyes-bridge": "bash packages/eyes/native/build.sh",
549546
+ cli: "bun --config=bin/bunfig.empty.toml run bin/8gent.ts",
549547
+ dev: "next dev",
549548
+ build: "bun --config=bin/bunfig.empty.toml scripts/build-bundles.ts && bun --config=bin/bunfig.empty.toml scripts/build-node.ts && node scripts/build-finalize.js && bun --config=bin/bunfig.empty.toml scripts/check-bundle-versions.ts",
549549
+ "build:tui": "bun --config=bin/bunfig.empty.toml scripts/build-bundles.ts --tui && node scripts/build-finalize.js",
549550
+ "build:binaries": "bun --config=bin/bunfig.empty.toml run scripts/build-binaries.ts",
549551
+ "build:binaries:host": "bun --config=bin/bunfig.empty.toml run scripts/build-binaries.ts --host",
549552
+ "package:linux": "bash scripts/package-linux.sh",
549553
+ "package:windows": "pwsh scripts/package-windows.ps1",
549554
+ prepublishOnly: "npm run build",
549555
+ postinstall: "node scripts/postinstall.js",
549556
+ "preflight:native": "sh scripts/preflight-native-deps.sh",
549557
+ test: "bun test packages/ apps/ tests/preload-temp-dirs.test.ts",
549558
+ "test:benchmarks": "bun test benchmarks/",
549559
+ "test:security": "bun test tests/security",
549560
+ "test:models": "bun --config=bin/bunfig.empty.toml scripts/test-models.ts",
549561
+ "test:models:providers": "bun --config=bin/bunfig.empty.toml scripts/test-models.ts --providers",
549562
+ "cua:setup": "bun --config=bin/bunfig.empty.toml run packages/eight/scripts/cua-setup.ts",
549563
+ "cua:run": "bun --config=bin/bunfig.empty.toml run packages/eight/scripts/cua-run.ts",
549564
+ smoke: "bun --config=bin/bunfig.empty.toml scripts/smoke.ts",
549565
+ "smoke:fast": "bun --config=bin/bunfig.empty.toml scripts/smoke.ts --skip-network",
549566
+ "smoke:strict": "bun --config=bin/bunfig.empty.toml scripts/smoke.ts --strict",
549567
+ "smoke:pack": "bun --config=bin/bunfig.empty.toml scripts/pack-smoke.ts",
549568
+ "smoke:bare-install": "sh scripts/bare-install-smoke.sh",
549569
+ "verify:presets": "bun --config=bin/bunfig.empty.toml scripts/verify-presets.ts",
549570
+ "verify:presets:strict": "bun --config=bin/bunfig.empty.toml scripts/verify-presets.ts --strict",
549571
+ lint: "biome lint .",
549572
+ "lint:fix": "biome lint --write .",
549573
+ format: "biome format --write .",
549574
+ "format:check": "biome format .",
549575
+ "check:biome": "biome check .",
549576
+ "check:biome:fix": "biome check --write .",
549577
+ typecheck: "tsc --noEmit",
549578
+ "typecheck:tui": "tsc --noEmit -p apps/tui/tsconfig.json",
549579
+ "check:harness": "tsc --noEmit -p tsconfig.harness.json",
549580
+ benchmark: "bun --config=bin/bunfig.empty.toml run scripts/benchmark.ts",
549581
+ "benchmark:suite": "bun --config=bin/bunfig.empty.toml run benchmarks/runner.ts",
549582
+ "benchmark:category": "bun --config=bin/bunfig.empty.toml run benchmarks/runner.ts --category",
549583
+ "benchmark:single": "bun --config=bin/bunfig.empty.toml run benchmarks/runner.ts --bench",
549584
+ "benchmark:swebench": "bun --config=bin/bunfig.empty.toml run benchmarks/swebench/run.ts",
549585
+ "benchmark:v2": "bun --config=bin/bunfig.empty.toml run benchmarks/autoresearch/harness-v2.ts",
549586
+ "benchmark:gate": "bun --config=bin/bunfig.empty.toml run benchmarks/gate.ts",
549587
+ "benchmark:gate:update": "bun --config=bin/bunfig.empty.toml run benchmarks/gate.ts --update",
549588
+ "benchmark:loop": "bun --config=bin/bunfig.empty.toml run benchmarks/computer-use-bakeoff.ts",
549589
+ "benchmark:bakeoff": "bun --no-env-file --config=bin/bunfig.empty.toml run benchmarks/computer-use-bakeoff.ts",
549590
+ "benchmark:multi": "bun --no-env-file --config=bin/bunfig.empty.toml run benchmarks/autoresearch/multi-model-harness.ts",
549591
+ audit: "bun --no-env-file --config=bin/bunfig.empty.toml run packages/audit/cli.ts",
549592
+ demo: "bun --no-env-file --config=bin/bunfig.empty.toml run scripts/demo-savings.ts",
549593
+ "provision-tenant": "bun --no-env-file --config=bin/bunfig.empty.toml run scripts/provision-tenant.ts",
549594
+ harness: "bun --no-env-file --config=bin/bunfig.empty.toml run packages/harness-cli/index.ts",
549595
+ "harness:run": "bun --no-env-file --config=bin/bunfig.empty.toml run packages/harness-cli/index.ts run",
549596
+ "harness:sessions": "bun --no-env-file --config=bin/bunfig.empty.toml run packages/harness-cli/index.ts sessions",
549597
+ "harness:inspect": "bun --no-env-file --config=bin/bunfig.empty.toml run packages/harness-cli/index.ts inspect",
549598
+ "harness:doctor": "bun --no-env-file --config=bin/bunfig.empty.toml run packages/harness-cli/index.ts doctor",
549599
+ debug: "bun --no-env-file --config=bin/bunfig.empty.toml run bin/debug.ts",
549600
+ "preflight:parse": "node scripts/excluded-parse-check.mjs"
549601
+ },
549602
+ workspaces: [
549603
+ "apps/*",
549604
+ "packages/*"
549605
+ ],
549606
+ devDependencies: {
549607
+ "@ai-sdk/openai-compatible": "^2.0.35",
549608
+ "@biomejs/biome": "^1.5.0",
549609
+ "@changesets/cli": "^2.30.0",
549610
+ "@mozilla/readability": "^0.6.0",
549611
+ "@napi-rs/canvas": "^0.1.97",
549612
+ "@types/bun": "latest",
549613
+ "@types/jsdom": "^28.0.0",
549614
+ "@types/pdf-parse": "^1.1.5",
549615
+ "@types/pngjs": "^6.0.5",
549616
+ "@types/react": "^19.2.14",
549617
+ "@types/ws": "^8.18.1",
549618
+ ai: "^6.0.116",
549619
+ "bmad-method": "^6.1.0",
549620
+ cheerio: "^1.2.0",
549621
+ glob: "^13.0.6",
549622
+ "ink-big-text": "^2.0.0",
549623
+ "ink-gradient": "^4.0.0",
549624
+ "ink-select-input": "^6.2.0",
549625
+ "ink-spinner": "^5.0.0",
549626
+ next: "^16.1.6",
549627
+ "next-themes": "^0.4.6",
549628
+ "pdf-parse": "^2.4.5",
549629
+ pngjs: "^7.0.0",
549630
+ "react-doctor": "^0.1.4",
549631
+ "string-width": "^8.1.1",
549632
+ stripe: "^17.7.0",
549633
+ typescript: "^5.0.0",
549634
+ yaml: "^2.9.1",
549635
+ zod: "^4.3.6"
549636
+ },
549637
+ dependencies: {
549638
+ ink: "^6.8.0",
549639
+ jsdom: "^28.1.0",
549640
+ mermaid: "^11.16.1"
549641
+ },
549642
+ optionalDependencies: {
549643
+ sharp: "^0.34.5",
549644
+ "better-sqlite3": "^12.8.0",
549645
+ "node-pty": "^1.1.0",
549646
+ "tree-sitter": "^0.21.0",
549647
+ "tree-sitter-go": "^0.21.0",
549648
+ "tree-sitter-javascript": "^0.21.0",
549649
+ "tree-sitter-python": "^0.21.0",
549650
+ "tree-sitter-rust": "^0.21.0",
549651
+ "tree-sitter-typescript": "^0.21.0"
549652
+ },
549653
+ publishConfig: {
549654
+ access: "public"
549655
+ },
549656
+ author: "8GI Foundation",
549657
+ license: "Apache-2.0",
549658
+ repository: {
549659
+ type: "git",
549660
+ url: "https://github.com/8gi-foundation/8gent-code.git"
549661
+ },
549662
+ homepage: "https://8gent.dev",
549663
+ bugs: {
549664
+ url: "https://github.com/8gi-foundation/8gent-code/issues"
549665
+ }
549666
+ };
549667
+ });
549668
+
549669
+ // packages/voice/termux.ts
549670
+ import { constants as constants14, accessSync as accessSync3, readFileSync as readFileSync92 } from "fs";
549671
+ import { delimiter as delimiter7, join as join145 } from "path";
549672
+ function isAndroidHost(platform = process.platform, env = process.env) {
549673
+ return platform === "android" || !!env.TERMUX_VERSION || String(env.PREFIX ?? "").includes("/com.termux/");
549674
+ }
549675
+ function findOnPath(name, env = process.env) {
549676
+ for (const dir of String(env.PATH ?? "").split(delimiter7)) {
549677
+ if (!dir)
549678
+ continue;
549679
+ const candidate = join145(dir, name);
549680
+ try {
549681
+ accessSync3(candidate, constants14.X_OK);
549682
+ return candidate;
549683
+ } catch {}
549684
+ }
549685
+ return null;
549686
+ }
549687
+ var init_termux = () => {};
549688
+
549689
+ // apps/tui/src/lib/external-agent-runner.ts
549690
+ import { execSync as execSync5, spawn as spawn23 } from "child_process";
549691
+ function getPreset(id) {
549692
+ return EXTERNAL_AGENT_PRESETS[id.toLowerCase()] ?? null;
549693
+ }
549694
+ function listPresetIds() {
549695
+ return Object.keys(EXTERNAL_AGENT_PRESETS);
549696
+ }
549697
+ function isInstalled(preset) {
549698
+ try {
549699
+ execSync5(`command -v "${preset.command}"`, {
549700
+ stdio: "ignore",
549701
+ timeout: 1500
549702
+ });
549703
+ return true;
549704
+ } catch {
549705
+ return false;
549706
+ }
549707
+ }
549708
+ var stripAnsi = (s) => s.replace(/\u001B\[[0-9;?]*[a-zA-Z]/g, "").replace(/\u001B\][^\u0007]*\u0007/g, ""), EXTERNAL_AGENT_PRESETS;
549709
+ var init_external_agent_runner = __esm(() => {
549710
+ init_shell();
549711
+ EXTERNAL_AGENT_PRESETS = {
549712
+ claude: {
549713
+ id: "claude",
549714
+ label: "Sparring",
549715
+ command: "claude",
549716
+ promptMode: "flag",
549717
+ flagName: "-p",
549718
+ args: [],
549719
+ timeoutMs: 120000,
549720
+ parseStdout: stripAnsi,
549721
+ homepage: "https://docs.claude.com/en/docs/claude-code",
549722
+ preferWindow: true,
549723
+ install: {
549724
+ command: "npm install -g --prefix=$HOME/.npm-global @anthropic-ai/claude-code",
549725
+ notes: 'Binary at ~/.npm-global/bin/claude. If `claude` isn\'t on PATH after install, add `export PATH="$HOME/.npm-global/bin:$PATH"` to your shell rc. Then run `claude` once outside the TUI to authenticate with Anthropic.'
549726
+ }
549727
+ },
549728
+ codex: {
549729
+ id: "codex",
549730
+ label: "OpenAI Codex",
549731
+ command: "codex",
549732
+ promptMode: "arg",
549733
+ args: ["exec"],
549734
+ timeoutMs: 120000,
549735
+ parseStdout: stripAnsi,
549736
+ homepage: "https://github.com/openai/codex",
549737
+ preferWindow: true,
549738
+ install: {
549739
+ command: "npm install -g --prefix=$HOME/.npm-global @openai/codex",
549740
+ notes: "Binary at ~/.npm-global/bin/codex. Add `~/.npm-global/bin` to PATH if needed. Requires `export OPENAI_API_KEY=sk-...` before /spawn."
549741
+ }
549742
+ },
549743
+ hermes: {
549744
+ id: "hermes",
549745
+ label: "Hermes Agent",
549746
+ command: "hermes",
549747
+ preferWindow: true,
549748
+ promptMode: "flag",
549749
+ flagName: "-z",
549750
+ args: [],
549751
+ timeoutMs: 120000,
549752
+ parseStdout: stripAnsi,
549753
+ homepage: "https://github.com/NousResearch/hermes-agent",
549754
+ install: {
549755
+ command: "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash -s -- --skip-setup --no-venv",
549756
+ notes: "Hermes needs Python \u2265 3.11 (anaconda's default 3.10 won't work; use pyenv or brew install python@3.11). Installer symlinks `hermes` into ~/.local/bin; add it to PATH if needed. After install, run `hermes setup` or `hermes model` outside the TUI to configure a provider. Without that, /spawn'd Hermes tabs will fail with auth errors (Bedrock is the default provider)."
549757
+ }
549758
+ },
549759
+ openclaw: {
549760
+ id: "openclaw",
549761
+ label: "OpenClaw",
549762
+ command: "openclaw",
549763
+ preferWindow: true,
549764
+ promptMode: "arg",
549765
+ args: ["run", "--headless"],
549766
+ timeoutMs: 120000,
549767
+ parseStdout: stripAnsi,
549768
+ homepage: "https://github.com/openclaw/openclaw",
549769
+ install: {
549770
+ command: "npm install -g --prefix=$HOME/.npm-global openclaw@latest",
549771
+ notes: "Binary at ~/.npm-global/bin/openclaw. Add `~/.npm-global/bin` to PATH if needed. After install run `openclaw onboard` outside the TUI to set up the gateway, workspace, and skills. (8gent now provides a managed Node 22 runtime automatically when needed; no separate nvm step required.)"
549772
+ },
549773
+ requiresNodeVersion: "22.14.0"
549774
+ },
549775
+ pi: {
549776
+ preferWindow: true,
549777
+ id: "pi",
549778
+ label: "Pi (pi-mono)",
549779
+ command: "pi",
549780
+ promptMode: "flag",
549781
+ flagName: "-p",
549782
+ args: [],
549783
+ timeoutMs: 120000,
549784
+ parseStdout: stripAnsi,
549785
+ homepage: "https://pi.dev",
549786
+ install: {
549787
+ command: "npm install -g --prefix=$HOME/.npm-global @mariozechner/pi-coding-agent",
549788
+ notes: "Binary at ~/.npm-global/bin/pi. Add `~/.npm-global/bin` to PATH if needed. Default provider is Google (Gemini). Set GEMINI_API_KEY, or override with --provider/--model and the matching API key env var (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY)."
549789
+ }
549790
+ },
549791
+ "8gent": {
549792
+ id: "8gent",
549793
+ label: "8gent (nested)",
549794
+ command: "8gent",
549795
+ promptMode: "arg",
549796
+ args: ["run"],
549797
+ timeoutMs: 180000,
549798
+ parseStdout: stripAnsi,
549799
+ homepage: "https://8gent.dev",
549800
+ install: {
549801
+ command: "npm install -g --prefix=$HOME/.npm-global @8gi-foundation/8gent-code --force",
549802
+ notes: "Binary at ~/.npm-global/bin/8gent. --force overwrites stale `8` / `8gent` / `8gent-code` bin symlinks (npm 9+ EEXIST). Add `~/.npm-global/bin` to PATH if not already."
549803
+ }
549804
+ }
549805
+ };
549806
+ });
549807
+
549808
+ // packages/eight/welcome.ts
549809
+ import { existsSync as existsSync100 } from "fs";
549810
+ import { basename as basename49, delimiter as delimiter8, dirname as dirname69, isAbsolute as isAbsolute47, join as join146, relative as relative35, resolve as resolve67 } from "path";
549811
+ function pathOutsideFolder(path, cwd) {
549812
+ const root = resolve67(cwd);
549813
+ return path.split(delimiter8).filter((dir) => {
549814
+ if (!dir || !isAbsolute47(dir))
549815
+ return false;
549816
+ const rel = relative35(root, resolve67(dir));
549817
+ return rel.startsWith("..") || isAbsolute47(rel);
549818
+ }).join(delimiter8);
549819
+ }
549820
+ function safeModelLabel(model) {
549821
+ const m = model.trim();
549822
+ if (!m || m.length > 80 || /:\/\/|[@?\s]/.test(m))
549823
+ return "a custom model";
549824
+ return m;
549825
+ }
549826
+ function inGitRepo(dir) {
549827
+ let d = dir;
549828
+ for (let i = 0;i < 64; i++) {
549829
+ if (existsSync100(join146(d, ".git")))
549830
+ return true;
549831
+ const up = dirname69(d);
549832
+ if (up === d)
549833
+ return false;
549834
+ d = up;
549835
+ }
549836
+ return false;
549837
+ }
549838
+ function hostLabel(android, platform, arch) {
549839
+ if (android)
549840
+ return `Android (Termux, ${arch})`;
549841
+ const os = platform === "darwin" ? "macOS" : platform === "linux" ? "Linux" : platform === "win32" ? "Windows" : platform;
549842
+ return `${os} ${arch}`;
549843
+ }
549844
+ async function knownPresets() {
549845
+ const runner = await Promise.resolve().then(() => (init_external_agent_runner(), {}));
549846
+ const out = [];
549847
+ for (const id of listPresetIds()) {
549848
+ const p = getPreset(id);
549849
+ if (p)
549850
+ out.push({ id: p.id, command: p.command });
549851
+ }
549852
+ return out;
549853
+ }
549854
+ async function gatherWelcomeFacts(opts) {
549855
+ const env = opts.env ?? process.env;
549856
+ const android = isAndroidHost(opts.platform ?? process.platform, env);
549857
+ const cwd = resolve67(opts.cwd);
549858
+ const home = env.HOME ? resolve67(env.HOME) : null;
549859
+ const lookupEnv = { ...env, PATH: pathOutsideFolder(String(env.PATH ?? ""), cwd) };
549860
+ const presets = (opts.presets ?? await knownPresets()).filter((p) => p.id !== "8gent");
549861
+ return {
549862
+ version: String(package_default.version),
549863
+ host: hostLabel(android, opts.platform ?? process.platform, opts.arch ?? process.arch),
549864
+ android,
549865
+ model: safeModelLabel(opts.model),
549866
+ provider: opts.provider,
549867
+ presetIds: presets.map((p) => p.id),
549868
+ installed: presets.filter((p) => findOnPath(p.command, lookupEnv) !== null).map((p) => p.id),
549869
+ folder: cwd === home ? "~" : basename49(cwd) || "/",
549870
+ gitRepo: inGitRepo(cwd)
549871
+ };
549872
+ }
549873
+ function listWords(items) {
549874
+ if (items.length <= 1)
549875
+ return items.join("");
549876
+ return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
549877
+ }
549878
+ function buildWelcome(f) {
549879
+ const where = f.android ? "phone" : "machine";
549880
+ const lines = [`Hi, I'm 8gent v${f.version} on ${f.host}, using ${f.model} via ${f.provider}.`];
549881
+ if (f.installed.length > 0) {
549882
+ lines.push(`On this ${where} I found ${listWords(f.installed)}. Say "run ${f.installed[0]}" and I'll open it in a tab beside me.`);
549883
+ } else {
549884
+ lines.push(`I checked PATH for ${listWords(f.presetIds)}: none installed, so it's just me here.`);
549885
+ }
549886
+ lines.push(f.gitRepo ? `This folder (${f.folder}) is a git repo, so I can read its history and run its tests.` : `This folder (${f.folder}) is not a git repo. I won't look through it unless you ask.`);
549887
+ const next = [];
549888
+ if (f.installed.length > 0)
549889
+ next.push(`run ${f.installed[0]}`);
549890
+ next.push(f.gitRepo ? "what changed in the last commit" : "make a folder called demo with a hello web page");
549891
+ next.push("what can you do");
549892
+ lines.push("Try:", ...next.map((n) => ` "${n}"`));
549893
+ return lines.join(`
549894
+ `);
549895
+ }
549896
+ var init_welcome = __esm(() => {
549897
+ init_package();
549898
+ init_termux();
549899
+ });
549900
+
549392
549901
  // packages/eight/failover-provider-config.ts
549393
549902
  function providerConfigForStep(session, step) {
549394
549903
  if (step.provider === session.name) {
@@ -549906,8 +550415,8 @@ var init_local_turn_error = __esm(() => {
549906
550415
  });
549907
550416
 
549908
550417
  // packages/eight/output-gate.ts
549909
- import { existsSync as existsSync100 } from "fs";
549910
- import { isAbsolute as isAbsolute47, relative as relative35, resolve as resolve67 } from "path";
550418
+ import { existsSync as existsSync101 } from "fs";
550419
+ import { isAbsolute as isAbsolute48, relative as relative36, resolve as resolve68 } from "path";
549911
550420
  function isOutputGateEnabled(env = process.env, option) {
549912
550421
  if (option !== undefined)
549913
550422
  return option;
@@ -549939,10 +550448,10 @@ class OutputGate {
549939
550448
  events = [];
549940
550449
  constructor(task, cwd, enabled) {
549941
550450
  this.cwd = cwd;
549942
- this.required = !enabled ? [] : namedOutputs(task).map((shown) => ({ shown, abs: resolve67(cwd, shown) })).filter(({ abs }) => !relative35(cwd, abs).startsWith("..") && !isAbsolute47(relative35(cwd, abs))).filter(({ abs }) => !existsSync100(abs));
550451
+ this.required = !enabled ? [] : namedOutputs(task).map((shown) => ({ shown, abs: resolve68(cwd, shown) })).filter(({ abs }) => !relative36(cwd, abs).startsWith("..") && !isAbsolute48(relative36(cwd, abs))).filter(({ abs }) => !existsSync101(abs));
549943
550452
  }
549944
550453
  missing() {
549945
- return this.required.filter(({ abs }) => !existsSync100(abs)).map(({ shown }) => shown);
550454
+ return this.required.filter(({ abs }) => !existsSync101(abs)).map(({ shown }) => shown);
549946
550455
  }
549947
550456
  check(reply) {
549948
550457
  const missing = this.missing();
@@ -549980,7 +550489,7 @@ var init_output_gate = __esm(() => {
549980
550489
  function stripPunctuation(s) {
549981
550490
  return s.replace(/[.,;:!?]+$/g, "").trim();
549982
550491
  }
549983
- function isGreeting(message) {
550492
+ function isGreeting2(message) {
549984
550493
  const stripped = stripPunctuation(message.toLowerCase()).trim();
549985
550494
  if (stripped.length === 0)
549986
550495
  return true;
@@ -550001,7 +550510,7 @@ class PreToolRouter {
550001
550510
  classify(userMessage, _projectContext) {
550002
550511
  const msg = userMessage ?? "";
550003
550512
  const trimmed = msg.trim();
550004
- if (trimmed.length === 0 || isGreeting(trimmed)) {
550513
+ if (trimmed.length === 0 || isGreeting2(trimmed)) {
550005
550514
  return {
550006
550515
  strategy: "none",
550007
550516
  args: {},
@@ -550273,12 +550782,12 @@ __export(exports_system_prompt, {
550273
550782
  styleHasGuide: () => styleHasGuide,
550274
550783
  workingProjectNote: () => workingProjectNote
550275
550784
  });
550276
- import { readFileSync as readFileSync92 } from "fs";
550277
- import { basename as basename49, join as join145 } from "path";
550785
+ import { existsSync as existsSync102, readFileSync as readFileSync93 } from "fs";
550786
+ import { basename as basename50, join as join147, resolve as resolve69 } from "path";
550278
550787
  function buildBoardContextSegment(path = BOARD_CONTEXT_PATH) {
550279
550788
  let text;
550280
550789
  try {
550281
- text = readFileSync92(path, "utf-8").trim();
550790
+ text = readFileSync93(path, "utf-8").trim();
550282
550791
  } catch {
550283
550792
  return "";
550284
550793
  }
@@ -550305,8 +550814,20 @@ function communicationStyleLine(style) {
550305
550814
  function styleHasGuide(style) {
550306
550815
  return isCommunicationStyle(style) && STYLE_GUIDE[style] !== "";
550307
550816
  }
550817
+ function isPlainHome(dir, home = resolveHome()) {
550818
+ try {
550819
+ return home !== "" && resolve69(dir) === resolve69(home) && !existsSync102(join147(dir, ".git"));
550820
+ } catch {
550821
+ return false;
550822
+ }
550823
+ }
550308
550824
  function workingProjectNote(dir) {
550309
- const name = basename49(dir) || dir;
550825
+ const name = basename50(dir) || dir;
550826
+ if (isPlainHome(dir)) {
550827
+ return `
550828
+
550829
+ **Working folder: \`${dir}\` is the person's home folder, not a project. Do not list, search or summarise it unless they ask. Ask what they want to work on.**`;
550830
+ }
550310
550831
  if (name === "8gent-code") {
550311
550832
  return `
550312
550833
 
@@ -550650,7 +551171,7 @@ var init_system_prompt = __esm(() => {
550650
551171
  init_tool_registry();
550651
551172
  init_soul_layers();
550652
551173
  IDENTITY_SEGMENT = composeSoulPrompt("owner");
550653
- BOARD_CONTEXT_PATH = join145(resolveHome(), ".8gent", "board-context.md");
551174
+ BOARD_CONTEXT_PATH = join147(resolveHome(), ".8gent", "board-context.md");
550654
551175
  ACTION_FIRST_STYLE = [
550655
551176
  "Shape every reply so the reader can act without rereading:",
550656
551177
  ACTION_FIRST_PRECEDENCE,
@@ -552719,16 +553240,16 @@ var init_agent = __esm(() => {
552719
553240
  });
552720
553241
 
552721
553242
  // packages/ai/task-router.ts
552722
- import { join as join146 } from "path";
553243
+ import { join as join148 } from "path";
552723
553244
  var CONFIG_DIR2, ROUTER_CONFIG_PATH, ROUTER_STATS_PATH, ClassificationSchema;
552724
553245
  var init_task_router = __esm(() => {
552725
553246
  init_zod();
552726
553247
  init_providers2();
552727
553248
  init_local_model_server();
552728
553249
  init_text_tool_endpoint();
552729
- CONFIG_DIR2 = join146(process.env.HOME || "~", ".8gent");
552730
- ROUTER_CONFIG_PATH = join146(CONFIG_DIR2, "router.json");
552731
- ROUTER_STATS_PATH = join146(CONFIG_DIR2, "router-stats.json");
553250
+ CONFIG_DIR2 = join148(process.env.HOME || "~", ".8gent");
553251
+ ROUTER_CONFIG_PATH = join148(CONFIG_DIR2, "router.json");
553252
+ ROUTER_STATS_PATH = join148(CONFIG_DIR2, "router-stats.json");
552732
553253
  ClassificationSchema = object({
552733
553254
  category: _enum(["code", "reasoning", "simple", "creative"]).describe("Task category: code (write/edit/debug code, fix errors, implement features), " + "reasoning (complex logic, planning, architecture, multi-step analysis), " + "simple (quick answers, explanations, short chat, factual questions), " + "creative (writing, naming, brainstorming, design ideas)"),
552734
553255
  confidence: number2().min(0).max(1).describe("How confident you are in this classification (0-1)"),
@@ -552742,11 +553263,11 @@ var init_toolshed_bridge = __esm(() => {
552742
553263
  });
552743
553264
 
552744
553265
  // packages/ai/embedding-cache.ts
552745
- import { join as join147 } from "path";
553266
+ import { join as join149 } from "path";
552746
553267
  var CACHE_DIR, CACHE_PATH;
552747
553268
  var init_embedding_cache = __esm(() => {
552748
- CACHE_DIR = join147(process.env.HOME || "~", ".8gent");
552749
- CACHE_PATH = join147(CACHE_DIR, "embedding-cache.json");
553269
+ CACHE_DIR = join149(process.env.HOME || "~", ".8gent");
553270
+ CACHE_PATH = join149(CACHE_DIR, "embedding-cache.json");
552750
553271
  });
552751
553272
 
552752
553273
  // packages/ai/edge-inference.ts
@@ -553027,13 +553548,13 @@ var init_quick_answer = __esm(() => {
553027
553548
  // packages/eight/session-scratch.ts
553028
553549
  import { lstatSync as lstatSync31, mkdirSync as mkdirSync72, rmSync as rmSync14 } from "fs";
553029
553550
  import { tmpdir as tmpdir17 } from "os";
553030
- import { join as join148 } from "path";
553551
+ import { join as join150 } from "path";
553031
553552
  function removeAllAtExit() {
553032
553553
  for (const dir of [...live2])
553033
553554
  removeSessionScratch(dir);
553034
553555
  }
553035
553556
  function sessionScratchPath(sessionId) {
553036
- return join148(tmpdir17(), `8gent-${sessionId}`);
553557
+ return join150(tmpdir17(), `8gent-${sessionId}`);
553037
553558
  }
553038
553559
  function createSessionScratch(sessionId) {
553039
553560
  const dir = sessionScratchPath(sessionId);
@@ -560938,19 +561459,19 @@ var init_opportunity_scanner = () => {};
560938
561459
  var init_capability_matcher = () => {};
560939
561460
 
560940
561461
  // packages/proactive/work-tracker.ts
560941
- import { join as join151 } from "path";
561462
+ import { join as join153 } from "path";
560942
561463
  var DATA_DIR3, STORE_PATH;
560943
561464
  var init_work_tracker = __esm(() => {
560944
- DATA_DIR3 = join151(process.env.HOME || "~", ".8gent");
560945
- STORE_PATH = join151(DATA_DIR3, "opportunities.json");
561465
+ DATA_DIR3 = join153(process.env.HOME || "~", ".8gent");
561466
+ STORE_PATH = join153(DATA_DIR3, "opportunities.json");
560946
561467
  });
560947
561468
 
560948
561469
  // packages/proactive/revenue-engine.ts
560949
- import { join as join152 } from "path";
561470
+ import { join as join154 } from "path";
560950
561471
  var DATA_DIR4, STORE_PATH2;
560951
561472
  var init_revenue_engine = __esm(() => {
560952
- DATA_DIR4 = join152(process.env.HOME || "~", ".8gent");
560953
- STORE_PATH2 = join152(DATA_DIR4, "revenue.json");
561473
+ DATA_DIR4 = join154(process.env.HOME || "~", ".8gent");
561474
+ STORE_PATH2 = join154(DATA_DIR4, "revenue.json");
560954
561475
  });
560955
561476
 
560956
561477
  // packages/proactive/deliverable-generator.ts
@@ -560964,10 +561485,10 @@ var init_content_packaging = () => {};
560964
561485
 
560965
561486
  // packages/tools/browser/cache.ts
560966
561487
  import { homedir as homedir77 } from "os";
560967
- import { join as join153 } from "path";
561488
+ import { join as join155 } from "path";
560968
561489
  var CACHE_DIR2, TTL_MS, MAX_CACHE_BYTES;
560969
561490
  var init_cache2 = __esm(() => {
560970
- CACHE_DIR2 = join153(process.env.EIGHT_DATA_DIR || join153(homedir77(), ".8gent"), "browser-cache");
561491
+ CACHE_DIR2 = join155(process.env.EIGHT_DATA_DIR || join155(homedir77(), ".8gent"), "browser-cache");
560971
561492
  TTL_MS = 60 * 60 * 1000;
560972
561493
  MAX_CACHE_BYTES = 100 * 1024 * 1024;
560973
561494
  });
@@ -561710,7 +562231,7 @@ var init_voice3 = __esm(() => {
561710
562231
 
561711
562232
  // packages/eight/observation-pack.ts
561712
562233
  import { createHash as createHash21 } from "crypto";
561713
- import { readFileSync as readFileSync94 } from "fs";
562234
+ import { readFileSync as readFileSync95 } from "fs";
561714
562235
  function observationPackEnabled(env = process.env) {
561715
562236
  return env.EIGHT_OBSERVATION_PACK === "1";
561716
562237
  }
@@ -561730,7 +562251,7 @@ class ObservationStore {
561730
562251
  const path = this.paths.get(handle);
561731
562252
  if (!path)
561732
562253
  throw new Error(`no saved output with handle "${handle}" in this session`);
561733
- return readFileSync94(path, "utf8").slice(offset, offset + limit);
562254
+ return readFileSync95(path, "utf8").slice(offset, offset + limit);
561734
562255
  }
561735
562256
  size(handle) {
561736
562257
  return this.read(handle).length;
@@ -562665,6 +563186,7 @@ class Agent {
562665
563186
  steerQueue = [];
562666
563187
  activeTurn = null;
562667
563188
  turnCounter = 0;
563189
+ welcomed = false;
562668
563190
  stopRequested = false;
562669
563191
  orchestratorBus;
562670
563192
  toolRegistry;
@@ -563132,14 +563654,15 @@ ${LOCAL_LOGIN_NOTE}`;
563132
563654
  instructions,
563133
563655
  localCoreTools,
563134
563656
  chatStartTime,
563135
- textForAgent
563657
+ textForAgent,
563658
+ smallTalk = false
563136
563659
  } = opts;
563137
563660
  const signal = this.armController().signal;
563138
563661
  const allow = new Set(localCoreTools);
563139
563662
  const specs = toolDefsToSpecs(this.executor.getToolDefinitions(), allow);
563140
563663
  let stepNumber = 0;
563141
563664
  let breakerStop = null;
563142
- if (this.extensionToolsAllowed()) {
563665
+ if (this.extensionToolsAllowed() && !smallTalk) {
563143
563666
  for (const t of this.extensionHost.listTools()) {
563144
563667
  if (this.modeAllows(t.name)) {
563145
563668
  specs.push({ name: t.name, description: t.description, parameters: t.parameters });
@@ -563703,6 +564226,21 @@ ${LOCAL_LOGIN_NOTE}`;
563703
564226
  console.log(`[turn-review] ${line}`);
563704
564227
  }
563705
564228
  }
564229
+ async greetingWelcome(text) {
564230
+ if (this.welcomed || this.config.headless || this.agentDepth > 0 || !isGreeting(text))
564231
+ return null;
564232
+ try {
564233
+ const facts = await gatherWelcomeFacts({
564234
+ model: String(this.config.model),
564235
+ provider: String(this.config.runtime),
564236
+ cwd: this.config.workingDirectory || process.cwd()
564237
+ });
564238
+ this.welcomed = true;
564239
+ return buildWelcome(facts);
564240
+ } catch {
564241
+ return null;
564242
+ }
564243
+ }
563706
564244
  async runTurn(userMessage, imageBase64, imageMimeType, imageOriginal) {
563707
564245
  await this.extensionsReady;
563708
564246
  this.loopDetector.reset();
@@ -563717,6 +564255,17 @@ ${LOCAL_LOGIN_NOTE}`;
563717
564255
  this.turnGitBaseline = asksForCommit(userMessage) ? gitSnapshot(this.config.workingDirectory || process.cwd()) : null;
563718
564256
  this.executor.beginTurn(userMessage);
563719
564257
  const textForAgent = userMessage.trim() || (imageBase64 ? "The user attached an image with no text. Describe what you see and help with anything relevant in the image." : userMessage);
564258
+ const smallTalkTurn = isSmallTalk(textForAgent) && !imageBase64 && this.config.agentScope !== "__table__";
564259
+ if (smallTalkTurn) {
564260
+ const welcome = await this.greetingWelcome(textForAgent);
564261
+ if (welcome) {
564262
+ this.messageHistory.push({ role: "user", content: textForAgent });
564263
+ this.messageHistory.push({ role: "assistant", content: welcome });
564264
+ this.sessionWriter.writeUserMessage(textForAgent);
564265
+ return welcome;
564266
+ }
564267
+ this.messageHistory.push({ role: "user", content: harnessNote(SMALL_TALK_NOTE) });
564268
+ }
563720
564269
  let visionId = null;
563721
564270
  let visionFailed = false;
563722
564271
  if (imageBase64 && await this.promptImageSeen()) {
@@ -563787,7 +564336,7 @@ ${result.description.slice(0, 200)}${result.description.length > 200 ? "..." : "
563787
564336
  }
563788
564337
  }
563789
564338
  const quickPrompt = quickLaneEnabled() && classifyPrompt(textForAgent) === "quick";
563790
- if (needsClarification(textForAgent) && !imageBase64 && !quickPrompt && !isNoToolScope(this.config.agentScope)) {
564339
+ if (needsClarification(textForAgent) && !imageBase64 && !quickPrompt && !smallTalkTurn && !isNoToolScope(this.config.agentScope)) {
563791
564340
  this.proactiveGatherer = createGatherer(textForAgent);
563792
564341
  const question = this.proactiveGatherer.getCurrentQuestion();
563793
564342
  if (question) {
@@ -563809,7 +564358,7 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
563809
564358
  this.kanban.moveTask(this.currentBmadTask.id, "ready");
563810
564359
  this.kanban.moveTask(this.currentBmadTask.id, "in_progress");
563811
564360
  }
563812
- if (!this.proactiveGatherer && !quickPrompt) {
564361
+ if (!this.proactiveGatherer && !quickPrompt && !smallTalkTurn) {
563813
564362
  await this.tryRunPreToolRouter(textForAgent);
563814
564363
  }
563815
564364
  const needsPlanningGate2 = !isVerbatimScope(this.config.agentScope) && needsPlanningGate(textForAgent);
@@ -563954,9 +564503,9 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
563954
564503
  "search_symbols",
563955
564504
  "recall"
563956
564505
  ]);
563957
- const scopedTools = isNoToolScope(this.config.agentScope) ? {} : this.config.agentScope === "__table__" ? Object.fromEntries(Object.entries(providerTools).filter(([k]) => TABLE_SESSION_TOOLS.has(k))) : providerTools;
564506
+ const scopedTools = isNoToolScope(this.config.agentScope) || smallTalkTurn ? {} : this.config.agentScope === "__table__" ? Object.fromEntries(Object.entries(providerTools).filter(([k]) => TABLE_SESSION_TOOLS.has(k))) : providerTools;
563958
564507
  const withExtensions = { ...scopedTools };
563959
- if (this.extensionToolsAllowed()) {
564508
+ if (this.extensionToolsAllowed() && !smallTalkTurn) {
563960
564509
  for (const t of this.extensionHost.listTools()) {
563961
564510
  if (t.name in withExtensions)
563962
564511
  continue;
@@ -563968,7 +564517,7 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
563968
564517
  }
563969
564518
  }
563970
564519
  const effectiveTools = this.modeFilter(withExtensions);
563971
- const textToolAllowlist = (isNoToolScope(this.config.agentScope) ? [] : this.config.agentScope === "__table__" ? [...TABLE_SESSION_TOOLS] : localCoreTools).filter((name) => getModeManager().isToolAllowed(name));
564520
+ const textToolAllowlist = (isNoToolScope(this.config.agentScope) || smallTalkTurn ? [] : this.config.agentScope === "__table__" ? [...TABLE_SESSION_TOOLS] : localCoreTools).filter((name) => getModeManager().isToolAllowed(name));
563972
564521
  const harness = this.harnessProfileFor(providerConfig.model, isLocalProvider);
563973
564522
  Object.assign(this.runtimeParams, {
563974
564523
  voiceChatActive: getRuntimeParams().voiceChatActive,
@@ -563993,7 +564542,8 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
563993
564542
  `),
563994
564543
  localCoreTools: textToolAllowlist,
563995
564544
  chatStartTime,
563996
- textForAgent
564545
+ textForAgent,
564546
+ smallTalk: smallTalkTurn
563997
564547
  });
563998
564548
  await this.readServerContextWindow();
563999
564549
  await this.compactIfNeeded(providerConfig);
@@ -564678,7 +565228,7 @@ ${summary || " (no provider errors recorded)"}`);
564678
565228
  };
564679
565229
  }
564680
565230
  const blankNative = gatedNative.content.trim() === "";
564681
- const content = blankNative ? emptyReplyNote(this.turnToolLedger.length) : gatedNative.content;
565231
+ const content = blankNative ? emptyReplyNote(this.turnToolLedger.length, this.turnToolLedger) : gatedNative.content;
564682
565232
  const flavor = voice.getFlavor("complete");
564683
565233
  const flavoredContent = fixCompletedLine(gatedNative.violated || isVerbatimScope(this.config.agentScope) ? content : flavorResponse(content, flavor)).text;
564684
565234
  this.messageHistory.push({ role: "assistant", content: flavoredContent });
@@ -565393,7 +565943,9 @@ var init_agent2 = __esm(() => {
565393
565943
  init_modes();
565394
565944
  init_planning_gate();
565395
565945
  init_registry();
565946
+ init_small_talk();
565396
565947
  init_verify_gate();
565948
+ init_welcome();
565397
565949
  init_local_tool_scope();
565398
565950
  init_local_turn_error();
565399
565951
  init_output_gate();
@@ -566891,9 +567443,9 @@ var init_throughput_tracker = __esm(() => {
566891
567443
  });
566892
567444
 
566893
567445
  // packages/orchestration/worktree-pool-agent.ts
566894
- import { execFileSync as execFileSync10, spawn as spawn23 } from "child_process";
566895
- import { appendFileSync as appendFileSync23, existsSync as existsSync105, mkdirSync as mkdirSync76, readFileSync as readFileSync98, writeFileSync as writeFileSync58 } from "fs";
566896
- import { join as join158 } from "path";
567446
+ import { execFileSync as execFileSync10, spawn as spawn24 } from "child_process";
567447
+ import { appendFileSync as appendFileSync23, existsSync as existsSync107, mkdirSync as mkdirSync76, readFileSync as readFileSync99, writeFileSync as writeFileSync58 } from "fs";
567448
+ import { join as join160 } from "path";
566897
567449
 
566898
567450
  class WorktreePoolAgent {
566899
567451
  task;
@@ -566909,16 +567461,16 @@ class WorktreePoolAgent {
566909
567461
  }
566910
567462
  start(onDone) {
566911
567463
  this.onDone = onDone;
566912
- const logDir = join158(this.task.worktreePath, ".8gent");
567464
+ const logDir = join160(this.task.worktreePath, ".8gent");
566913
567465
  mkdirSync76(logDir, { recursive: true });
566914
- const logPath = join158(logDir, "output.log");
567466
+ const logPath = join160(logDir, "output.log");
566915
567467
  const env = {
566916
567468
  ...process.env,
566917
567469
  EIGHT_WORKTREE_ID: this.task.id,
566918
567470
  EIGHT_WORKTREE_PATH: this.task.worktreePath,
566919
567471
  ...this.task.model ? { EIGHGENT_MODEL: this.task.model } : {}
566920
567472
  };
566921
- this.proc = spawn23("bun", [...safeBunFlags(), "run", "packages/eight/index.ts", this.task.prompt], {
567473
+ this.proc = spawn24("bun", [...safeBunFlags(), "run", "packages/eight/index.ts", this.task.prompt], {
566922
567474
  cwd: this.task.worktreePath,
566923
567475
  stdio: ["pipe", "pipe", "pipe"],
566924
567476
  env,
@@ -566953,7 +567505,7 @@ class WorktreePoolAgent {
566953
567505
  filesChanged,
566954
567506
  completedAt: Date.now()
566955
567507
  };
566956
- const resultPath = join158(this.task.worktreePath, ".8gent", "result.json");
567508
+ const resultPath = join160(this.task.worktreePath, ".8gent", "result.json");
566957
567509
  try {
566958
567510
  writeFileSync58(resultPath, JSON.stringify(result, null, 2));
566959
567511
  } catch {}
@@ -566972,11 +567524,11 @@ class WorktreePoolAgent {
566972
567524
  }
566973
567525
  }
566974
567526
  static readResult(worktreePath) {
566975
- const p = join158(worktreePath, ".8gent", "result.json");
566976
- if (!existsSync105(p))
567527
+ const p = join160(worktreePath, ".8gent", "result.json");
567528
+ if (!existsSync107(p))
566977
567529
  return null;
566978
567530
  try {
566979
- return JSON.parse(readFileSync98(p, "utf-8"));
567531
+ return JSON.parse(readFileSync99(p, "utf-8"));
566980
567532
  } catch {
566981
567533
  return null;
566982
567534
  }
@@ -566988,8 +567540,8 @@ var init_worktree_pool_agent = __esm(() => {
566988
567540
 
566989
567541
  // packages/orchestration/worktree-pool.ts
566990
567542
  import { execFileSync as execFileSync11 } from "child_process";
566991
- import { existsSync as existsSync106, mkdirSync as mkdirSync77 } from "fs";
566992
- import { join as join159, resolve as resolve68 } from "path";
567543
+ import { existsSync as existsSync108, mkdirSync as mkdirSync77 } from "fs";
567544
+ import { join as join161, resolve as resolve70 } from "path";
566993
567545
 
566994
567546
  class WorktreePool {
566995
567547
  projectRoot;
@@ -567002,8 +567554,8 @@ class WorktreePool {
567002
567554
  running = 0;
567003
567555
  queue = [];
567004
567556
  constructor(opts = {}) {
567005
- this.projectRoot = resolve68(opts.projectRoot ?? process.cwd());
567006
- this.worktreesDir = join159(this.projectRoot, ".8gent", "worktrees");
567557
+ this.projectRoot = resolve70(opts.projectRoot ?? process.cwd());
567558
+ this.worktreesDir = join161(this.projectRoot, ".8gent", "worktrees");
567007
567559
  this.maxConcurrent = opts.maxConcurrent ?? DEFAULT_MAX;
567008
567560
  this.taskTimeoutMs = opts.taskTimeoutMs ?? DEFAULT_TIMEOUT2;
567009
567561
  mkdirSync77(this.worktreesDir, { recursive: true });
@@ -567011,7 +567563,7 @@ class WorktreePool {
567011
567563
  async spawn(prompt, opts = {}) {
567012
567564
  const id = `wt-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
567013
567565
  const branch = opts.branch ?? `8gent/worktree-${id}`;
567014
- const worktreePath = join159(this.worktreesDir, id);
567566
+ const worktreePath = join161(this.worktreesDir, id);
567015
567567
  const task = {
567016
567568
  id,
567017
567569
  prompt,
@@ -567122,7 +567674,7 @@ class WorktreePool {
567122
567674
  }
567123
567675
  }
567124
567676
  gitWorktreeRemove(path) {
567125
- if (!existsSync106(path))
567677
+ if (!existsSync108(path))
567126
567678
  return;
567127
567679
  try {
567128
567680
  execFileSync11("git", ["worktree", "remove", path, "--force"], {
@@ -567147,19 +567699,19 @@ var init_worktree_pool = __esm(() => {
567147
567699
 
567148
567700
  // packages/orchestration/worktree-messaging.ts
567149
567701
  import {
567150
- existsSync as existsSync107,
567702
+ existsSync as existsSync109,
567151
567703
  mkdirSync as mkdirSync78,
567152
- readFileSync as readFileSync99,
567704
+ readFileSync as readFileSync100,
567153
567705
  readdirSync as readdirSync26,
567154
567706
  unlinkSync as unlinkSync3,
567155
567707
  writeFileSync as writeFileSync59
567156
567708
  } from "fs";
567157
- import { join as join160 } from "path";
567709
+ import { join as join162 } from "path";
567158
567710
 
567159
567711
  class WorktreeMessaging {
567160
567712
  base;
567161
567713
  constructor(projectRoot) {
567162
- this.base = join160(projectRoot, ".8gent", "messages");
567714
+ this.base = join162(projectRoot, ".8gent", "messages");
567163
567715
  mkdirSync78(this.base, { recursive: true });
567164
567716
  }
567165
567717
  send(message) {
@@ -567170,9 +567722,9 @@ class WorktreeMessaging {
567170
567722
  };
567171
567723
  const targets = message.to === "broadcast" ? this.listInboxes() : [message.to];
567172
567724
  for (const target of targets) {
567173
- const dir = join160(this.base, target);
567725
+ const dir = join162(this.base, target);
567174
567726
  mkdirSync78(dir, { recursive: true });
567175
- writeFileSync59(join160(dir, `${msg.id}.json`), JSON.stringify(msg, null, 2));
567727
+ writeFileSync59(join162(dir, `${msg.id}.json`), JSON.stringify(msg, null, 2));
567176
567728
  }
567177
567729
  return msg;
567178
567730
  }
@@ -567183,15 +567735,15 @@ class WorktreeMessaging {
567183
567735
  return this.readDir(agentId, true);
567184
567736
  }
567185
567737
  readDir(agentId, remove) {
567186
- const dir = join160(this.base, agentId);
567187
- if (!existsSync107(dir))
567738
+ const dir = join162(this.base, agentId);
567739
+ if (!existsSync109(dir))
567188
567740
  return [];
567189
567741
  const files = readdirSync26(dir).filter((f) => f.endsWith(".json")).sort();
567190
567742
  const messages = [];
567191
567743
  for (const f of files) {
567192
- const fp = join160(dir, f);
567744
+ const fp = join162(dir, f);
567193
567745
  try {
567194
- messages.push(JSON.parse(readFileSync99(fp, "utf-8")));
567746
+ messages.push(JSON.parse(readFileSync100(fp, "utf-8")));
567195
567747
  if (remove)
567196
567748
  unlinkSync3(fp);
567197
567749
  } catch {}
@@ -567199,7 +567751,7 @@ class WorktreeMessaging {
567199
567751
  return messages;
567200
567752
  }
567201
567753
  listInboxes() {
567202
- if (!existsSync107(this.base))
567754
+ if (!existsSync109(this.base))
567203
567755
  return [];
567204
567756
  return readdirSync26(this.base);
567205
567757
  }
@@ -568829,9 +569381,9 @@ var init_cli = __esm(async () => {
568829
569381
  });
568830
569382
 
568831
569383
  // packages/orchestration/adaptive-pipeline.ts
568832
- import { spawn as spawn24 } from "child_process";
569384
+ import { spawn as spawn25 } from "child_process";
568833
569385
  import { homedir as homedir81 } from "os";
568834
- import { join as join161 } from "path";
569386
+ import { join as join163 } from "path";
568835
569387
 
568836
569388
  class Obstacle {
568837
569389
  type;
@@ -569226,7 +569778,7 @@ async function callLMStudio(model, system, user, maxTokens) {
569226
569778
  }
569227
569779
  function callAppleFoundation(system, user) {
569228
569780
  return new Promise((resolve, reject) => {
569229
- const proc = spawn24(BRIDGE_PATH2, [], { stdio: ["pipe", "pipe", "ignore"] });
569781
+ const proc = spawn25(BRIDGE_PATH2, [], { stdio: ["pipe", "pipe", "ignore"] });
569230
569782
  let buf = "";
569231
569783
  const timer = setTimeout(() => {
569232
569784
  proc.kill();
@@ -569316,7 +569868,7 @@ var init_adaptive_pipeline = __esm(() => {
569316
569868
  init_role_config();
569317
569869
  OLLAMA_URL2 = process.env.OLLAMA_BASE_URL || "http://localhost:11434";
569318
569870
  LMSTUDIO_URL2 = process.env.LMSTUDIO_BASE_URL || "http://localhost:1234/v1";
569319
- BRIDGE_PATH2 = process.env.APPLE_FOUNDATION_BRIDGE || join161(homedir81(), ".8gent", "bin", "apple-foundation-bridge");
569871
+ BRIDGE_PATH2 = process.env.APPLE_FOUNDATION_BRIDGE || join163(homedir81(), ".8gent", "bin", "apple-foundation-bridge");
569320
569872
  ((Severity) => {
569321
569873
  Severity[Severity["Trivial"] = 1] = "Trivial";
569322
569874
  Severity[Severity["Moderate"] = 2] = "Moderate";
@@ -569327,13 +569879,13 @@ var init_adaptive_pipeline = __esm(() => {
569327
569879
 
569328
569880
  // packages/orchestration/pipeline-cli.ts
569329
569881
  import { mkdirSync as mkdirSync80, writeFileSync as writeFileSync61 } from "fs";
569330
- import { join as join162, resolve as resolve69 } from "path";
569882
+ import { join as join164, resolve as resolve71 } from "path";
569331
569883
  async function runPipelineCommand(args) {
569332
- let outDir = resolve69(process.cwd(), "pipeline-output");
569884
+ let outDir = resolve71(process.cwd(), "pipeline-output");
569333
569885
  const taskParts = [];
569334
569886
  for (let i = 0;i < args.length; i++) {
569335
569887
  if (args[i] === "--out" && args[i + 1]) {
569336
- outDir = resolve69(args[++i]);
569888
+ outDir = resolve71(args[++i]);
569337
569889
  } else if (!args[i].startsWith("-")) {
569338
569890
  taskParts.push(args[i]);
569339
569891
  }
@@ -569353,7 +569905,7 @@ async function runPipelineCommand(args) {
569353
569905
  });
569354
569906
  const result = await pipeline.run(task);
569355
569907
  mkdirSync80(outDir, { recursive: true });
569356
- const artifactPath = join162(outDir, "index.html");
569908
+ const artifactPath = join164(outDir, "index.html");
569357
569909
  writeFileSync61(artifactPath, result.artifact || "<!-- pipeline produced no artifact -->");
569358
569910
  console.log("");
569359
569911
  console.log(`stages : ${result.stages.length}`);
@@ -569455,7 +570007,7 @@ var init_port_probe = () => {};
569455
570007
  import { randomBytes as randomBytes9, timingSafeEqual as timingSafeEqual2 } from "crypto";
569456
570008
  import { appendFileSync as appendFileSync24, mkdirSync as mkdirSync81 } from "fs";
569457
570009
  import { homedir as homedir82 } from "os";
569458
- import { join as join163 } from "path";
570010
+ import { join as join165 } from "path";
569459
570011
  function envMs(name, fallback) {
569460
570012
  const n = Number(process.env[name]);
569461
570013
  return Number.isFinite(n) && n > 0 ? n : fallback;
@@ -569486,9 +570038,9 @@ function allowable(command) {
569486
570038
  }
569487
570039
  function auditApproval(line) {
569488
570040
  try {
569489
- const dir = process.env.EIGHT_DATA_DIR || join163(homedir82(), ".8gent");
570041
+ const dir = process.env.EIGHT_DATA_DIR || join165(homedir82(), ".8gent");
569490
570042
  mkdirSync81(dir, { recursive: true });
569491
- appendFileSync24(join163(dir, "approvals-audit.jsonl"), `${JSON.stringify({ ts: new Date().toISOString(), ...line })}
570043
+ appendFileSync24(join165(dir, "approvals-audit.jsonl"), `${JSON.stringify({ ts: new Date().toISOString(), ...line })}
569492
570044
  `, { mode: 384 });
569493
570045
  } catch (err) {
569494
570046
  console.error("[channel-approvals] audit write failed:", err.message);
@@ -569650,19 +570202,19 @@ var init_classroom = __esm(() => {
569650
570202
  import { randomBytes as randomBytes10 } from "crypto";
569651
570203
  import {
569652
570204
  closeSync as closeSync21,
569653
- existsSync as existsSync109,
570205
+ existsSync as existsSync111,
569654
570206
  fchmodSync as fchmodSync5,
569655
570207
  fsyncSync as fsyncSync2,
569656
570208
  linkSync,
569657
570209
  mkdirSync as mkdirSync82,
569658
570210
  openSync as openSync21,
569659
- readFileSync as readFileSync100,
570211
+ readFileSync as readFileSync101,
569660
570212
  renameSync as renameSync15,
569661
570213
  unlinkSync as unlinkSync4,
569662
570214
  writeSync as writeSync6
569663
570215
  } from "fs";
569664
570216
  import { cpus } from "os";
569665
- import { dirname as dirname73 } from "path";
570217
+ import { dirname as dirname74 } from "path";
569666
570218
  function startLimitFor(maxSessions, requested) {
569667
570219
  const env = Number(process.env.EIGHT_WORK_QUEUE_STARTS);
569668
570220
  const n = requested ?? (Number.isInteger(env) && env > 0 ? env : Math.floor(cpus().length / 2));
@@ -569703,7 +570255,7 @@ function acquireLock(lockPath, opts = {}) {
569703
570255
  return;
569704
570256
  let judged;
569705
570257
  try {
569706
- judged = readFileSync100(lockPath, "utf8");
570258
+ judged = readFileSync101(lockPath, "utf8");
569707
570259
  } catch (err) {
569708
570260
  if (errCode2(err) === "ENOENT")
569709
570261
  continue;
@@ -569722,7 +570274,7 @@ function acquireLock(lockPath, opts = {}) {
569722
570274
  continue;
569723
570275
  throw err;
569724
570276
  }
569725
- const took = readFileSync100(moved, "utf8");
570277
+ const took = readFileSync101(moved, "utf8");
569726
570278
  if (took === judged) {
569727
570279
  unlinkSync4(moved);
569728
570280
  continue;
@@ -569750,15 +570302,15 @@ class WorkQueue {
569750
570302
  constructor(path, opts) {
569751
570303
  this.path = path;
569752
570304
  this.startLimit = startLimitFor(opts.maxSessions, opts.startLimit);
569753
- const dir = dirname73(path);
569754
- if (!existsSync109(dir))
570305
+ const dir = dirname74(path);
570306
+ if (!existsSync111(dir))
569755
570307
  mkdirSync82(dir, { recursive: true, mode: 448 });
569756
570308
  this.lockPath = `${path}.lock`;
569757
570309
  acquireLock(this.lockPath);
569758
570310
  let raw = "";
569759
570311
  try {
569760
- if (existsSync109(path))
569761
- raw = readFileSync100(path, "utf8");
570312
+ if (existsSync111(path))
570313
+ raw = readFileSync101(path, "utf8");
569762
570314
  this.replay(raw);
569763
570315
  this.fd = openSync21(path, "a", 384);
569764
570316
  fchmodSync5(this.fd, 384);
@@ -569880,7 +570432,7 @@ class WorkQueue {
569880
570432
  }
569881
570433
  releaseLock() {
569882
570434
  try {
569883
- if (readFileSync100(this.lockPath, "utf8").trim() === String(process.pid)) {
570435
+ if (readFileSync101(this.lockPath, "utf8").trim() === String(process.pid)) {
569884
570436
  unlinkSync4(this.lockPath);
569885
570437
  }
569886
570438
  } catch {}
@@ -570839,7 +571391,7 @@ var init_dispatch = __esm(() => {
570839
571391
  });
570840
571392
 
570841
571393
  // packages/harness/adapters/cli.ts
570842
- import { spawn as spawn25 } from "child_process";
571394
+ import { spawn as spawn26 } from "child_process";
570843
571395
 
570844
571396
  class CliHarness {
570845
571397
  name;
@@ -570882,7 +571434,7 @@ class CliHarness {
570882
571434
  const argv = buildArgv(this.config, task.prompt);
570883
571435
  let child;
570884
571436
  try {
570885
- child = spawn25(argv[0], argv.slice(1), {
571437
+ child = spawn26(argv[0], argv.slice(1), {
570886
571438
  cwd: task.cwd || process.cwd(),
570887
571439
  env: { ...process.env, ...this.config.env },
570888
571440
  detached: process.platform !== "win32",
@@ -572728,7 +573280,7 @@ var init_post_to_channel = __esm(() => {
572728
573280
 
572729
573281
  // packages/table/huddle-voice.ts
572730
573282
  import { spawnSync as spawnSync12 } from "child_process";
572731
- import { existsSync as existsSync111 } from "fs";
573283
+ import { existsSync as existsSync113 } from "fs";
572732
573284
  function voiceFor(code) {
572733
573285
  return VOICES[code.toUpperCase()] ?? HUMAN_VOICE;
572734
573286
  }
@@ -572743,11 +573295,11 @@ function inQuietHours(now) {
572743
573295
  }
572744
573296
  function findSupertonic() {
572745
573297
  for (const p of SUPERTONIC_CANDIDATES)
572746
- if (existsSync111(p))
573298
+ if (existsSync113(p))
572747
573299
  return p;
572748
573300
  const which = spawnSync12("which", ["supertonic"], { encoding: "utf8" });
572749
573301
  const found = which.stdout?.trim();
572750
- return found && existsSync111(found) ? found : null;
573302
+ return found && existsSync113(found) ? found : null;
572751
573303
  }
572752
573304
  function speechText(text, maxChars = 480) {
572753
573305
  const cleaned = text.replace(/\(verified:[^)]*\)/g, "").replace(/\[CLAIM STRIPPED:[^\]]*\]/g, "").replace(/`+/g, "").replace(/^[\s>*-]+/gm, "").replace(/\s+/g, " ").trim();
@@ -572780,7 +573332,7 @@ function narrateTurn(opts) {
572780
573332
  if (!bin)
572781
573333
  return { audioPath: null, durationMs: estimate, skipped: "no_tts" };
572782
573334
  const r = spawnSync12(bin, ["tts", text, "-o", opts.outPath, "--voice", opts.voice.supertonic, "--steps", String(opts.steps ?? 8)], { encoding: "utf8", timeout: 120000 });
572783
- if (r.status !== 0 || !existsSync111(opts.outPath)) {
573335
+ if (r.status !== 0 || !existsSync113(opts.outPath)) {
572784
573336
  return { audioPath: null, durationMs: estimate, skipped: "tts_failed" };
572785
573337
  }
572786
573338
  return { audioPath: opts.outPath, durationMs: probeDurationMs(opts.outPath) ?? estimate };
@@ -572806,7 +573358,7 @@ var init_huddle_voice = __esm(() => {
572806
573358
  });
572807
573359
 
572808
573360
  // packages/table/message-speak.ts
572809
- import { mkdtempSync as mkdtempSync10, readFileSync as readFileSync103, rmSync as rmSync15 } from "fs";
573361
+ import { mkdtempSync as mkdtempSync10, readFileSync as readFileSync104, rmSync as rmSync15 } from "fs";
572810
573362
  import * as os53 from "os";
572811
573363
  import * as path122 from "path";
572812
573364
  function voiceForAuthor(authorId, voiceFor) {
@@ -572830,7 +573382,7 @@ async function synthesizeMessageSpeech(message, deps = defaultDeps) {
572830
573382
  const reason = result.skipped === "empty_text" ? "empty_text" : "tts_failed";
572831
573383
  return { ok: false, reason: result.skipped === "no_tts" ? "no_tts" : reason };
572832
573384
  }
572833
- const bytes = readFileSync103(result.audioPath);
573385
+ const bytes = readFileSync104(result.audioPath);
572834
573386
  return { ok: true, bytes, durationMs: result.durationMs };
572835
573387
  } finally {
572836
573388
  rmSync15(dir, { recursive: true, force: true });
@@ -572881,7 +573433,7 @@ var init_message_speak = __esm(() => {
572881
573433
  });
572882
573434
 
572883
573435
  // packages/table/message-audio.ts
572884
- import { existsSync as existsSync112, mkdirSync as mkdirSync86, readFileSync as readFileSync104 } from "fs";
573436
+ import { existsSync as existsSync114, mkdirSync as mkdirSync86, readFileSync as readFileSync105 } from "fs";
572885
573437
  import * as os54 from "os";
572886
573438
  import * as path123 from "path";
572887
573439
  function messageAudioRoot() {
@@ -572897,10 +573449,10 @@ function handleTableAudioHttp(url) {
572897
573449
  return null;
572898
573450
  const [, messageId, file] = m;
572899
573451
  const filePath = path123.join(messageAudioDir(messageId), file);
572900
- if (!existsSync112(filePath))
573452
+ if (!existsSync114(filePath))
572901
573453
  return new Response("not found", { status: 404 });
572902
573454
  const ext = file.slice(file.lastIndexOf("."));
572903
- return new Response(readFileSync104(filePath), {
573455
+ return new Response(readFileSync105(filePath), {
572904
573456
  headers: {
572905
573457
  "content-type": MIME[ext] ?? "application/octet-stream",
572906
573458
  "cache-control": "no-store"
@@ -575019,7 +575571,7 @@ function fnv1a(text) {
575019
575571
  function draw(seedText, axis, options) {
575020
575572
  return options[fnv1a(`${axis}:${seedText}`) % options.length];
575021
575573
  }
575022
- function resolve70(intent) {
575574
+ function resolve72(intent) {
575023
575575
  const tone = intent.tone ?? "";
575024
575576
  if (tone && !TONES[tone]) {
575025
575577
  throw new DesignRefused("intent.tone", `unknown tone ${JSON.stringify(tone)}. Known tones: ${TONE_NAMES.join(", ")}.`);
@@ -575103,7 +575655,7 @@ function coordinateId(c) {
575103
575655
  return fnv1a(canonical).toString(16).padStart(8, "0");
575104
575656
  }
575105
575657
  function compose(intent) {
575106
- return composeAt(resolve70(intent), intent);
575658
+ return composeAt(resolve72(intent), intent);
575107
575659
  }
575108
575660
  var TONES, TONE_NAMES, BASE_PX;
575109
575661
  var init_compose = __esm(() => {
@@ -575892,18 +576444,18 @@ var init_slide_render = __esm(() => {
575892
576444
  // packages/table/bake.ts
575893
576445
  import { spawnSync as spawnSync13 } from "child_process";
575894
576446
  import { createHash as createHash26 } from "crypto";
575895
- import { existsSync as existsSync113, mkdirSync as mkdirSync87, readdirSync as readdirSync27, readFileSync as readFileSync105, rmSync as rmSync16, writeFileSync as writeFileSync63 } from "fs";
575896
- import { basename as basename50, join as join170 } from "path";
576447
+ import { existsSync as existsSync115, mkdirSync as mkdirSync87, readdirSync as readdirSync27, readFileSync as readFileSync106, rmSync as rmSync16, writeFileSync as writeFileSync63 } from "fs";
576448
+ import { basename as basename51, join as join172 } from "path";
575897
576449
  function findChrome3() {
575898
- return CHROME_CANDIDATES2.find((p) => existsSync113(p)) ?? null;
576450
+ return CHROME_CANDIDATES2.find((p) => existsSync115(p)) ?? null;
575899
576451
  }
575900
576452
  function huddleDir(huddleId) {
575901
- return join170(HUDDLES_DIR, huddleId);
576453
+ return join172(HUDDLES_DIR, huddleId);
575902
576454
  }
575903
576455
  function ensureHuddleDirs(huddleId) {
575904
576456
  const dir = huddleDir(huddleId);
575905
576457
  for (const sub of ["", "slides", "audio", "deck"])
575906
- mkdirSync87(join170(dir, sub), { recursive: true });
576458
+ mkdirSync87(join172(dir, sub), { recursive: true });
575907
576459
  return dir;
575908
576460
  }
575909
576461
  function slideToPng(htmlPath, pngPath, chrome) {
@@ -575917,7 +576469,7 @@ function slideToPng(htmlPath, pngPath, chrome) {
575917
576469
  `--screenshot=${pngPath}`,
575918
576470
  `file://${htmlPath}`
575919
576471
  ], { encoding: "utf8", timeout: 60000 });
575920
- return r.status === 0 && existsSync113(pngPath);
576472
+ return r.status === 0 && existsSync115(pngPath);
575921
576473
  }
575922
576474
  function emitDeckV2V(manifest) {
575923
576475
  const slides = manifest.turns.map((t) => {
@@ -576018,11 +576570,11 @@ function ffmpegClip(args) {
576018
576570
  return r.status === 0;
576019
576571
  }
576020
576572
  function sha256File(path) {
576021
- return createHash26("sha256").update(readFileSync105(path)).digest("hex");
576573
+ return createHash26("sha256").update(readFileSync106(path)).digest("hex");
576022
576574
  }
576023
576575
  function writeRecordingToManifest(manifestPath, manifest, videoPath) {
576024
576576
  const recording = {
576025
- file: basename50(videoPath),
576577
+ file: basename51(videoPath),
576026
576578
  sha256: sha256File(videoPath),
576027
576579
  bakedAt: Date.now()
576028
576580
  };
@@ -576037,13 +576589,13 @@ function slugify4(text, fallback = "huddle") {
576037
576589
  function bakeHuddle(manifest, stamp) {
576038
576590
  const dir = ensureHuddleDirs(manifest.huddleId);
576039
576591
  mkdirSync87(CREATIVE_DIR2, { recursive: true });
576040
- const manifestPath = join170(dir, "manifest.json");
576592
+ const manifestPath = join172(dir, "manifest.json");
576041
576593
  writeFileSync63(manifestPath, JSON.stringify(manifest, null, 2), "utf8");
576042
- const deckPath = join170(dir, "deck", "deck.html");
576594
+ const deckPath = join172(dir, "deck", "deck.html");
576043
576595
  writeFileSync63(deckPath, emitDeckHyperframes(manifest), "utf8");
576044
- const deckV2VPath = join170(dir, "deck", "deck-v2v.html");
576596
+ const deckV2VPath = join172(dir, "deck", "deck-v2v.html");
576045
576597
  writeFileSync63(deckV2VPath, emitDeckV2V(manifest), "utf8");
576046
- const transcriptPath = join170(dir, "transcript.md");
576598
+ const transcriptPath = join172(dir, "transcript.md");
576047
576599
  writeFileSync63(transcriptPath, emitTranscript(manifest), "utf8");
576048
576600
  const result = { manifestPath, deckPath, deckV2VPath, transcriptPath, videoPath: null, slidePngs: [] };
576049
576601
  if (manifest.turns.length === 0) {
@@ -576055,11 +576607,11 @@ function bakeHuddle(manifest, stamp) {
576055
576607
  result.videoError = "no Chrome/Chromium found for slide capture";
576056
576608
  return result;
576057
576609
  }
576058
- const work = join170(dir, "work");
576610
+ const work = join172(dir, "work");
576059
576611
  mkdirSync87(work, { recursive: true });
576060
576612
  for (const turn of manifest.turns) {
576061
- const htmlPath = join170(dir, "slides", `slide-${turn.turnId}.html`);
576062
- if (!existsSync113(htmlPath)) {
576613
+ const htmlPath = join172(dir, "slides", `slide-${turn.turnId}.html`);
576614
+ if (!existsSync115(htmlPath)) {
576063
576615
  const { html } = renderSlide(turn.spec, {
576064
576616
  code: turn.code,
576065
576617
  name: turn.name,
@@ -576070,7 +576622,7 @@ function bakeHuddle(manifest, stamp) {
576070
576622
  });
576071
576623
  writeFileSync63(htmlPath, html, "utf8");
576072
576624
  }
576073
- const png = join170(dir, "slides", `slide-${turn.turnId}.png`);
576625
+ const png = join172(dir, "slides", `slide-${turn.turnId}.png`);
576074
576626
  if (!slideToPng(htmlPath, png, chrome)) {
576075
576627
  result.videoError = `slide capture failed for turn ${turn.index}`;
576076
576628
  return result;
@@ -576079,11 +576631,11 @@ function bakeHuddle(manifest, stamp) {
576079
576631
  }
576080
576632
  const clips = [];
576081
576633
  for (const turn of manifest.turns) {
576082
- const png = join170(dir, "slides", `slide-${turn.turnId}.png`);
576083
- const clip = join170(work, `clip-${String(turn.index).padStart(3, "0")}.mp4`);
576634
+ const png = join172(dir, "slides", `slide-${turn.turnId}.png`);
576635
+ const clip = join172(work, `clip-${String(turn.index).padStart(3, "0")}.mp4`);
576084
576636
  const secs = (turn.durationMs / 1000).toFixed(3);
576085
576637
  const video = ["-loop", "1", "-framerate", "30", "-t", secs, "-i", png];
576086
- const audio = turn.audioPath && existsSync113(turn.audioPath) ? ["-ss", (turn.audioOffsetMs / 1000).toFixed(3), "-t", secs, "-i", turn.audioPath] : ["-f", "lavfi", "-t", secs, "-i", "anullsrc=r=44100:cl=stereo"];
576638
+ const audio = turn.audioPath && existsSync115(turn.audioPath) ? ["-ss", (turn.audioOffsetMs / 1000).toFixed(3), "-t", secs, "-i", turn.audioPath] : ["-f", "lavfi", "-t", secs, "-i", "anullsrc=r=44100:cl=stereo"];
576087
576639
  const ok = ffmpegClip([
576088
576640
  "-y",
576089
576641
  ...video,
@@ -576113,19 +576665,19 @@ function bakeHuddle(manifest, stamp) {
576113
576665
  "-shortest",
576114
576666
  clip
576115
576667
  ]);
576116
- if (!ok || !existsSync113(clip)) {
576668
+ if (!ok || !existsSync115(clip)) {
576117
576669
  result.videoError = `ffmpeg clip failed for turn ${turn.index}`;
576118
576670
  return result;
576119
576671
  }
576120
576672
  clips.push(clip);
576121
576673
  }
576122
- const listPath = join170(work, "clips.txt");
576674
+ const listPath = join172(work, "clips.txt");
576123
576675
  writeFileSync63(listPath, clips.map((c) => `file '${c.replace(/'/g, "'\\''")}'`).join(`
576124
576676
  `), "utf8");
576125
576677
  const outName = `huddle-${slugify4(manifest.topic)}-${stamp}.mp4`;
576126
- const outPath = join170(CREATIVE_DIR2, outName);
576678
+ const outPath = join172(CREATIVE_DIR2, outName);
576127
576679
  const ok = ffmpegClip(["-y", "-f", "concat", "-safe", "0", "-i", listPath, "-c", "copy", "-movflags", "+faststart", outPath]);
576128
- if (!ok || !existsSync113(outPath)) {
576680
+ if (!ok || !existsSync115(outPath)) {
576129
576681
  result.videoError = "ffmpeg concat failed";
576130
576682
  return result;
576131
576683
  }
@@ -576144,8 +576696,8 @@ var CREATIVE_DIR2, HUDDLES_DIR, CHROME_CANDIDATES2;
576144
576696
  var init_bake = __esm(() => {
576145
576697
  init_home();
576146
576698
  init_slide_render();
576147
- CREATIVE_DIR2 = join170(resolveHome(), ".8gent", "creative");
576148
- HUDDLES_DIR = join170(resolveHome(), ".8gent", "huddles");
576699
+ CREATIVE_DIR2 = join172(resolveHome(), ".8gent", "creative");
576700
+ HUDDLES_DIR = join172(resolveHome(), ".8gent", "huddles");
576149
576701
  CHROME_CANDIDATES2 = [
576150
576702
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
576151
576703
  "/Applications/Chromium.app/Contents/MacOS/Chromium",
@@ -577594,8 +578146,8 @@ var init_zen = __esm(() => {
577594
578146
  });
577595
578147
 
577596
578148
  // packages/daemon/huddle-stage.ts
577597
- import { existsSync as existsSync114, mkdirSync as mkdirSync88, readFileSync as readFileSync107, writeFileSync as writeFileSync64 } from "fs";
577598
- import { join as join172 } from "path";
578149
+ import { existsSync as existsSync116, mkdirSync as mkdirSync88, readFileSync as readFileSync108, writeFileSync as writeFileSync64 } from "fs";
578150
+ import { join as join174 } from "path";
577599
578151
  function openStage(huddleId, channelId, topic) {
577600
578152
  ensureHuddleDirs(huddleId);
577601
578153
  stages.set(huddleId, {
@@ -577645,7 +578197,7 @@ function nameOf2(holder) {
577645
578197
  }
577646
578198
  function claimRoots() {
577647
578199
  const home = resolveHome();
577648
- return [join172(home, "8gent-code"), join172(home, "8gi-governance"), getDataDir()];
578200
+ return [join174(home, "8gent-code"), join174(home, "8gi-governance"), getDataDir()];
577649
578201
  }
577650
578202
  async function runTurnPipeline(huddleId, turnId, holder, replyText, broadcast, opts = {}) {
577651
578203
  const state = stages.get(huddleId);
@@ -577666,7 +578218,7 @@ async function runTurnPipeline(huddleId, turnId, holder, replyText, broadcast, o
577666
578218
  };
577667
578219
  const { html, sha256 } = renderSlide(verified.spec, ctx);
577668
578220
  const dir = ensureHuddleDirs(huddleId);
577669
- writeFileSync64(join172(dir, "slides", `slide-${turnId}.html`), html, "utf8");
578221
+ writeFileSync64(join174(dir, "slides", `slide-${turnId}.html`), html, "utf8");
577670
578222
  broadcast(state.channelId, {
577671
578223
  type: "huddle:slide",
577672
578224
  huddleId,
@@ -577681,7 +578233,7 @@ async function runTurnPipeline(huddleId, turnId, holder, replyText, broadcast, o
577681
578233
  });
577682
578234
  await waitForStage(state, huddleId, turnId);
577683
578235
  const voice = voiceFor(code);
577684
- const wav = join172(dir, "audio", `turn-${turnId}.wav`);
578236
+ const wav = join174(dir, "audio", `turn-${turnId}.wav`);
577685
578237
  const speech = speechText(resolved.speech);
577686
578238
  const narration = mediaEnabled ? narrateTurn({ text: speech, voice, outPath: wav, interactive: opts.interactive ?? true }) : { audioPath: null, durationMs: estimateReadingMs(speech), skipped: "no_tts" };
577687
578239
  try {
@@ -577725,9 +578277,9 @@ function ingestDictation(huddleId, holder, wavPath, whisperJsonPath, broadcast)
577725
578277
  const state = stages.get(huddleId);
577726
578278
  if (!state)
577727
578279
  return 0;
577728
- if (!existsSync114(whisperJsonPath))
578280
+ if (!existsSync116(whisperJsonPath))
577729
578281
  return 0;
577730
- const segments = parseWhisperJson(readFileSync107(whisperJsonPath, "utf8"));
578282
+ const segments = parseWhisperJson(readFileSync108(whisperJsonPath, "utf8"));
577731
578283
  const slides = zenSlides(segments, Object.keys(OFFICERS));
577732
578284
  const dir = ensureHuddleDirs(huddleId);
577733
578285
  const name = nameOf2(holder);
@@ -577736,7 +578288,7 @@ function ingestDictation(huddleId, holder, wavPath, whisperJsonPath, broadcast)
577736
578288
  const index = state.turns.length;
577737
578289
  const ctx = { code: "HUMAN", name, index: index + 1, huddleId };
577738
578290
  const { html, sha256 } = renderSlide(slide.spec, ctx);
577739
- writeFileSync64(join172(dir, "slides", `slide-${turnId}.html`), html, "utf8");
578291
+ writeFileSync64(join174(dir, "slides", `slide-${turnId}.html`), html, "utf8");
577740
578292
  broadcast(state.channelId, {
577741
578293
  type: "huddle:slide",
577742
578294
  huddleId,
@@ -577783,11 +578335,11 @@ function closeStage(huddleId) {
577783
578335
  turns: state.turns
577784
578336
  };
577785
578337
  if (!mediaEnabled) {
577786
- writeFileSync64(join172(ensureHuddleDirs(huddleId), "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
578338
+ writeFileSync64(join174(ensureHuddleDirs(huddleId), "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
577787
578339
  return {
577788
578340
  videoPath: null,
577789
578341
  videoError: "media disabled for this process",
577790
- transcriptPath: join172(huddleDir(huddleId), "transcript.md"),
578342
+ transcriptPath: join174(huddleDir(huddleId), "transcript.md"),
577791
578343
  turnCount: state.turns.length,
577792
578344
  hashes: state.turns.map((t) => t.sha256)
577793
578345
  };
@@ -577806,7 +578358,7 @@ function closeStage(huddleId) {
577806
578358
  return {
577807
578359
  videoPath: null,
577808
578360
  videoError: err.message,
577809
- transcriptPath: join172(huddleDir(huddleId), "transcript.md"),
578361
+ transcriptPath: join174(huddleDir(huddleId), "transcript.md"),
577810
578362
  turnCount: state.turns.length,
577811
578363
  hashes: state.turns.map((t) => t.sha256)
577812
578364
  };
@@ -577830,11 +578382,11 @@ function handleStageHttp(url, wsUrl) {
577830
578382
  }
577831
578383
  if (!file || file.includes(".."))
577832
578384
  return new Response("not found", { status: 404 });
577833
- const path = join172(huddleDir(huddleId), kind, file);
577834
- if (!existsSync114(path))
578385
+ const path = join174(huddleDir(huddleId), kind, file);
578386
+ if (!existsSync116(path))
577835
578387
  return new Response("not found", { status: 404 });
577836
578388
  const ext = file.slice(file.lastIndexOf("."));
577837
- return new Response(readFileSync107(path), {
578389
+ return new Response(readFileSync108(path), {
577838
578390
  headers: { "content-type": MIME2[ext] ?? "application/octet-stream", "cache-control": "no-store" }
577839
578391
  });
577840
578392
  }
@@ -578157,7 +578709,7 @@ var init_shared_sessions = __esm(() => {
578157
578709
 
578158
578710
  // packages/daemon/live-anatomy.ts
578159
578711
  import { timingSafeEqual as timingSafeEqual5 } from "crypto";
578160
- import { readFileSync as readFileSync108 } from "fs";
578712
+ import { readFileSync as readFileSync109 } from "fs";
578161
578713
  function obj(v) {
578162
578714
  return v && typeof v === "object" && !Array.isArray(v) ? v : {};
578163
578715
  }
@@ -578502,7 +579054,7 @@ function liveClose(ws) {
578502
579054
  }
578503
579055
  function mermaidScript() {
578504
579056
  try {
578505
- mermaidJs ??= readFileSync108(Bun.resolveSync("mermaid/dist/mermaid.min.js", import.meta.dir), "utf8");
579057
+ mermaidJs ??= readFileSync109(Bun.resolveSync("mermaid/dist/mermaid.min.js", import.meta.dir), "utf8");
578506
579058
  } catch {
578507
579059
  return new Response("mermaid is not installed next to the daemon", { status: 503 });
578508
579060
  }
@@ -579710,13 +580262,13 @@ var init_workspace_db = __esm(() => {
579710
580262
  });
579711
580263
 
579712
580264
  // packages/daemon/routes/store/audit.ts
579713
- import { appendFileSync as appendFileSync26, existsSync as existsSync116, mkdirSync as mkdirSync90 } from "fs";
580265
+ import { appendFileSync as appendFileSync26, existsSync as existsSync118, mkdirSync as mkdirSync90 } from "fs";
579714
580266
  import * as path127 from "path";
579715
580267
  function auditDir() {
579716
580268
  if (_auditDir)
579717
580269
  return _auditDir;
579718
580270
  const dir = path127.join(getDataDir(), "audit");
579719
- if (!existsSync116(dir)) {
580271
+ if (!existsSync118(dir)) {
579720
580272
  try {
579721
580273
  mkdirSync90(dir, { recursive: true });
579722
580274
  } catch (err) {
@@ -581056,7 +581608,7 @@ var init_session2 = __esm(() => {
581056
581608
  });
581057
581609
 
581058
581610
  // packages/daemon/routes/store/index.ts
581059
- import { existsSync as existsSync120, mkdirSync as mkdirSync94, readFileSync as readFileSync111, writeFileSync as writeFileSync67 } from "fs";
581611
+ import { existsSync as existsSync122, mkdirSync as mkdirSync94, readFileSync as readFileSync112, writeFileSync as writeFileSync67 } from "fs";
581060
581612
  import * as crypto13 from "crypto";
581061
581613
  import * as path131 from "path";
581062
581614
  function ensureServerToken(tokenPath) {
@@ -581064,10 +581616,10 @@ function ensureServerToken(tokenPath) {
581064
581616
  return _cachedToken;
581065
581617
  const file = tokenPath ?? path131.join(getDataDir(), "server.token");
581066
581618
  const dir = path131.dirname(file);
581067
- if (!existsSync120(dir))
581619
+ if (!existsSync122(dir))
581068
581620
  mkdirSync94(dir, { recursive: true });
581069
- if (existsSync120(file)) {
581070
- const t = readFileSync111(file, "utf-8").trim();
581621
+ if (existsSync122(file)) {
581622
+ const t = readFileSync112(file, "utf-8").trim();
581071
581623
  if (t.length >= 32) {
581072
581624
  if (!tokenPath)
581073
581625
  _cachedToken = t;
@@ -582941,7 +583493,7 @@ var PREPARE_BUDGET_MS = 120000, SPEAK_GRACE_MS = 500, SPEAK_BUDGET_MS = 120000,
582941
583493
 
582942
583494
  // packages/daemon/huddle-minutes.ts
582943
583495
  import { writeFileSync as writeFileSync68 } from "fs";
582944
- import { join as join179 } from "path";
583496
+ import { join as join181 } from "path";
582945
583497
  function turnsBlock(turns) {
582946
583498
  const lines = turns.map((t) => `${t.code === "HUMAN" ? t.name : `${t.code} ${t.name}`}: ${t.text.slice(0, TURN_TEXT_CAP)}`);
582947
583499
  let block = lines.join(`
@@ -583106,7 +583658,7 @@ Your previous reply was not valid JSON matching the contract. Reply again with O
583106
583658
  }
583107
583659
  function writeMinutesFile(minutes) {
583108
583660
  const dir = ensureHuddleDirs(minutes.huddleId);
583109
- const path = join179(dir, "minutes.json");
583661
+ const path = join181(dir, "minutes.json");
583110
583662
  writeFileSync68(path, JSON.stringify(minutes, null, 2), "utf8");
583111
583663
  return path;
583112
583664
  }
@@ -584956,12 +585508,12 @@ var init_gateway = __esm(() => {
584956
585508
  });
584957
585509
 
584958
585510
  // packages/daemon/heartbeat.ts
584959
- import { join as join180 } from "path";
585511
+ import { join as join182 } from "path";
584960
585512
  function taskQueuePath() {
584961
- return join180(getDataDir(), "task-queue.json");
585513
+ return join182(getDataDir(), "task-queue.json");
584962
585514
  }
584963
585515
  function inboxPath() {
584964
- return join180(getDataDir(), "inbox.json");
585516
+ return join182(getDataDir(), "inbox.json");
584965
585517
  }
584966
585518
  function defaultConfig() {
584967
585519
  return {
@@ -585891,14 +586443,14 @@ import { createHash as createHash31, createHmac as createHmac4, randomBytes as r
585891
586443
  import {
585892
586444
  appendFileSync as appendFileSync27,
585893
586445
  chmodSync as chmodSync6,
585894
- existsSync as existsSync121,
586446
+ existsSync as existsSync123,
585895
586447
  mkdirSync as mkdirSync96,
585896
- readFileSync as readFileSync113,
586448
+ readFileSync as readFileSync114,
585897
586449
  rmSync as rmSync18,
585898
586450
  truncateSync as truncateSync2,
585899
586451
  writeFileSync as writeFileSync69
585900
586452
  } from "fs";
585901
- import { dirname as dirname79 } from "path";
586453
+ import { dirname as dirname80 } from "path";
585902
586454
  function digest(line) {
585903
586455
  return createHash31("sha256").update(line.prev).update(`
585904
586456
  `).update(JSON.stringify(line)).digest("hex");
@@ -585917,15 +586469,15 @@ class AuditLog {
585917
586469
  constructor(path, saltPath, clock = Date.now, onRepair = () => {}) {
585918
586470
  this.path = path;
585919
586471
  this.clock = clock;
585920
- ensurePrivateDir(dirname79(path));
585921
- if (existsSync121(saltPath)) {
585922
- this.salt = readFileSync113(saltPath);
586472
+ ensurePrivateDir(dirname80(path));
586473
+ if (existsSync123(saltPath)) {
586474
+ this.salt = readFileSync114(saltPath);
585923
586475
  } else {
585924
586476
  this.salt = randomBytes15(32);
585925
586477
  writeFileSync69(saltPath, this.salt, { mode: 384 });
585926
586478
  chmodSync6(saltPath, 384);
585927
586479
  }
585928
- if (existsSync121(path)) {
586480
+ if (existsSync123(path)) {
585929
586481
  const dropped = repairTornTail(path);
585930
586482
  if (dropped > 0)
585931
586483
  onRepair(dropped);
@@ -585968,7 +586520,7 @@ class AuditLog {
585968
586520
  }
585969
586521
  }
585970
586522
  function repairTornTail(path) {
585971
- const buf = readFileSync113(path);
586523
+ const buf = readFileSync114(path);
585972
586524
  if (buf.length === 0 || buf[buf.length - 1] === 10)
585973
586525
  return 0;
585974
586526
  const cut = buf.lastIndexOf(10) + 1;
@@ -585983,9 +586535,9 @@ function repairTornTail(path) {
585983
586535
  return buf.length - cut;
585984
586536
  }
585985
586537
  function verifyAudit(path) {
585986
- if (!existsSync121(path))
586538
+ if (!existsSync123(path))
585987
586539
  return { ok: true, count: 0, lastHash: GENESIS };
585988
- const lines = readFileSync113(path, "utf8").split(`
586540
+ const lines = readFileSync114(path, "utf8").split(`
585989
586541
  `).filter(Boolean);
585990
586542
  let prev = GENESIS;
585991
586543
  for (let i = 0;i < lines.length; i++) {
@@ -586018,15 +586570,15 @@ import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv
586018
586570
  import {
586019
586571
  chmodSync as chmodSync7,
586020
586572
  closeSync as closeSync24,
586021
- existsSync as existsSync122,
586573
+ existsSync as existsSync124,
586022
586574
  fsyncSync as fsyncSync4,
586023
586575
  openSync as openSync24,
586024
- readFileSync as readFileSync114,
586576
+ readFileSync as readFileSync115,
586025
586577
  renameSync as renameSync17,
586026
586578
  unlinkSync as unlinkSync7,
586027
586579
  writeSync as writeSync8
586028
586580
  } from "fs";
586029
- import { dirname as dirname80, join as join181 } from "path";
586581
+ import { dirname as dirname81, join as join183 } from "path";
586030
586582
  function seal(plain, key) {
586031
586583
  const iv = randomBytes16(12);
586032
586584
  const c = createCipheriv2("aes-256-gcm", key, iv);
@@ -586053,15 +586605,15 @@ class MemoryVault {
586053
586605
  constructor(dir, store, key) {
586054
586606
  this.store = store;
586055
586607
  this.key = key;
586056
- this.file = join181(dir, "memory.db.enc");
586608
+ this.file = join183(dir, "memory.db.enc");
586057
586609
  }
586058
586610
  static open(dir, keyProvider = keychainKey) {
586059
586611
  const key = keyProvider();
586060
586612
  if (!key || key.length !== 32)
586061
586613
  throw new Error("vault: no encryption key available");
586062
586614
  ensurePrivateDir(dir);
586063
- const file = join181(dir, "memory.db.enc");
586064
- const db = existsSync122(file) ? Database11.deserialize(unseal(readFileSync114(file), key)) : new Database11(":memory:");
586615
+ const file = join183(dir, "memory.db.enc");
586616
+ const db = existsSync124(file) ? Database11.deserialize(unseal(readFileSync115(file), key)) : new Database11(":memory:");
586065
586617
  db.exec("PRAGMA secure_delete = ON");
586066
586618
  const vault = new MemoryVault(dir, new MemoryStore(db), key);
586067
586619
  vault.persist();
@@ -586080,7 +586632,7 @@ class MemoryVault {
586080
586632
  }
586081
586633
  chmodSync7(tmp, 384);
586082
586634
  renameSync17(tmp, this.file);
586083
- const dfd = openSync24(dirname80(this.file), "r");
586635
+ const dfd = openSync24(dirname81(this.file), "r");
586084
586636
  try {
586085
586637
  fsyncSync4(dfd);
586086
586638
  } finally {
@@ -586167,8 +586719,8 @@ function validateTenant(memory, scope) {
586167
586719
 
586168
586720
  // packages/memory/telegram-memory.ts
586169
586721
  import { randomInt, timingSafeEqual as timingSafeEqual8 } from "crypto";
586170
- import { chmodSync as chmodSync8, existsSync as existsSync123, readFileSync as readFileSync115, statSync as statSync37, unlinkSync as unlinkSync8, writeFileSync as writeFileSync70 } from "fs";
586171
- import { join as join182 } from "path";
586722
+ import { chmodSync as chmodSync8, existsSync as existsSync125, readFileSync as readFileSync116, statSync as statSync37, unlinkSync as unlinkSync8, writeFileSync as writeFileSync70 } from "fs";
586723
+ import { join as join184 } from "path";
586172
586724
  function parseMatrix(raw) {
586173
586725
  try {
586174
586726
  const m = JSON.parse(raw);
@@ -586236,20 +586788,20 @@ class TelegramMemory {
586236
586788
  this.keyProvider = opts.keyProvider ?? keychainKey;
586237
586789
  }
586238
586790
  get flagFile() {
586239
- return join182(this.opts.dir, "disabled");
586791
+ return join184(this.opts.dir, "disabled");
586240
586792
  }
586241
586793
  disabledByEnv() {
586242
586794
  const v = (this.env.TELEGRAM_MEMORY_DISABLED ?? "").trim().toLowerCase();
586243
586795
  return v === "1" || v === "true" || v === "yes";
586244
586796
  }
586245
586797
  isDisabled() {
586246
- return this.disabledByEnv() || existsSync123(this.flagFile);
586798
+ return this.disabledByEnv() || existsSync125(this.flagFile);
586247
586799
  }
586248
586800
  isOperator(fromId) {
586249
586801
  return typeof fromId === "number" && splitIds(this.env.TELEGRAM_OPERATOR_USER_IDS).includes(String(fromId));
586250
586802
  }
586251
586803
  matrix() {
586252
- const file = join182(this.opts.dir, "matrix.json");
586804
+ const file = join184(this.opts.dir, "matrix.json");
586253
586805
  let sig;
586254
586806
  try {
586255
586807
  const st = statSync37(file);
@@ -586261,7 +586813,7 @@ class TelegramMemory {
586261
586813
  }
586262
586814
  if (this.matrixCache?.sig === sig)
586263
586815
  return this.matrixCache.matrix;
586264
- const parsed = parseMatrix(readFileSync115(file, "utf8"));
586816
+ const parsed = parseMatrix(readFileSync116(file, "utf8"));
586265
586817
  if (parsed) {
586266
586818
  this.matrixCache = { sig, matrix: parsed };
586267
586819
  this.noteMatrix("ok");
@@ -586305,7 +586857,7 @@ class TelegramMemory {
586305
586857
  }
586306
586858
  ensureAudit() {
586307
586859
  if (!this.audit) {
586308
- this.audit = new AuditLog(join182(this.opts.dir, "audit.jsonl"), join182(this.opts.dir, "audit.salt"), this.clock, (n) => this.log(`audit: dropped ${n} byte(s) of a torn last line`));
586860
+ this.audit = new AuditLog(join184(this.opts.dir, "audit.jsonl"), join184(this.opts.dir, "audit.salt"), this.clock, (n) => this.log(`audit: dropped ${n} byte(s) of a torn last line`));
586309
586861
  }
586310
586862
  return this.audit;
586311
586863
  }
@@ -586432,7 +586984,7 @@ class TelegramMemory {
586432
586984
  const uid = String(ctx.fromId);
586433
586985
  const chat = String(ctx.chatId);
586434
586986
  const listed = splitIds(this.env.TELEGRAM_MEMORY_CHAT_IDS).includes(chat);
586435
- const hasState = existsSync123(this.opts.dir);
586987
+ const hasState = existsSync125(this.opts.dir);
586436
586988
  if (!listed && !hasState) {
586437
586989
  return "Memory is not enabled for this chat and nothing is stored, so there is nothing to change or erase.";
586438
586990
  }
@@ -586448,7 +587000,7 @@ class TelegramMemory {
586448
587000
  if (this.disabledByEnv()) {
586449
587001
  return "Memory is disabled by TELEGRAM_MEMORY_DISABLED in the bot environment. /memon cannot override it.";
586450
587002
  }
586451
- if (existsSync123(this.flagFile))
587003
+ if (existsSync125(this.flagFile))
586452
587004
  unlinkSync8(this.flagFile);
586453
587005
  this.auditEvent(uid, chat, "memon", "0", {}, "ok");
586454
587006
  return "Memory is on.";
@@ -586456,7 +587008,7 @@ class TelegramMemory {
586456
587008
  const now = this.clock();
586457
587009
  const given = arg.trim();
586458
587010
  if (!given) {
586459
- if (!existsSync123(join182(this.opts.dir, "memory.db.enc"))) {
587011
+ if (!existsSync125(join184(this.opts.dir, "memory.db.enc"))) {
586460
587012
  return "Nothing is stored, so there is nothing to erase.";
586461
587013
  }
586462
587014
  const code = String(randomInt(1e5, 1e6));
@@ -586545,53 +587097,53 @@ var init_formatters = () => {};
586545
587097
 
586546
587098
  // packages/telegram-bot/memory.ts
586547
587099
  import { homedir as homedir90 } from "os";
586548
- import { dirname as dirname81, join as join183 } from "path";
587100
+ import { dirname as dirname82, join as join185 } from "path";
586549
587101
  var DEFAULT_MEMORY_PATH;
586550
587102
  var init_memory3 = __esm(() => {
586551
- DEFAULT_MEMORY_PATH = join183(homedir90(), ".8gent", "bot-memory.json");
587103
+ DEFAULT_MEMORY_PATH = join185(homedir90(), ".8gent", "bot-memory.json");
586552
587104
  });
586553
587105
 
586554
587106
  // packages/telegram-bot/agent-mode.ts
586555
587107
  import { homedir as homedir91 } from "os";
586556
- import { join as join184 } from "path";
587108
+ import { join as join186 } from "path";
586557
587109
  var HOME3, LOOP_STATE, LEGACY_STATE, CONFIG_FILE2, RUN_PID_FILE, KNOWLEDGE_DIR;
586558
587110
  var init_agent_mode = __esm(() => {
586559
587111
  init_bun_flags();
586560
587112
  init_formatters();
586561
587113
  init_memory3();
586562
587114
  HOME3 = homedir91();
586563
- LOOP_STATE = join184(HOME3, "8gent-code/benchmarks/autoresearch/loop-state.json");
586564
- LEGACY_STATE = join184(HOME3, "iris-observatory/benchmarks/autoresearch/loop-state.json");
586565
- CONFIG_FILE2 = join184(HOME3, ".8gent/config.json");
586566
- RUN_PID_FILE = join184(HOME3, ".8gent/run.pid");
586567
- KNOWLEDGE_DIR = join184(HOME3, ".8gent/intelligence");
587115
+ LOOP_STATE = join186(HOME3, "8gent-code/benchmarks/autoresearch/loop-state.json");
587116
+ LEGACY_STATE = join186(HOME3, "iris-observatory/benchmarks/autoresearch/loop-state.json");
587117
+ CONFIG_FILE2 = join186(HOME3, ".8gent/config.json");
587118
+ RUN_PID_FILE = join186(HOME3, ".8gent/run.pid");
587119
+ KNOWLEDGE_DIR = join186(HOME3, ".8gent/intelligence");
586568
587120
  });
586569
587121
 
586570
587122
  // packages/telegram-bot/intelligence.ts
586571
587123
  import { homedir as homedir92 } from "os";
586572
- import { join as join185 } from "path";
587124
+ import { join as join187 } from "path";
586573
587125
  var HOME4, INTEL_DIR, REPOS_FILE, DIGEST_FILE;
586574
587126
  var init_intelligence = __esm(() => {
586575
587127
  HOME4 = homedir92();
586576
- INTEL_DIR = join185(HOME4, ".8gent/intelligence");
586577
- REPOS_FILE = join185(INTEL_DIR, "repos.json");
586578
- DIGEST_FILE = join185(INTEL_DIR, "latest-digest.json");
587128
+ INTEL_DIR = join187(HOME4, ".8gent/intelligence");
587129
+ REPOS_FILE = join187(INTEL_DIR, "repos.json");
587130
+ DIGEST_FILE = join187(INTEL_DIR, "latest-digest.json");
586579
587131
  });
586580
587132
 
586581
587133
  // packages/telegram-bot/commands.ts
586582
587134
  import { homedir as homedir93 } from "os";
586583
- import { join as join186 } from "path";
587135
+ import { join as join188 } from "path";
586584
587136
  var HOME5, LOOP_STATE2, LEGACY_STATE2, NIGHTLY_LOG, CONFIG_FILE3, RUN_PID_FILE2;
586585
587137
  var init_commands = __esm(() => {
586586
587138
  init_bun_flags();
586587
587139
  init_formatters();
586588
587140
  init_intelligence();
586589
587141
  HOME5 = homedir93();
586590
- LOOP_STATE2 = join186(HOME5, "8gent-code/benchmarks/autoresearch/loop-state.json");
586591
- LEGACY_STATE2 = join186(HOME5, "iris-observatory/benchmarks/autoresearch/loop-state.json");
586592
- NIGHTLY_LOG = join186(HOME5, ".8gent/nightly.log");
586593
- CONFIG_FILE3 = join186(HOME5, ".8gent/config.json");
586594
- RUN_PID_FILE2 = join186(HOME5, ".8gent/run.pid");
587142
+ LOOP_STATE2 = join188(HOME5, "8gent-code/benchmarks/autoresearch/loop-state.json");
587143
+ LEGACY_STATE2 = join188(HOME5, "iris-observatory/benchmarks/autoresearch/loop-state.json");
587144
+ NIGHTLY_LOG = join188(HOME5, ".8gent/nightly.log");
587145
+ CONFIG_FILE3 = join188(HOME5, ".8gent/config.json");
587146
+ RUN_PID_FILE2 = join188(HOME5, ".8gent/run.pid");
586595
587147
  });
586596
587148
 
586597
587149
  // packages/telegram-bot/live-dashboard.ts
@@ -587008,8 +587560,8 @@ function truncate2(text, max) {
587008
587560
  var MAX_MOBILE_LEN = 1800, MAX_CHUNK_LEN = 3800;
587009
587561
 
587010
587562
  // packages/telegram-bot/file-sender.ts
587011
- import { existsSync as existsSync124, statSync as statSync38 } from "fs";
587012
- import { basename as basename53 } from "path";
587563
+ import { existsSync as existsSync126, statSync as statSync38 } from "fs";
587564
+ import { basename as basename54 } from "path";
587013
587565
 
587014
587566
  class FileSender {
587015
587567
  token;
@@ -587092,7 +587644,7 @@ class FileSender {
587092
587644
  if (attachment.buffer)
587093
587645
  return attachment.buffer;
587094
587646
  if (attachment.path) {
587095
- if (!existsSync124(attachment.path))
587647
+ if (!existsSync126(attachment.path))
587096
587648
  return null;
587097
587649
  return await Bun.file(attachment.path).bytes().then((b) => Buffer.from(b));
587098
587650
  }
@@ -587104,7 +587656,7 @@ class FileSender {
587104
587656
  if (!stat.isFile())
587105
587657
  throw new Error(`file-sender: ${input} is not a file`);
587106
587658
  const bytes = await Bun.file(input).bytes();
587107
- return { buffer: Buffer.from(bytes), name: basename53(input) };
587659
+ return { buffer: Buffer.from(bytes), name: basename54(input) };
587108
587660
  }
587109
587661
  return { buffer: input, name: fallback };
587110
587662
  }
@@ -587121,8 +587673,8 @@ var init_file_sender = __esm(() => {
587121
587673
  });
587122
587674
 
587123
587675
  // packages/telegram-bot/session-store.ts
587124
- import { existsSync as existsSync125, mkdirSync as mkdirSync97, readFileSync as readFileSync116, writeFileSync as writeFileSync71 } from "fs";
587125
- import { dirname as dirname82 } from "path";
587676
+ import { existsSync as existsSync127, mkdirSync as mkdirSync97, readFileSync as readFileSync117, writeFileSync as writeFileSync71 } from "fs";
587677
+ import { dirname as dirname83 } from "path";
587126
587678
 
587127
587679
  class SessionStore2 {
587128
587680
  sessions = new Map;
@@ -587196,7 +587748,7 @@ class SessionStore2 {
587196
587748
  if (!this.persistPath)
587197
587749
  return;
587198
587750
  try {
587199
- mkdirSync97(dirname82(this.persistPath), { recursive: true });
587751
+ mkdirSync97(dirname83(this.persistPath), { recursive: true });
587200
587752
  const data = JSON.stringify({ version: 1, savedAt: Date.now(), sessions: Array.from(this.sessions.values()) }, null, 2);
587201
587753
  writeFileSync71(this.persistPath, data, "utf-8");
587202
587754
  } catch {}
@@ -587215,9 +587767,9 @@ class SessionStore2 {
587215
587767
  if (!this.persistPath)
587216
587768
  return;
587217
587769
  try {
587218
- if (!existsSync125(this.persistPath))
587770
+ if (!existsSync127(this.persistPath))
587219
587771
  return;
587220
- const raw = readFileSync116(this.persistPath, "utf-8");
587772
+ const raw = readFileSync117(this.persistPath, "utf-8");
587221
587773
  const parsed = JSON.parse(raw);
587222
587774
  if (!parsed?.sessions)
587223
587775
  return;
@@ -587745,7 +588297,7 @@ var init_telegram_bot = __esm(() => {
587745
588297
  });
587746
588298
 
587747
588299
  // packages/telegram-bot/boardroom.ts
587748
- import { spawn as spawn26 } from "child_process";
588300
+ import { spawn as spawn27 } from "child_process";
587749
588301
  function renderBoard(topic, rows, opts = {}) {
587750
588302
  const done = rows.filter((r) => r.status === "done").length;
587751
588303
  const lines = [];
@@ -587911,7 +588463,7 @@ function askVerdictViaClaude(cwd) {
587911
588463
  }
587912
588464
  function runClaude(args, cwd, signal) {
587913
588465
  return new Promise((resolve, reject) => {
587914
- const child = spawn26("claude", [...args, "--disallowedTools", ...OFFICER_DENIED_TOOLS], {
588466
+ const child = spawn27("claude", [...args, "--disallowedTools", ...OFFICER_DENIED_TOOLS], {
587915
588467
  cwd,
587916
588468
  stdio: ["ignore", "pipe", "pipe"]
587917
588469
  });
@@ -588215,16 +588767,16 @@ var init_flow_bot = __esm(() => {
588215
588767
  });
588216
588768
 
588217
588769
  // packages/telegram-bot/voice-mode.ts
588218
- import { spawn as spawn27 } from "child_process";
588770
+ import { spawn as spawn28 } from "child_process";
588219
588771
  import { createHash as createHash32 } from "crypto";
588220
- import { existsSync as existsSync126, mkdirSync as mkdirSync98, readFileSync as readFileSync117, writeFileSync as writeFileSync72 } from "fs";
588772
+ import { existsSync as existsSync128, mkdirSync as mkdirSync98, readFileSync as readFileSync118, writeFileSync as writeFileSync72 } from "fs";
588221
588773
  import { homedir as homedir94 } from "os";
588222
- import { dirname as dirname83, join as join187 } from "path";
588774
+ import { dirname as dirname84, join as join189 } from "path";
588223
588775
  function readVoiceState(path = VOICE_STATE_PATH) {
588224
- if (!existsSync126(path))
588776
+ if (!existsSync128(path))
588225
588777
  return { ...DEFAULT_STATE };
588226
588778
  try {
588227
- const parsed = JSON.parse(readFileSync117(path, "utf-8"));
588779
+ const parsed = JSON.parse(readFileSync118(path, "utf-8"));
588228
588780
  const notices = {};
588229
588781
  if (parsed?.groupNotices && typeof parsed.groupNotices === "object") {
588230
588782
  for (const [k, v] of Object.entries(parsed.groupNotices)) {
@@ -588248,7 +588800,7 @@ function writeVoiceState(enabled, path = VOICE_STATE_PATH) {
588248
588800
  groupNotices: readVoiceState(path).groupNotices ?? {}
588249
588801
  };
588250
588802
  try {
588251
- mkdirSync98(dirname83(path), { recursive: true });
588803
+ mkdirSync98(dirname84(path), { recursive: true });
588252
588804
  writeFileSync72(path, `${JSON.stringify(state, null, 2)}
588253
588805
  `, "utf-8");
588254
588806
  } catch (err) {
@@ -588267,7 +588819,7 @@ function recordGroupNotice(chatId, path = VOICE_STATE_PATH) {
588267
588819
  groupNotices: { ...prev.groupNotices ?? {}, [chatId]: groupNoticeHash() }
588268
588820
  };
588269
588821
  try {
588270
- mkdirSync98(dirname83(path), { recursive: true });
588822
+ mkdirSync98(dirname84(path), { recursive: true });
588271
588823
  writeFileSync72(path, `${JSON.stringify(state, null, 2)}
588272
588824
  `, "utf-8");
588273
588825
  } catch (err) {
@@ -588291,7 +588843,7 @@ function decideVoice(markdown, opts) {
588291
588843
  }
588292
588844
  async function sendVoiceNote(opts) {
588293
588845
  const bin = opts.bin ?? KITTENTTS_BIN;
588294
- if (!existsSync126(bin))
588846
+ if (!existsSync128(bin))
588295
588847
  return { sent: false, reason: "kittentts-telegram not installed" };
588296
588848
  const args = ["--voice", opts.voice];
588297
588849
  if (opts.explicitChat !== undefined) {
@@ -588303,7 +588855,7 @@ async function sendVoiceNote(opts) {
588303
588855
  if (opts.threadId !== undefined) {
588304
588856
  let supportsThread = false;
588305
588857
  try {
588306
- supportsThread = readFileSync117(bin, "utf-8").includes("--thread)");
588858
+ supportsThread = readFileSync118(bin, "utf-8").includes("--thread)");
588307
588859
  } catch {}
588308
588860
  if (!supportsThread)
588309
588861
  return { sent: false, reason: "TTS bridge cannot address a topic" };
@@ -588321,7 +588873,7 @@ async function sendVoiceNote(opts) {
588321
588873
  if (opts.caption)
588322
588874
  args.push("--caption", opts.caption);
588323
588875
  return new Promise((resolve) => {
588324
- const child = spawn27(bin, args, { stdio: ["pipe", "ignore", "pipe"] });
588876
+ const child = spawn28(bin, args, { stdio: ["pipe", "ignore", "pipe"] });
588325
588877
  let stderr = "";
588326
588878
  child.stderr?.on("data", (d) => {
588327
588879
  stderr += String(d);
@@ -588331,11 +588883,11 @@ async function sendVoiceNote(opts) {
588331
588883
  child.stdin?.end(opts.text);
588332
588884
  });
588333
588885
  }
588334
- function readConfiguredChatId(envPath = join187(homedir94(), ".claude", ".env")) {
588335
- if (!existsSync126(envPath))
588886
+ function readConfiguredChatId(envPath = join189(homedir94(), ".claude", ".env")) {
588887
+ if (!existsSync128(envPath))
588336
588888
  return null;
588337
588889
  try {
588338
- for (const line of readFileSync117(envPath, "utf-8").split(`
588890
+ for (const line of readFileSync118(envPath, "utf-8").split(`
588339
588891
  `)) {
588340
588892
  const m = line.match(/^\s*(?:export\s+)?TELEGRAM_CHAT_ID\s*=\s*["']?([^"'#\s]+)/);
588341
588893
  if (m)
@@ -588346,8 +588898,8 @@ function readConfiguredChatId(envPath = join187(homedir94(), ".claude", ".env"))
588346
588898
  }
588347
588899
  var R10_TRANSIT_NOTICE = "Speech-to-text runs locally on the operator's machine (ffmpeg plus whisper-cli, no cloud STT). Audio from the Telegram path reaches the machine through Telegram's servers: a voice note the operator sends is stored and relayed by Telegram, and our spoken reply travels back the same way. Bot chats are not end-to-end encrypted. That transit is the channel the operator chose, it is not our transcription, and it applies only to the operator's own private chat. Listen-mode notes, when built, are never captured from the Telegram path. No audio or transcript is sent to any rented model API.", R10_GROUP_NOTICE = "In this group, voice notes from the operator that reply to this bot are transcribed on the operator's machine (ffmpeg plus whisper-cli, no cloud STT). Everything posted in this group, including those voice notes and our spoken replies, is visible to every member and is stored and relayed by Telegram. Group chats are not end-to-end encrypted. Voice notes from anyone else are ignored: they are not downloaded or transcribed. The transcript is never posted here. No audio or transcript is sent to any rented model API.", VOICE_STATE_PATH, KITTENTTS_BIN, MAX_SPOKEN_CHARS = 600, DEFAULT_STATE;
588348
588900
  var init_voice_mode = __esm(() => {
588349
- VOICE_STATE_PATH = process.env.EIGHT_TG_VOICE_STATE || join187(homedir94(), ".8gent", "telegram-voice.json");
588350
- KITTENTTS_BIN = join187(homedir94(), ".claude", "bin", "kittentts-telegram");
588901
+ VOICE_STATE_PATH = process.env.EIGHT_TG_VOICE_STATE || join189(homedir94(), ".8gent", "telegram-voice.json");
588902
+ KITTENTTS_BIN = join189(homedir94(), ".claude", "bin", "kittentts-telegram");
588351
588903
  DEFAULT_STATE = { enabled: false, updatedAt: "", groupNotices: {} };
588352
588904
  });
588353
588905
 
@@ -588389,11 +588941,11 @@ var init_types9 = __esm(() => {
588389
588941
  });
588390
588942
 
588391
588943
  // packages/voice/model-manager.ts
588392
- import { existsSync as existsSync127, mkdirSync as mkdirSync99, realpathSync as realpathSync37, unlinkSync as unlinkSync9 } from "fs";
588944
+ import { existsSync as existsSync129, mkdirSync as mkdirSync99, realpathSync as realpathSync37, unlinkSync as unlinkSync9 } from "fs";
588393
588945
  import { homedir as homedir95 } from "os";
588394
- import { join as join188, sep as sep31 } from "path";
588946
+ import { join as join190, sep as sep31 } from "path";
588395
588947
  function resolveWhisperModel(opts = {}) {
588396
- const exists = opts.exists ?? existsSync127;
588948
+ const exists = opts.exists ?? existsSync129;
588397
588949
  const dirs = [
588398
588950
  resolveModelsPath(opts.modelsDir ?? "~/.8gent/models/whisper"),
588399
588951
  ...opts.extraDirs ?? []
@@ -588403,7 +588955,7 @@ function resolveWhisperModel(opts = {}) {
588403
588955
  for (const m of WHISPER_MODEL_RANK) {
588404
588956
  if (!english && m.filename.endsWith(".en.bin"))
588405
588957
  continue;
588406
- const path = join188(dir, m.filename);
588958
+ const path = join190(dir, m.filename);
588407
588959
  if (!exists(path))
588408
588960
  continue;
588409
588961
  if (!opts.exists && !isInside2(dir, path))
@@ -588432,7 +588984,7 @@ function missingWhisperModelMessage(modelsDir = "~/.8gent/models/whisper") {
588432
588984
  }
588433
588985
  function resolveModelsPath(configPath) {
588434
588986
  if (configPath.startsWith("~")) {
588435
- return join188(homedir95(), configPath.slice(1));
588987
+ return join190(homedir95(), configPath.slice(1));
588436
588988
  }
588437
588989
  return configPath;
588438
588990
  }
@@ -588450,7 +589002,7 @@ var init_model_manager = __esm(() => {
588450
589002
  });
588451
589003
 
588452
589004
  // packages/voice/spoken-draft.ts
588453
- function basename54(p) {
589005
+ function basename55(p) {
588454
589006
  const parts = p.replace(/[/\\]+$/, "").split(/[/\\]/);
588455
589007
  return parts[parts.length - 1] || p;
588456
589008
  }
@@ -588466,7 +589018,7 @@ There is a code block on screen.
588466
589018
  t = t.replace(/\b(?:https?|ftp):\/\/[^\s)>\]]+/gi, "a link");
588467
589019
  t = t.replace(/\bwww\.[^\s)>\]]+/gi, "a link");
588468
589020
  t = t.replace(/(?:~|\.{1,2}|[A-Za-z]:)?(?:[\\/][\w.@+-]+){2,}[\\/]?(?::\d+(?::\d+)?)?/g, (m) => {
588469
- const name = basename54(m.replace(/:\d+(?::\d+)?$/, ""));
589021
+ const name = basename55(m.replace(/:\d+(?::\d+)?$/, ""));
588470
589022
  return name ? `the file ${name}` : "a file";
588471
589023
  });
588472
589024
  t = t.replace(/`([^`\n]+)`/g, "$1");
@@ -588597,22 +589149,22 @@ var init_voice_ack = __esm(() => {
588597
589149
  });
588598
589150
 
588599
589151
  // packages/daemon/task-registry.ts
588600
- import { existsSync as existsSync128, mkdirSync as mkdirSync100, readFileSync as readFileSync118, writeFileSync as writeFileSync73 } from "fs";
588601
- import { join as join189 } from "path";
589152
+ import { existsSync as existsSync130, mkdirSync as mkdirSync100, readFileSync as readFileSync119, writeFileSync as writeFileSync73 } from "fs";
589153
+ import { join as join191 } from "path";
588602
589154
  function tasksPath() {
588603
- return join189(getDataDir(), "tasks.json");
589155
+ return join191(getDataDir(), "tasks.json");
588604
589156
  }
588605
589157
  function ensureDir8() {
588606
589158
  const dir = getDataDir();
588607
- if (!existsSync128(dir))
589159
+ if (!existsSync130(dir))
588608
589160
  mkdirSync100(dir, { recursive: true });
588609
589161
  }
588610
589162
  function load3() {
588611
589163
  if (loaded)
588612
589164
  return;
588613
589165
  try {
588614
- if (existsSync128(tasksPath())) {
588615
- tasks = JSON.parse(readFileSync118(tasksPath(), "utf-8"));
589166
+ if (existsSync130(tasksPath())) {
589167
+ tasks = JSON.parse(readFileSync119(tasksPath(), "utf-8"));
588616
589168
  }
588617
589169
  } catch {
588618
589170
  tasks = [];
@@ -588676,14 +589228,14 @@ var init_task_registry = __esm(() => {
588676
589228
  });
588677
589229
 
588678
589230
  // packages/daemon/cos-router.ts
588679
- import { execSync as execSync5 } from "child_process";
588680
- import { existsSync as existsSync129, readFileSync as readFileSync119, writeFileSync as writeFileSync74 } from "fs";
588681
- import { join as join190 } from "path";
589231
+ import { execSync as execSync6 } from "child_process";
589232
+ import { existsSync as existsSync131, readFileSync as readFileSync120, writeFileSync as writeFileSync74 } from "fs";
589233
+ import { join as join192 } from "path";
588682
589234
  function goalsPath() {
588683
- return join190(getDataDir(), "goals.json");
589235
+ return join192(getDataDir(), "goals.json");
588684
589236
  }
588685
589237
  function cosWorkspace() {
588686
- return join190(getDataDir(), "workspace");
589238
+ return join192(getDataDir(), "workspace");
588687
589239
  }
588688
589240
 
588689
589241
  class CoSRouter {
@@ -588758,12 +589310,12 @@ Error: ${payload.error}`);
588758
589310
  ID: \`${task.id}\`
588759
589311
  Repo: ${repo}
588760
589312
  Priority: ${priority}`);
588761
- const repoPath = join190(cosWorkspace(), repo);
589313
+ const repoPath = join192(cosWorkspace(), repo);
588762
589314
  let issueUrl = "";
588763
589315
  let issueNumber = 0;
588764
- if (existsSync129(repoPath)) {
589316
+ if (existsSync131(repoPath)) {
588765
589317
  try {
588766
- const result = execSync5(`cd "${repoPath}" && gh issue create --title "${description.replace(/"/g, "\\\"")}" --body "Delegated by CEO via Telegram.
589318
+ const result = execSync6(`cd "${repoPath}" && gh issue create --title "${description.replace(/"/g, "\\\"")}" --body "Delegated by CEO via Telegram.
588767
589319
 
588768
589320
  Task ID: ${task.id}
588769
589321
  Priority: ${priority}"`, { encoding: "utf-8", timeout: 15000 }).trim();
@@ -588957,8 +589509,8 @@ Total: ${goals.length} objectives`);
588957
589509
  }
588958
589510
  loadGoals() {
588959
589511
  try {
588960
- if (existsSync129(goalsPath())) {
588961
- return JSON.parse(readFileSync119(goalsPath(), "utf-8"));
589512
+ if (existsSync131(goalsPath())) {
589513
+ return JSON.parse(readFileSync120(goalsPath(), "utf-8"));
588962
589514
  }
588963
589515
  } catch {}
588964
589516
  return [];
@@ -588974,20 +589526,20 @@ var init_cos_router = __esm(() => {
588974
589526
  });
588975
589527
 
588976
589528
  // packages/daemon/telegram-bridge.ts
588977
- import { spawn as spawn28 } from "child_process";
589529
+ import { spawn as spawn29 } from "child_process";
588978
589530
  import { createHash as createHash33 } from "crypto";
588979
589531
  import {
588980
589532
  appendFileSync as appendFileSync28,
588981
589533
  chmodSync as chmodSync9,
588982
- existsSync as existsSync130,
589534
+ existsSync as existsSync132,
588983
589535
  mkdirSync as mkdirSync101,
588984
- readFileSync as readFileSync120,
589536
+ readFileSync as readFileSync121,
588985
589537
  statSync as statSync39,
588986
589538
  unlinkSync as unlinkSync10,
588987
589539
  writeFileSync as writeFileSync75
588988
589540
  } from "fs";
588989
589541
  import { tmpdir as tmpdir19 } from "os";
588990
- import { dirname as dirname84, join as join191 } from "path";
589542
+ import { dirname as dirname85, join as join193 } from "path";
588991
589543
  function observeUnauthorized(update) {
588992
589544
  try {
588993
589545
  const u = update;
@@ -589001,9 +589553,9 @@ function observeUnauthorized(update) {
589001
589553
  if (statSync39(OBSERVED_LOG).size > OBSERVED_MAX_BYTES)
589002
589554
  return;
589003
589555
  } catch {
589004
- mkdirSync101(dirname84(OBSERVED_LOG), { recursive: true, mode: 448 });
589556
+ mkdirSync101(dirname85(OBSERVED_LOG), { recursive: true, mode: 448 });
589005
589557
  }
589006
- if (!existsSync130(OBSERVED_LOG))
589558
+ if (!existsSync132(OBSERVED_LOG))
589007
589559
  writeFileSync75(OBSERVED_LOG, "", { mode: 384 });
589008
589560
  chmodSync9(OBSERVED_LOG, 384);
589009
589561
  appendFileSync28(OBSERVED_LOG, `${JSON.stringify({
@@ -589020,7 +589572,7 @@ function observeUnauthorized(update) {
589020
589572
  } catch {}
589021
589573
  }
589022
589574
  function sessionStorePath() {
589023
- return process.env.EIGHT_TG_SESSIONS || join191(getDataDir(), "telegram-sessions.json");
589575
+ return process.env.EIGHT_TG_SESSIONS || join193(getDataDir(), "telegram-sessions.json");
589024
589576
  }
589025
589577
  function bindChatThread(chatId, threadId) {
589026
589578
  chatThreads.clear();
@@ -589071,12 +589623,12 @@ async function tgSend(token, chatId, text, parseMode = "Markdown") {
589071
589623
  }
589072
589624
  function whisperModelDirs() {
589073
589625
  return {
589074
- modelsDir: join191(getDataDir(), "models", "whisper"),
589075
- extraDirs: [join191(resolveHome(), "models")]
589626
+ modelsDir: join193(getDataDir(), "models", "whisper"),
589627
+ extraDirs: [join193(resolveHome(), "models")]
589076
589628
  };
589077
589629
  }
589078
589630
  function cosPoolWorkspace() {
589079
- return join191(getDataDir(), "workspace");
589631
+ return join193(getDataDir(), "workspace");
589080
589632
  }
589081
589633
  function localWhisperModel() {
589082
589634
  return resolveWhisperModel(whisperModelDirs())?.path ?? null;
@@ -589115,7 +589667,7 @@ function runAsync(cmd, args, timeoutMs) {
589115
589667
  pid: child.pid
589116
589668
  });
589117
589669
  };
589118
- const child = spawn28(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
589670
+ const child = spawn29(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
589119
589671
  const timer = setTimeout(() => {
589120
589672
  child.kill("SIGKILL");
589121
589673
  finish(null);
@@ -589150,13 +589702,13 @@ async function transcribeVoice(token, fileId) {
589150
589702
  const audioUrl = `https://api.telegram.org/file/bot${token}/${fileData.result.file_path}`;
589151
589703
  const audioRes = await fetch(audioUrl);
589152
589704
  const audioBuffer = await audioRes.arrayBuffer();
589153
- const stem = join191(tmpdir19(), `tg-voice-${Date.now()}-${Math.floor(performance.now())}`);
589705
+ const stem = join193(tmpdir19(), `tg-voice-${Date.now()}-${Math.floor(performance.now())}`);
589154
589706
  const ogg = `${stem}.ogg`;
589155
589707
  const wav = `${stem}.wav`;
589156
589708
  try {
589157
589709
  writeFileSync75(ogg, Buffer.from(audioBuffer));
589158
589710
  const conv = await runAsync("ffmpeg", ["-y", "-i", ogg, "-ar", "16000", "-ac", "1", wav], 30000);
589159
- if (conv.status !== 0 || !existsSync130(wav)) {
589711
+ if (conv.status !== 0 || !existsSync132(wav)) {
589160
589712
  console.error(subprocessFailure("ffmpeg", conv.status, conv.stderr));
589161
589713
  return "[voice message received - could not decode the audio]";
589162
589714
  }
@@ -589173,7 +589725,7 @@ async function transcribeVoice(token, fileId) {
589173
589725
  } finally {
589174
589726
  for (const f of [ogg, wav]) {
589175
589727
  try {
589176
- if (existsSync130(f))
589728
+ if (existsSync132(f))
589177
589729
  unlinkSync10(f);
589178
589730
  } catch {}
589179
589731
  }
@@ -589343,7 +589895,7 @@ function localSpokenModel(env, fetchImpl = fetch, json = false) {
589343
589895
  }
589344
589896
  function assertNotAiJamesToken(token, env = process.env, readRef = (p) => {
589345
589897
  try {
589346
- return readFileSync120(p, "utf8");
589898
+ return readFileSync121(p, "utf8");
589347
589899
  } catch {
589348
589900
  return null;
589349
589901
  }
@@ -589423,7 +589975,7 @@ class TelegramDaemonBridge {
589423
589975
  get memory() {
589424
589976
  if (!this.memoryStore) {
589425
589977
  this.memoryStore = new TelegramMemory({
589426
- dir: join191(getDataDir(), "memory"),
589978
+ dir: join193(getDataDir(), "memory"),
589427
589979
  env: this.config.env ?? process.env,
589428
589980
  scrubSessions: (uid) => this.scrubSessionTurns(uid)
589429
589981
  });
@@ -589802,8 +590354,8 @@ What do we work on next?`);
589802
590354
  observeVoiceDrop(message) {
589803
590355
  try {
589804
590356
  const path = this.config.observeLogPath ?? OBSERVED_LOG;
589805
- mkdirSync101(dirname84(path), { recursive: true, mode: 448 });
589806
- if (!existsSync130(path))
590357
+ mkdirSync101(dirname85(path), { recursive: true, mode: 448 });
590358
+ if (!existsSync132(path))
589807
590359
  writeFileSync75(path, "", { mode: 384 });
589808
590360
  chmodSync9(path, 384);
589809
590361
  appendFileSync28(path, `${JSON.stringify({
@@ -590814,7 +591366,7 @@ var init_telegram_bridge = __esm(() => {
590814
591366
  init_input_gate();
590815
591367
  init_notifications();
590816
591368
  init_voice_ack();
590817
- OBSERVED_LOG = join191(resolveHome(), ".8gent", "telegram-observed.jsonl");
591369
+ OBSERVED_LOG = join193(resolveHome(), ".8gent", "telegram-observed.jsonl");
590818
591370
  OBSERVED_MAX_BYTES = 5 * 1024 * 1024;
590819
591371
  MULTI_STEP_ENABLED = process.env.EIGHT_TG_LEGACY !== "1";
590820
591372
  chatThreads = new Map;
@@ -590857,7 +591409,7 @@ var init_telegram_bridge = __esm(() => {
590857
591409
  });
590858
591410
 
590859
591411
  // packages/daemon/index.ts
590860
- import { appendFileSync as appendFileSync29, existsSync as existsSync131, mkdirSync as mkdirSync102 } from "fs";
591412
+ import { appendFileSync as appendFileSync29, existsSync as existsSync133, mkdirSync as mkdirSync102 } from "fs";
590861
591413
  async function loadConfig2() {
590862
591414
  const defaults = {
590863
591415
  port: PORT,
@@ -590882,7 +591434,7 @@ async function loadConfig2() {
590882
591434
  }
590883
591435
  }
590884
591436
  function setupLogging() {
590885
- if (!existsSync131(DATA_DIR5)) {
591437
+ if (!existsSync133(DATA_DIR5)) {
590886
591438
  mkdirSync102(DATA_DIR5, { recursive: true });
590887
591439
  }
590888
591440
  const events = [
@@ -591186,7 +591738,7 @@ var init_daemon = __esm(() => {
591186
591738
  });
591187
591739
 
591188
591740
  // packages/daemon/service.ts
591189
- import { existsSync as existsSync132, mkdirSync as mkdirSync103, rmSync as rmSync19, writeFileSync as writeFileSync76 } from "fs";
591741
+ import { existsSync as existsSync134, mkdirSync as mkdirSync103, rmSync as rmSync19, writeFileSync as writeFileSync76 } from "fs";
591190
591742
  import * as os65 from "os";
591191
591743
  import * as path139 from "path";
591192
591744
  function paths(ctx) {
@@ -591345,7 +591897,7 @@ async function serviceStatus(ctx) {
591345
591897
  const query = backend.statusQuery(ctx);
591346
591898
  const res = await exec4(query.kind === "powershell" ? powershellArgv(query.script) : query.argv);
591347
591899
  const definition = backend.definitionPath(ctx);
591348
- return backend.parseStatus(res, definition !== null && existsSync132(definition));
591900
+ return backend.parseStatus(res, definition !== null && existsSync134(definition));
591349
591901
  }
591350
591902
  async function runOperation(op, ctx, log = console.log) {
591351
591903
  if (op !== "uninstall") {
@@ -592308,11 +592860,11 @@ var init_install = __esm(() => {
592308
592860
  });
592309
592861
 
592310
592862
  // packages/eight/self-update.ts
592311
- import { spawn as spawn29 } from "child_process";
592863
+ import { spawn as spawn30 } from "child_process";
592312
592864
  import { createHash as createHash36, createPublicKey as createPublicKey2, verify as cryptoVerify, randomBytes as randomBytes18 } from "crypto";
592313
- import { chmodSync as chmodSync10, existsSync as existsSync136, mkdtempSync as mkdtempSync12, renameSync as renameSync19, rmSync as rmSync21, writeFileSync as writeFileSync81 } from "fs";
592865
+ import { chmodSync as chmodSync10, existsSync as existsSync138, mkdtempSync as mkdtempSync12, renameSync as renameSync19, rmSync as rmSync21, writeFileSync as writeFileSync81 } from "fs";
592314
592866
  import { tmpdir as tmpdir20 } from "os";
592315
- import { join as join195, resolve as resolve76 } from "path";
592867
+ import { join as join197, resolve as resolve78 } from "path";
592316
592868
  import { fileURLToPath as fileURLToPath6 } from "url";
592317
592869
  function parseVersion(v) {
592318
592870
  const m = /^v?(\d+)\.(\d+)\.(\d+)$/.exec(v.trim());
@@ -592344,7 +592896,7 @@ function detectChannel(p) {
592344
592896
  return "binary";
592345
592897
  if (/[\\/]node_modules[\\/]/.test(p.modulePath))
592346
592898
  return "npm";
592347
- const hasGit = p.isGitCheckout ?? ((dir) => existsSync136(`${dir}/.git`));
592899
+ const hasGit = p.isGitCheckout ?? ((dir) => existsSync138(`${dir}/.git`));
592348
592900
  const parts = p.modulePath.replace(/^file:\/\//, "").split(/[\\/]/);
592349
592901
  for (let i = parts.length - 1;i > 0; i--) {
592350
592902
  if (hasGit(parts.slice(0, i).join("/") || "/"))
@@ -592585,7 +593137,7 @@ function npmHint(spec, prefix, ignoreScripts = false) {
592585
593137
  }
592586
593138
  function defaultRun2(cmd, args, opts) {
592587
593139
  return new Promise((resolve) => {
592588
- const p = spawn29(cmd, args, { stdio: "inherit", shell: opts.shell });
593140
+ const p = spawn30(cmd, args, { stdio: "inherit", shell: opts.shell });
592589
593141
  p.on("exit", (code) => resolve(code ?? 1));
592590
593142
  p.on("error", () => resolve(127));
592591
593143
  });
@@ -592604,7 +593156,7 @@ function probeVersionWithTimeout(file, timeoutMs = PROBE_TIMEOUT_MS3) {
592604
593156
  };
592605
593157
  let p;
592606
593158
  try {
592607
- p = spawn29(file, ["--version"], { stdio: ["ignore", "pipe", "ignore"] });
593159
+ p = spawn30(file, ["--version"], { stdio: ["ignore", "pipe", "ignore"] });
592608
593160
  } catch {
592609
593161
  finish("");
592610
593162
  return;
@@ -592650,13 +593202,13 @@ function swapInto(staged, target, platform) {
592650
593202
  } catch {
592651
593203
  old = `${target}.old-${randomBytes18(4).toString("hex")}`;
592652
593204
  }
592653
- const hadTarget = existsSync136(target);
593205
+ const hadTarget = existsSync138(target);
592654
593206
  if (hadTarget)
592655
593207
  renameSync19(target, old);
592656
593208
  try {
592657
593209
  renameSync19(staged, target);
592658
593210
  } catch (err) {
592659
- if (hadTarget && !existsSync136(target))
593211
+ if (hadTarget && !existsSync138(target))
592660
593212
  renameSync19(old, target);
592661
593213
  throw err;
592662
593214
  }
@@ -592694,9 +593246,9 @@ async function updateNpmFromRelease(o, rel, platform) {
592694
593246
  if (actual !== expected)
592695
593247
  return `checksum mismatch for ${name} (expected ${expected}, got ${actual}); nothing changed`;
592696
593248
  o.log(`SHA256 matches SHA256SUMS: ${actual}`);
592697
- const dir = mkdtempSync12(join195(resolve76(o.tmpDir ?? tmpdir20()), "8gent-update-"));
593249
+ const dir = mkdtempSync12(join197(resolve78(o.tmpDir ?? tmpdir20()), "8gent-update-"));
592698
593250
  try {
592699
- const file = join195(dir, name);
593251
+ const file = join197(dir, name);
592700
593252
  writeFileSync81(file, bytes, { flag: "wx", mode: 384 });
592701
593253
  o.log(`Installing with npm, package scripts off: npm install -g ${file} --ignore-scripts`);
592702
593254
  const code = await runNpmInstall(o, rel.version, platform, file);
@@ -592854,7 +593406,7 @@ var init_changelog_view = __esm(() => {
592854
593406
 
592855
593407
  // packages/eight/source-update.ts
592856
593408
  import { execFile as execFile6 } from "child_process";
592857
- import { existsSync as existsSync137, realpathSync as realpathSync39, statSync as statSync41 } from "fs";
593409
+ import { existsSync as existsSync139, realpathSync as realpathSync39, statSync as statSync41 } from "fs";
592858
593410
  import { homedir as homedir97 } from "os";
592859
593411
  import * as nodePath from "path";
592860
593412
  function scrubbedEnv2(base) {
@@ -592953,7 +593505,7 @@ function modulePathToFs(modulePath) {
592953
593505
  }
592954
593506
  return s;
592955
593507
  }
592956
- function findCheckoutRoot(modulePath, platform, hasGit = (d) => existsSync137(lib(platform).join(d, ".git"))) {
593508
+ function findCheckoutRoot(modulePath, platform, hasGit = (d) => existsSync139(lib(platform).join(d, ".git"))) {
592957
593509
  const p = lib(platform);
592958
593510
  const fsPath = modulePathToFs(modulePath);
592959
593511
  let dir = p.dirname(platform === "win32" ? fsPath.replace(/\//g, "\\") : fsPath);
@@ -592969,7 +593521,7 @@ function findCheckoutRoot(modulePath, platform, hasGit = (d) => existsSync137(li
592969
593521
  }
592970
593522
  function findBrowserCheckout(o) {
592971
593523
  const p = lib(o.platform);
592972
- const hasGit = o.hasGit ?? ((d) => existsSync137(p.join(d, ".git")));
593524
+ const hasGit = o.hasGit ?? ((d) => existsSync139(p.join(d, ".git")));
592973
593525
  const looked = [];
592974
593526
  let note;
592975
593527
  const cands = [];
@@ -593272,7 +593824,7 @@ async function runSourceUpdate(deps, opts, report) {
593272
593824
  git,
593273
593825
  bun: bun ?? "bun",
593274
593826
  platform,
593275
- fileExists: deps.fileExists ?? ((f) => existsSync137(f)),
593827
+ fileExists: deps.fileExists ?? ((f) => existsSync139(f)),
593276
593828
  now: deps.now ?? (() => new Date),
593277
593829
  baseEnv: env,
593278
593830
  forgeHost: env.EIGHT_FORGE_HOST,
@@ -593759,122 +594311,6 @@ var init_read_hidden = __esm(() => {
593759
594311
  MAX_PIPED_BYTES = 64 * 1024;
593760
594312
  });
593761
594313
 
593762
- // apps/tui/src/lib/external-agent-runner.ts
593763
- import { execSync as execSync6, spawn as spawn30 } from "child_process";
593764
- function getPreset(id) {
593765
- return EXTERNAL_AGENT_PRESETS[id.toLowerCase()] ?? null;
593766
- }
593767
- function isInstalled(preset) {
593768
- try {
593769
- execSync6(`command -v "${preset.command}"`, {
593770
- stdio: "ignore",
593771
- timeout: 1500
593772
- });
593773
- return true;
593774
- } catch {
593775
- return false;
593776
- }
593777
- }
593778
- var stripAnsi = (s) => s.replace(/\u001B\[[0-9;?]*[a-zA-Z]/g, "").replace(/\u001B\][^\u0007]*\u0007/g, ""), EXTERNAL_AGENT_PRESETS;
593779
- var init_external_agent_runner = __esm(() => {
593780
- init_shell();
593781
- EXTERNAL_AGENT_PRESETS = {
593782
- claude: {
593783
- id: "claude",
593784
- label: "Sparring",
593785
- command: "claude",
593786
- promptMode: "flag",
593787
- flagName: "-p",
593788
- args: [],
593789
- timeoutMs: 120000,
593790
- parseStdout: stripAnsi,
593791
- homepage: "https://docs.claude.com/en/docs/claude-code",
593792
- preferWindow: true,
593793
- install: {
593794
- command: "npm install -g --prefix=$HOME/.npm-global @anthropic-ai/claude-code",
593795
- notes: 'Binary at ~/.npm-global/bin/claude. If `claude` isn\'t on PATH after install, add `export PATH="$HOME/.npm-global/bin:$PATH"` to your shell rc. Then run `claude` once outside the TUI to authenticate with Anthropic.'
593796
- }
593797
- },
593798
- codex: {
593799
- id: "codex",
593800
- label: "OpenAI Codex",
593801
- command: "codex",
593802
- promptMode: "arg",
593803
- args: ["exec"],
593804
- timeoutMs: 120000,
593805
- parseStdout: stripAnsi,
593806
- homepage: "https://github.com/openai/codex",
593807
- preferWindow: true,
593808
- install: {
593809
- command: "npm install -g --prefix=$HOME/.npm-global @openai/codex",
593810
- notes: "Binary at ~/.npm-global/bin/codex. Add `~/.npm-global/bin` to PATH if needed. Requires `export OPENAI_API_KEY=sk-...` before /spawn."
593811
- }
593812
- },
593813
- hermes: {
593814
- id: "hermes",
593815
- label: "Hermes Agent",
593816
- command: "hermes",
593817
- preferWindow: true,
593818
- promptMode: "flag",
593819
- flagName: "-z",
593820
- args: [],
593821
- timeoutMs: 120000,
593822
- parseStdout: stripAnsi,
593823
- homepage: "https://github.com/NousResearch/hermes-agent",
593824
- install: {
593825
- command: "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash -s -- --skip-setup --no-venv",
593826
- notes: "Hermes needs Python \u2265 3.11 (anaconda's default 3.10 won't work; use pyenv or brew install python@3.11). Installer symlinks `hermes` into ~/.local/bin; add it to PATH if needed. After install, run `hermes setup` or `hermes model` outside the TUI to configure a provider. Without that, /spawn'd Hermes tabs will fail with auth errors (Bedrock is the default provider)."
593827
- }
593828
- },
593829
- openclaw: {
593830
- id: "openclaw",
593831
- label: "OpenClaw",
593832
- command: "openclaw",
593833
- preferWindow: true,
593834
- promptMode: "arg",
593835
- args: ["run", "--headless"],
593836
- timeoutMs: 120000,
593837
- parseStdout: stripAnsi,
593838
- homepage: "https://github.com/openclaw/openclaw",
593839
- install: {
593840
- command: "npm install -g --prefix=$HOME/.npm-global openclaw@latest",
593841
- notes: "Binary at ~/.npm-global/bin/openclaw. Add `~/.npm-global/bin` to PATH if needed. After install run `openclaw onboard` outside the TUI to set up the gateway, workspace, and skills. (8gent now provides a managed Node 22 runtime automatically when needed; no separate nvm step required.)"
593842
- },
593843
- requiresNodeVersion: "22.14.0"
593844
- },
593845
- pi: {
593846
- preferWindow: true,
593847
- id: "pi",
593848
- label: "Pi (pi-mono)",
593849
- command: "pi",
593850
- promptMode: "flag",
593851
- flagName: "-p",
593852
- args: [],
593853
- timeoutMs: 120000,
593854
- parseStdout: stripAnsi,
593855
- homepage: "https://pi.dev",
593856
- install: {
593857
- command: "npm install -g --prefix=$HOME/.npm-global @mariozechner/pi-coding-agent",
593858
- notes: "Binary at ~/.npm-global/bin/pi. Add `~/.npm-global/bin` to PATH if needed. Default provider is Google (Gemini). Set GEMINI_API_KEY, or override with --provider/--model and the matching API key env var (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY)."
593859
- }
593860
- },
593861
- "8gent": {
593862
- id: "8gent",
593863
- label: "8gent (nested)",
593864
- command: "8gent",
593865
- promptMode: "arg",
593866
- args: ["run"],
593867
- timeoutMs: 180000,
593868
- parseStdout: stripAnsi,
593869
- homepage: "https://8gent.dev",
593870
- install: {
593871
- command: "npm install -g --prefix=$HOME/.npm-global @8gi-foundation/8gent-code --force",
593872
- notes: "Binary at ~/.npm-global/bin/8gent. --force overwrites stale `8` / `8gent` / `8gent-code` bin symlinks (npm 9+ EEXIST). Add `~/.npm-global/bin` to PATH if not already."
593873
- }
593874
- }
593875
- };
593876
- });
593877
-
593878
594314
  // packages/install-runner/install-runner.ts
593879
594315
  function planInstallRun(args) {
593880
594316
  const { preset } = args;
@@ -595248,15 +595684,15 @@ var init_companion = __esm(() => {
595248
595684
  });
595249
595685
 
595250
595686
  // packages/eight/update-resume.ts
595251
- import { mkdirSync as mkdirSync107, readFileSync as readFileSync125, rmSync as rmSync22, writeFileSync as writeFileSync82 } from "fs";
595252
- import { join as join198 } from "path";
595687
+ import { mkdirSync as mkdirSync107, readFileSync as readFileSync126, rmSync as rmSync22, writeFileSync as writeFileSync82 } from "fs";
595688
+ import { join as join200 } from "path";
595253
595689
  function dataDir4(env = process.env) {
595254
- return join198(resolveHome(env), ".8gent");
595690
+ return join200(resolveHome(env), ".8gent");
595255
595691
  }
595256
595692
  function consumeResumeRequest(env = process.env) {
595257
595693
  const f = file(env);
595258
595694
  try {
595259
- const raw = JSON.parse(readFileSync125(f, "utf8"));
595695
+ const raw = JSON.parse(readFileSync126(f, "utf8"));
595260
595696
  rmSync22(f, { force: true });
595261
595697
  const id = typeof raw.sessionId === "string" && /^[A-Za-z0-9_.-]{1,128}$/.test(raw.sessionId) ? raw.sessionId : undefined;
595262
595698
  return {
@@ -595279,7 +595715,7 @@ function relaunchCommand(o) {
595279
595715
  env: { ...o.env ?? process.env, [UPDATE_NOTE_ENV]: o.req.note }
595280
595716
  };
595281
595717
  }
595282
- var UPDATE_NOTE_ENV = "EIGHT_UPDATE_NOTE", file = (env) => join198(dataDir4(env), "update-resume.json");
595718
+ var UPDATE_NOTE_ENV = "EIGHT_UPDATE_NOTE", file = (env) => join200(dataDir4(env), "update-resume.json");
595283
595719
  var init_update_resume = __esm(() => {
595284
595720
  init_home();
595285
595721
  });
@@ -596696,7 +597132,7 @@ var init_routines = __esm(() => {
596696
597132
  });
596697
597133
 
596698
597134
  // packages/ai/text-tool-demo-tools.ts
596699
- import { readdirSync as readdirSync31, readFileSync as readFileSync131, statSync as statSync42 } from "fs";
597135
+ import { readdirSync as readdirSync31, readFileSync as readFileSync132, statSync as statSync42 } from "fs";
596700
597136
  function str5(args, key) {
596701
597137
  const v = args[key];
596702
597138
  return typeof v === "string" ? v : "";
@@ -596727,7 +597163,7 @@ var init_text_tool_demo_tools = __esm(() => {
596727
597163
  if (info.isDirectory()) {
596728
597164
  return `Error: "${path}" is a directory, not a file. Use list_files.`;
596729
597165
  }
596730
- const text = readFileSync131(path, "utf-8");
597166
+ const text = readFileSync132(path, "utf-8");
596731
597167
  if (text.length > MAX_FILE_BYTES) {
596732
597168
  return `${text.slice(0, MAX_FILE_BYTES)}
596733
597169
  [...truncated, ${text.length} bytes total]`;
@@ -596791,7 +597227,7 @@ var init_text_tool_demo_tools = __esm(() => {
596791
597227
  if (info.isDirectory()) {
596792
597228
  return `Error: grep only searches a single file; "${path}" is a directory.`;
596793
597229
  }
596794
- const text = readFileSync131(path, "utf-8");
597230
+ const text = readFileSync132(path, "utf-8");
596795
597231
  const matches = [];
596796
597232
  const lines = text.split(`
596797
597233
  `);
@@ -597636,7 +598072,7 @@ function nodeExecPath(execPath = process.execPath, env = process.env, exists = e
597636
598072
 
597637
598073
  // bin/8gent.ts
597638
598074
  refuseIfNested();
597639
- var VERSION5 = "0.20.15";
598075
+ var VERSION5 = "0.20.17";
597640
598076
  var RELAUNCH_EXIT_CODE = 75;
597641
598077
  var MODULE_DIR = path158.dirname(fileURLToPath7(import.meta.url));
597642
598078
  var EXEC_DIR = path158.dirname(process.execPath);