@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/node/cli.js CHANGED
@@ -41912,8 +41912,6 @@ var init_allowlist = __esm(() => {
41912
41912
  "node",
41913
41913
  "npm",
41914
41914
  "npx",
41915
- "pnpm",
41916
- "yarn",
41917
41915
  "deno",
41918
41916
  "python",
41919
41917
  "python3",
@@ -41921,9 +41919,6 @@ var init_allowlist = __esm(() => {
41921
41919
  "pip3",
41922
41920
  "uv",
41923
41921
  "git",
41924
- "go",
41925
- "cargo",
41926
- "rustc",
41927
41922
  "tsc",
41928
41923
  "gh",
41929
41924
  "docker",
@@ -41948,20 +41943,18 @@ var init_allowlist = __esm(() => {
41948
41943
  "biome",
41949
41944
  "eslint",
41950
41945
  "prettier",
41951
- "vite"
41946
+ "vite",
41947
+ "8gent"
41952
41948
  ]);
41953
41949
  SHORT_VERSION = {
41954
41950
  node: "-v",
41955
41951
  bun: "-v",
41956
41952
  npm: "-v",
41957
- pnpm: "-v",
41958
- yarn: "-v",
41959
41953
  deno: "-V",
41960
41954
  python: "-V",
41961
41955
  python3: "-V",
41962
41956
  ffmpeg: "-version",
41963
- ffprobe: "-version",
41964
- go: "version"
41957
+ ffprobe: "-version"
41965
41958
  };
41966
41959
  SECRET_ARG = /(^|\/)\.env(\.[\w.-]+)?$|(^|\/)\.env\b|id_rsa|id_ed25519|id_ecdsa|(^|\/)\.ssh(\/|$)|\.aws\/|credentials|\.netrc|\.npmrc|\.git-credentials|keychain|\.pem$|\.key$|\.p12$/;
41967
41960
  REDIR_RE2 = /(?<![<>&\d])(\d?|&)(>>?|<)(\|?)\s*(&\d+|[^\s;|&<>()]+)/g;
@@ -46546,8 +46539,31 @@ function emptyReplyStall(toolCalls) {
46546
46539
  function isEmptyReplyStall(line) {
46547
46540
  return line.startsWith(EMPTY_REPLY_STALL_PREFIX);
46548
46541
  }
46549
- function emptyReplyNote(toolCalls) {
46550
- return `[harness] No reply: ${emptyReplyStall(toolCalls)}.`;
46542
+ function refusedCalls(log, max = 3) {
46543
+ const out = [];
46544
+ let total = 0;
46545
+ for (const e of log) {
46546
+ const m = /^\[[^\]]*\b(?:BLOCKED|DENIED)\b[^\]]*\]\s*([^\n]*)/.exec((e.result ?? "").trimStart());
46547
+ if (!m)
46548
+ continue;
46549
+ total++;
46550
+ if (out.length >= max)
46551
+ continue;
46552
+ const a = e.args;
46553
+ const first = typeof a?.command === "string" ? a.command.trim().split(/\s+/)[0] ?? "" : "";
46554
+ const bin = /^[A-Za-z][\w.+-]{0,40}$/.test(first) ? ` ${first}` : "";
46555
+ const why = /declin/i.test(m[1]) ? "declined" : "blocked by policy";
46556
+ out.push(`${e.name}${bin}: ${why}`);
46557
+ }
46558
+ return { total, shown: out };
46559
+ }
46560
+ function emptyReplyNote(toolCalls, log = []) {
46561
+ const base = `[harness] No reply: ${emptyReplyStall(toolCalls)}.`;
46562
+ const { total, shown } = refusedCalls(log);
46563
+ if (total === 0)
46564
+ return base;
46565
+ const more = total > shown.length ? ` (and ${total - shown.length} more)` : "";
46566
+ return `${base} ${total} of the calls were refused, so they did not run: ${shown.join("; ")}${more}.`;
46551
46567
  }
46552
46568
  function isEmptyReplyNote(reply) {
46553
46569
  return reply.startsWith("[harness] No reply:");
@@ -46640,7 +46656,7 @@ ${summary}`;
46640
46656
  if (unverified.length === 0)
46641
46657
  return { content, rounds, toolLog, unverified: [] };
46642
46658
  const notes = [
46643
- empty ? emptyReplyNote(toolLog.length) : content.trimEnd(),
46659
+ empty ? emptyReplyNote(toolLog.length, toolLog) : content.trimEnd(),
46644
46660
  unfulfilled.length > 0 ? formatHarnessNote(unfulfilled) : ""
46645
46661
  ].filter((n) => n.trim() !== "");
46646
46662
  return { content: notes.join(`
@@ -557020,7 +557036,7 @@ onboarding preferences skip animations adhd quarantine toolshed skills design ev
557020
557036
  resume history continue compact chat agent github debug music dj pet export fork rewind branch cron deploy
557021
557037
  vercel telegram router rename spawn settings quiet term create-app hands eyes handeyes goal subgoal build
557022
557038
  notes ideas btw questions projects terminal reload exit
557023
- copy hotkeys tree import update route privacy consult bug me allow-read`.split(/\s+/));
557039
+ copy hotkeys tree import update route privacy consult bug me allow-read mode`.split(/\s+/));
557024
557040
  });
557025
557041
 
557026
557042
  // packages/extensions/prompts.ts
@@ -565515,7 +565531,9 @@ function defaultSessionsDir2() {
565515
565531
 
565516
565532
  class SessionWriter {
565517
565533
  filePath;
565518
- fd;
565534
+ fd = -1;
565535
+ dev = -1;
565536
+ ino = -1;
565519
565537
  persist;
565520
565538
  seq = 0;
565521
565539
  sessionId;
@@ -565547,15 +565565,47 @@ class SessionWriter {
565547
565565
  fs76.mkdirSync(dir, { recursive: true });
565548
565566
  }
565549
565567
  this.filePath = path105.join(dir, `${sessionId}.jsonl`);
565550
- this.fd = fs76.openSync(this.filePath, "a");
565568
+ this.open();
565569
+ }
565570
+ open() {
565571
+ const c = fs76.constants;
565572
+ const fd = fs76.openSync(this.filePath, c.O_WRONLY | c.O_APPEND | c.O_CREAT | (c.O_NOFOLLOW ?? 0), 384);
565573
+ const st = fs76.fstatSync(fd);
565574
+ if (!st.isFile()) {
565575
+ fs76.closeSync(fd);
565576
+ throw new Error(`${this.filePath} is not a regular file`);
565577
+ }
565578
+ this.fd = fd;
565579
+ this.dev = st.dev;
565580
+ this.ino = st.ino;
565581
+ }
565582
+ fdIsOurs() {
565583
+ if (this.fd < 0)
565584
+ return false;
565585
+ try {
565586
+ const st = fs76.fstatSync(this.fd);
565587
+ return st.dev === this.dev && st.ino === this.ino;
565588
+ } catch {
565589
+ return false;
565590
+ }
565551
565591
  }
565552
565592
  write(entry) {
565553
565593
  if (!this.persist)
565554
565594
  return;
565555
565595
  const line = `${JSON.stringify(entry)}
565556
565596
  `;
565557
- fs76.writeSync(this.fd, line);
565597
+ try {
565598
+ if (!this.fdIsOurs())
565599
+ this.open();
565600
+ fs76.writeSync(this.fd, line);
565601
+ } catch (err) {
565602
+ this.fd = -1;
565603
+ this.skippedWrites++;
565604
+ this.lastWriteError = `session log not written: ${err instanceof Error ? err.message : String(err)}`;
565605
+ }
565558
565606
  }
565607
+ lastWriteError = null;
565608
+ skippedWrites = 0;
565559
565609
  nextSeq() {
565560
565610
  return this.seq++;
565561
565611
  }
@@ -565765,8 +565815,9 @@ class SessionWriter {
565765
565815
  reportId: reportId ?? null
565766
565816
  }
565767
565817
  });
565768
- if (this.persist)
565818
+ if (this.persist && this.fdIsOurs())
565769
565819
  fs76.closeSync(this.fd);
565820
+ this.fd = -1;
565770
565821
  }
565771
565822
  getFilePath() {
565772
565823
  return this.filePath;
@@ -565907,6 +565958,12 @@ var init_slash_commands = __esm(() => {
565907
565958
  description: "Enable infinite mode (autonomous until done)",
565908
565959
  usage: "/infinite [task]"
565909
565960
  },
565961
+ {
565962
+ name: "mode",
565963
+ aliases: [],
565964
+ description: "Set this tab's permission mode: plan, ask, guarded or infinite (same as Shift+Tab)",
565965
+ usage: "/mode <plan|ask|guarded|infinite>"
565966
+ },
565910
565967
  {
565911
565968
  name: "onboarding",
565912
565969
  aliases: ["onboard", "setup", "intro"],
@@ -569517,6 +569574,52 @@ var init_planning_gate = __esm(() => {
569517
569574
  PLANNING_KEYWORDS = /\b(build|create|implement|fix|refactor|add|setup|configure|migrate|convert|redesign|scaffold|deploy|integrate)\b/i;
569518
569575
  });
569519
569576
 
569577
+ // packages/eight/small-talk.ts
569578
+ function flatten(text) {
569579
+ return text.toLowerCase().replace(/^\[mode: [^\]]*\]\s*/, "").replace(/['’]/g, "").replace(/[^a-z0-9 ]+/g, " ").replace(/\s+/g, " ").trim();
569580
+ }
569581
+ function isSmallTalk(text) {
569582
+ const flat = flatten(text);
569583
+ return flat.length > 0 && flat.length <= 40 && GREETING.test(flat);
569584
+ }
569585
+ function isGreeting(text) {
569586
+ return isSmallTalk(text) && !THANKS.test(flatten(text));
569587
+ }
569588
+ 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.";
569589
+ var init_small_talk = __esm(() => {
569590
+ CORE = [
569591
+ "h+i+",
569592
+ "h+e+y+",
569593
+ "h+e+l+o+",
569594
+ "hiya",
569595
+ "howdy",
569596
+ "y+o+",
569597
+ "sup",
569598
+ "wa+s+s?u+p+",
569599
+ "w?h?a+t?s? ?u+p+",
569600
+ "wh?a+t+s? go+d+",
569601
+ "good (?:morning|afternoon|evening|night)",
569602
+ "gm",
569603
+ "gn",
569604
+ "morning",
569605
+ "evening",
569606
+ "how are you(?: doing| today)?",
569607
+ "how are things",
569608
+ "hows it going",
569609
+ "how you doing",
569610
+ "you there",
569611
+ "anyone there",
569612
+ "ping",
569613
+ "thanks(?: a lot| so much)?",
569614
+ "thank you(?: so much)?",
569615
+ "thx",
569616
+ "ty",
569617
+ "cheers"
569618
+ ].join("|");
569619
+ GREETING = new RegExp(`^(?:(?:hi+|hey+|hello+|yo+|hiya|howdy) )?(?:${CORE})(?: (?:there|again|everyone|all|team|mate|man|bro|friend|8gent|eight))?$`);
569620
+ THANKS = /^(?:thanks|thank you|thx|ty|cheers)\b/;
569621
+ });
569622
+
569520
569623
  // packages/eight/verify-gate.ts
569521
569624
  function isVerifyGateEnabled(env = process.env) {
569522
569625
  const v = (env.EIGHT_VERIFY_GATE ?? "").trim().toLowerCase();
@@ -569559,6 +569662,412 @@ var init_verify_gate = __esm(() => {
569559
569662
  `);
569560
569663
  });
569561
569664
 
569665
+ // package.json
569666
+ var package_default;
569667
+ var init_package = __esm(() => {
569668
+ package_default = {
569669
+ name: "@8gi-foundation/8gent-code",
569670
+ version: "0.20.17",
569671
+ private: false,
569672
+ engines: {
569673
+ node: ">=22.5"
569674
+ },
569675
+ description: "Autonomous coding agent. Runs locally on Ollama. Zero API cost. Your code stays on your machine. Open source.",
569676
+ type: "module",
569677
+ bin: {
569678
+ "8": "./bin/8gent-run.js",
569679
+ "8gent": "./bin/8gent-run.js",
569680
+ "8gent-code": "./bin/8gent-run.js"
569681
+ },
569682
+ files: [
569683
+ "dist/cli.js",
569684
+ "dist/tui.js",
569685
+ "dist/pty-bridge.cjs",
569686
+ "dist/node/cli.js",
569687
+ "dist/node/tui.js",
569688
+ "dist/node/pty-bridge.cjs",
569689
+ "dist/skills",
569690
+ "dist/sounds",
569691
+ "bin/8gent-run.js",
569692
+ "bin/node-version.js",
569693
+ "bin/termux-exec.js",
569694
+ "packages/decide/calibration",
569695
+ "packages/daemon/VESSEL-CONTEXT.md",
569696
+ "bin/bunfig.empty.toml",
569697
+ "scripts/postinstall.js",
569698
+ "README.md",
569699
+ "CHANGELOG.md",
569700
+ "LICENSE"
569701
+ ],
569702
+ scripts: {
569703
+ start: "bun --config=bin/bunfig.empty.toml run packages/eight/index.ts",
569704
+ agent: "bun --config=bin/bunfig.empty.toml run packages/eight/index.ts",
569705
+ daemon: "bun --config=bin/bunfig.empty.toml run packages/daemon/index.ts",
569706
+ "daemon:local": "bun --config=bin/bunfig.empty.toml run packages/daemon/scripts/start-local.ts",
569707
+ tui: "bun --config=bin/bunfig.empty.toml run apps/tui/src/index.tsx",
569708
+ pet: "bash apps/lil-eight/build.sh && open 'apps/lil-eight/build/Lil Eight.app'",
569709
+ "pet:build": "bash apps/lil-eight/build.sh",
569710
+ "pet:open": "open 'apps/lil-eight/build/Lil Eight.app'",
569711
+ "pet:kill": "pkill -f LilEight",
569712
+ "pet:log": "tail -f ~/.8gent/lil-eight.log",
569713
+ "install-wizard": "bun --config=bin/bunfig.empty.toml run scripts/install-wizard.tsx",
569714
+ "install:apple-foundation": "bun --config=bin/bunfig.empty.toml run scripts/install-apple-foundation.ts",
569715
+ "build:eyes-bridge": "bash packages/eyes/native/build.sh",
569716
+ cli: "bun --config=bin/bunfig.empty.toml run bin/8gent.ts",
569717
+ dev: "next dev",
569718
+ 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",
569719
+ "build:tui": "bun --config=bin/bunfig.empty.toml scripts/build-bundles.ts --tui && node scripts/build-finalize.js",
569720
+ "build:binaries": "bun --config=bin/bunfig.empty.toml run scripts/build-binaries.ts",
569721
+ "build:binaries:host": "bun --config=bin/bunfig.empty.toml run scripts/build-binaries.ts --host",
569722
+ "package:linux": "bash scripts/package-linux.sh",
569723
+ "package:windows": "pwsh scripts/package-windows.ps1",
569724
+ prepublishOnly: "npm run build",
569725
+ postinstall: "node scripts/postinstall.js",
569726
+ "preflight:native": "sh scripts/preflight-native-deps.sh",
569727
+ test: "bun test packages/ apps/ tests/preload-temp-dirs.test.ts",
569728
+ "test:benchmarks": "bun test benchmarks/",
569729
+ "test:security": "bun test tests/security",
569730
+ "test:models": "bun --config=bin/bunfig.empty.toml scripts/test-models.ts",
569731
+ "test:models:providers": "bun --config=bin/bunfig.empty.toml scripts/test-models.ts --providers",
569732
+ "cua:setup": "bun --config=bin/bunfig.empty.toml run packages/eight/scripts/cua-setup.ts",
569733
+ "cua:run": "bun --config=bin/bunfig.empty.toml run packages/eight/scripts/cua-run.ts",
569734
+ smoke: "bun --config=bin/bunfig.empty.toml scripts/smoke.ts",
569735
+ "smoke:fast": "bun --config=bin/bunfig.empty.toml scripts/smoke.ts --skip-network",
569736
+ "smoke:strict": "bun --config=bin/bunfig.empty.toml scripts/smoke.ts --strict",
569737
+ "smoke:pack": "bun --config=bin/bunfig.empty.toml scripts/pack-smoke.ts",
569738
+ "smoke:bare-install": "sh scripts/bare-install-smoke.sh",
569739
+ "verify:presets": "bun --config=bin/bunfig.empty.toml scripts/verify-presets.ts",
569740
+ "verify:presets:strict": "bun --config=bin/bunfig.empty.toml scripts/verify-presets.ts --strict",
569741
+ lint: "biome lint .",
569742
+ "lint:fix": "biome lint --write .",
569743
+ format: "biome format --write .",
569744
+ "format:check": "biome format .",
569745
+ "check:biome": "biome check .",
569746
+ "check:biome:fix": "biome check --write .",
569747
+ typecheck: "tsc --noEmit",
569748
+ "typecheck:tui": "tsc --noEmit -p apps/tui/tsconfig.json",
569749
+ "check:harness": "tsc --noEmit -p tsconfig.harness.json",
569750
+ benchmark: "bun --config=bin/bunfig.empty.toml run scripts/benchmark.ts",
569751
+ "benchmark:suite": "bun --config=bin/bunfig.empty.toml run benchmarks/runner.ts",
569752
+ "benchmark:category": "bun --config=bin/bunfig.empty.toml run benchmarks/runner.ts --category",
569753
+ "benchmark:single": "bun --config=bin/bunfig.empty.toml run benchmarks/runner.ts --bench",
569754
+ "benchmark:swebench": "bun --config=bin/bunfig.empty.toml run benchmarks/swebench/run.ts",
569755
+ "benchmark:v2": "bun --config=bin/bunfig.empty.toml run benchmarks/autoresearch/harness-v2.ts",
569756
+ "benchmark:gate": "bun --config=bin/bunfig.empty.toml run benchmarks/gate.ts",
569757
+ "benchmark:gate:update": "bun --config=bin/bunfig.empty.toml run benchmarks/gate.ts --update",
569758
+ "benchmark:loop": "bun --config=bin/bunfig.empty.toml run benchmarks/computer-use-bakeoff.ts",
569759
+ "benchmark:bakeoff": "bun --no-env-file --config=bin/bunfig.empty.toml run benchmarks/computer-use-bakeoff.ts",
569760
+ "benchmark:multi": "bun --no-env-file --config=bin/bunfig.empty.toml run benchmarks/autoresearch/multi-model-harness.ts",
569761
+ audit: "bun --no-env-file --config=bin/bunfig.empty.toml run packages/audit/cli.ts",
569762
+ demo: "bun --no-env-file --config=bin/bunfig.empty.toml run scripts/demo-savings.ts",
569763
+ "provision-tenant": "bun --no-env-file --config=bin/bunfig.empty.toml run scripts/provision-tenant.ts",
569764
+ harness: "bun --no-env-file --config=bin/bunfig.empty.toml run packages/harness-cli/index.ts",
569765
+ "harness:run": "bun --no-env-file --config=bin/bunfig.empty.toml run packages/harness-cli/index.ts run",
569766
+ "harness:sessions": "bun --no-env-file --config=bin/bunfig.empty.toml run packages/harness-cli/index.ts sessions",
569767
+ "harness:inspect": "bun --no-env-file --config=bin/bunfig.empty.toml run packages/harness-cli/index.ts inspect",
569768
+ "harness:doctor": "bun --no-env-file --config=bin/bunfig.empty.toml run packages/harness-cli/index.ts doctor",
569769
+ debug: "bun --no-env-file --config=bin/bunfig.empty.toml run bin/debug.ts",
569770
+ "preflight:parse": "node scripts/excluded-parse-check.mjs"
569771
+ },
569772
+ workspaces: [
569773
+ "apps/*",
569774
+ "packages/*"
569775
+ ],
569776
+ devDependencies: {
569777
+ "@ai-sdk/openai-compatible": "^2.0.35",
569778
+ "@biomejs/biome": "^1.5.0",
569779
+ "@changesets/cli": "^2.30.0",
569780
+ "@mozilla/readability": "^0.6.0",
569781
+ "@napi-rs/canvas": "^0.1.97",
569782
+ "@types/bun": "latest",
569783
+ "@types/jsdom": "^28.0.0",
569784
+ "@types/pdf-parse": "^1.1.5",
569785
+ "@types/pngjs": "^6.0.5",
569786
+ "@types/react": "^19.2.14",
569787
+ "@types/ws": "^8.18.1",
569788
+ ai: "^6.0.116",
569789
+ "bmad-method": "^6.1.0",
569790
+ cheerio: "^1.2.0",
569791
+ glob: "^13.0.6",
569792
+ "ink-big-text": "^2.0.0",
569793
+ "ink-gradient": "^4.0.0",
569794
+ "ink-select-input": "^6.2.0",
569795
+ "ink-spinner": "^5.0.0",
569796
+ next: "^16.1.6",
569797
+ "next-themes": "^0.4.6",
569798
+ "pdf-parse": "^2.4.5",
569799
+ pngjs: "^7.0.0",
569800
+ "react-doctor": "^0.1.4",
569801
+ "string-width": "^8.1.1",
569802
+ stripe: "^17.7.0",
569803
+ typescript: "^5.0.0",
569804
+ yaml: "^2.9.1",
569805
+ zod: "^4.3.6"
569806
+ },
569807
+ dependencies: {
569808
+ ink: "^6.8.0",
569809
+ jsdom: "^28.1.0",
569810
+ mermaid: "^11.16.1"
569811
+ },
569812
+ optionalDependencies: {
569813
+ sharp: "^0.34.5",
569814
+ "better-sqlite3": "^12.8.0",
569815
+ "node-pty": "^1.1.0",
569816
+ "tree-sitter": "^0.21.0",
569817
+ "tree-sitter-go": "^0.21.0",
569818
+ "tree-sitter-javascript": "^0.21.0",
569819
+ "tree-sitter-python": "^0.21.0",
569820
+ "tree-sitter-rust": "^0.21.0",
569821
+ "tree-sitter-typescript": "^0.21.0"
569822
+ },
569823
+ publishConfig: {
569824
+ access: "public"
569825
+ },
569826
+ author: "8GI Foundation",
569827
+ license: "Apache-2.0",
569828
+ repository: {
569829
+ type: "git",
569830
+ url: "https://github.com/8gi-foundation/8gent-code.git"
569831
+ },
569832
+ homepage: "https://8gent.dev",
569833
+ bugs: {
569834
+ url: "https://github.com/8gi-foundation/8gent-code/issues"
569835
+ }
569836
+ };
569837
+ });
569838
+
569839
+ // packages/voice/termux.ts
569840
+ import { constants as constants14, accessSync as accessSync4, readFileSync as readFileSync93 } from "node:fs";
569841
+ import { delimiter as delimiter8, join as join146 } from "node:path";
569842
+ function isAndroidHost(platform = process.platform, env = process.env) {
569843
+ return platform === "android" || !!env.TERMUX_VERSION || String(env.PREFIX ?? "").includes("/com.termux/");
569844
+ }
569845
+ function findOnPath(name, env = process.env) {
569846
+ for (const dir of String(env.PATH ?? "").split(delimiter8)) {
569847
+ if (!dir)
569848
+ continue;
569849
+ const candidate = join146(dir, name);
569850
+ try {
569851
+ accessSync4(candidate, constants14.X_OK);
569852
+ return candidate;
569853
+ } catch {}
569854
+ }
569855
+ return null;
569856
+ }
569857
+ var init_termux = () => {};
569858
+
569859
+ // apps/tui/src/lib/external-agent-runner.ts
569860
+ import { execSync as execSync5, spawn as spawn21 } from "node:child_process";
569861
+ function getPreset(id) {
569862
+ return EXTERNAL_AGENT_PRESETS[id.toLowerCase()] ?? null;
569863
+ }
569864
+ function listPresetIds() {
569865
+ return Object.keys(EXTERNAL_AGENT_PRESETS);
569866
+ }
569867
+ function isInstalled(preset) {
569868
+ try {
569869
+ execSync5(`command -v "${preset.command}"`, {
569870
+ stdio: "ignore",
569871
+ timeout: 1500
569872
+ });
569873
+ return true;
569874
+ } catch {
569875
+ return false;
569876
+ }
569877
+ }
569878
+ var stripAnsi = (s) => s.replace(/\[[0-9;?]*[a-zA-Z]/g, "").replace(/\][^]*/g, ""), EXTERNAL_AGENT_PRESETS;
569879
+ var init_external_agent_runner = __esm(() => {
569880
+ init_shell();
569881
+ EXTERNAL_AGENT_PRESETS = {
569882
+ claude: {
569883
+ id: "claude",
569884
+ label: "Sparring",
569885
+ command: "claude",
569886
+ promptMode: "flag",
569887
+ flagName: "-p",
569888
+ args: [],
569889
+ timeoutMs: 120000,
569890
+ parseStdout: stripAnsi,
569891
+ homepage: "https://docs.claude.com/en/docs/claude-code",
569892
+ preferWindow: true,
569893
+ install: {
569894
+ command: "npm install -g --prefix=$HOME/.npm-global @anthropic-ai/claude-code",
569895
+ 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.'
569896
+ }
569897
+ },
569898
+ codex: {
569899
+ id: "codex",
569900
+ label: "OpenAI Codex",
569901
+ command: "codex",
569902
+ promptMode: "arg",
569903
+ args: ["exec"],
569904
+ timeoutMs: 120000,
569905
+ parseStdout: stripAnsi,
569906
+ homepage: "https://github.com/openai/codex",
569907
+ preferWindow: true,
569908
+ install: {
569909
+ command: "npm install -g --prefix=$HOME/.npm-global @openai/codex",
569910
+ notes: "Binary at ~/.npm-global/bin/codex. Add `~/.npm-global/bin` to PATH if needed. Requires `export OPENAI_API_KEY=sk-...` before /spawn."
569911
+ }
569912
+ },
569913
+ hermes: {
569914
+ id: "hermes",
569915
+ label: "Hermes Agent",
569916
+ command: "hermes",
569917
+ preferWindow: true,
569918
+ promptMode: "flag",
569919
+ flagName: "-z",
569920
+ args: [],
569921
+ timeoutMs: 120000,
569922
+ parseStdout: stripAnsi,
569923
+ homepage: "https://github.com/NousResearch/hermes-agent",
569924
+ install: {
569925
+ command: "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash -s -- --skip-setup --no-venv",
569926
+ notes: "Hermes needs Python ≥ 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)."
569927
+ }
569928
+ },
569929
+ openclaw: {
569930
+ id: "openclaw",
569931
+ label: "OpenClaw",
569932
+ command: "openclaw",
569933
+ preferWindow: true,
569934
+ promptMode: "arg",
569935
+ args: ["run", "--headless"],
569936
+ timeoutMs: 120000,
569937
+ parseStdout: stripAnsi,
569938
+ homepage: "https://github.com/openclaw/openclaw",
569939
+ install: {
569940
+ command: "npm install -g --prefix=$HOME/.npm-global openclaw@latest",
569941
+ 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.)"
569942
+ },
569943
+ requiresNodeVersion: "22.14.0"
569944
+ },
569945
+ pi: {
569946
+ preferWindow: true,
569947
+ id: "pi",
569948
+ label: "Pi (pi-mono)",
569949
+ command: "pi",
569950
+ promptMode: "flag",
569951
+ flagName: "-p",
569952
+ args: [],
569953
+ timeoutMs: 120000,
569954
+ parseStdout: stripAnsi,
569955
+ homepage: "https://pi.dev",
569956
+ install: {
569957
+ command: "npm install -g --prefix=$HOME/.npm-global @mariozechner/pi-coding-agent",
569958
+ 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)."
569959
+ }
569960
+ },
569961
+ "8gent": {
569962
+ id: "8gent",
569963
+ label: "8gent (nested)",
569964
+ command: "8gent",
569965
+ promptMode: "arg",
569966
+ args: ["run"],
569967
+ timeoutMs: 180000,
569968
+ parseStdout: stripAnsi,
569969
+ homepage: "https://8gent.dev",
569970
+ install: {
569971
+ command: "npm install -g --prefix=$HOME/.npm-global @8gi-foundation/8gent-code --force",
569972
+ 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."
569973
+ }
569974
+ }
569975
+ };
569976
+ });
569977
+
569978
+ // packages/eight/welcome.ts
569979
+ import { existsSync as existsSync101 } from "node:fs";
569980
+ import { basename as basename49, delimiter as delimiter9, dirname as dirname70, isAbsolute as isAbsolute48, join as join147, relative as relative35, resolve as resolve67 } from "node:path";
569981
+ function pathOutsideFolder(path, cwd) {
569982
+ const root = resolve67(cwd);
569983
+ return path.split(delimiter9).filter((dir) => {
569984
+ if (!dir || !isAbsolute48(dir))
569985
+ return false;
569986
+ const rel = relative35(root, resolve67(dir));
569987
+ return rel.startsWith("..") || isAbsolute48(rel);
569988
+ }).join(delimiter9);
569989
+ }
569990
+ function safeModelLabel(model) {
569991
+ const m = model.trim();
569992
+ if (!m || m.length > 80 || /:\/\/|[@?\s]/.test(m))
569993
+ return "a custom model";
569994
+ return m;
569995
+ }
569996
+ function inGitRepo(dir) {
569997
+ let d = dir;
569998
+ for (let i = 0;i < 64; i++) {
569999
+ if (existsSync101(join147(d, ".git")))
570000
+ return true;
570001
+ const up = dirname70(d);
570002
+ if (up === d)
570003
+ return false;
570004
+ d = up;
570005
+ }
570006
+ return false;
570007
+ }
570008
+ function hostLabel(android, platform, arch) {
570009
+ if (android)
570010
+ return `Android (Termux, ${arch})`;
570011
+ const os = platform === "darwin" ? "macOS" : platform === "linux" ? "Linux" : platform === "win32" ? "Windows" : platform;
570012
+ return `${os} ${arch}`;
570013
+ }
570014
+ async function knownPresets() {
570015
+ const runner = await Promise.resolve().then(() => (init_external_agent_runner(), {}));
570016
+ const out = [];
570017
+ for (const id of listPresetIds()) {
570018
+ const p = getPreset(id);
570019
+ if (p)
570020
+ out.push({ id: p.id, command: p.command });
570021
+ }
570022
+ return out;
570023
+ }
570024
+ async function gatherWelcomeFacts(opts) {
570025
+ const env = opts.env ?? process.env;
570026
+ const android = isAndroidHost(opts.platform ?? process.platform, env);
570027
+ const cwd = resolve67(opts.cwd);
570028
+ const home = env.HOME ? resolve67(env.HOME) : null;
570029
+ const lookupEnv = { ...env, PATH: pathOutsideFolder(String(env.PATH ?? ""), cwd) };
570030
+ const presets = (opts.presets ?? await knownPresets()).filter((p) => p.id !== "8gent");
570031
+ return {
570032
+ version: String(package_default.version),
570033
+ host: hostLabel(android, opts.platform ?? process.platform, opts.arch ?? process.arch),
570034
+ android,
570035
+ model: safeModelLabel(opts.model),
570036
+ provider: opts.provider,
570037
+ presetIds: presets.map((p) => p.id),
570038
+ installed: presets.filter((p) => findOnPath(p.command, lookupEnv) !== null).map((p) => p.id),
570039
+ folder: cwd === home ? "~" : basename49(cwd) || "/",
570040
+ gitRepo: inGitRepo(cwd)
570041
+ };
570042
+ }
570043
+ function listWords(items) {
570044
+ if (items.length <= 1)
570045
+ return items.join("");
570046
+ return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
570047
+ }
570048
+ function buildWelcome(f) {
570049
+ const where = f.android ? "phone" : "machine";
570050
+ const lines = [`Hi, I'm 8gent v${f.version} on ${f.host}, using ${f.model} via ${f.provider}.`];
570051
+ if (f.installed.length > 0) {
570052
+ 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.`);
570053
+ } else {
570054
+ lines.push(`I checked PATH for ${listWords(f.presetIds)}: none installed, so it's just me here.`);
570055
+ }
570056
+ 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.`);
570057
+ const next = [];
570058
+ if (f.installed.length > 0)
570059
+ next.push(`run ${f.installed[0]}`);
570060
+ next.push(f.gitRepo ? "what changed in the last commit" : "make a folder called demo with a hello web page");
570061
+ next.push("what can you do");
570062
+ lines.push("Try:", ...next.map((n) => ` "${n}"`));
570063
+ return lines.join(`
570064
+ `);
570065
+ }
570066
+ var init_welcome = __esm(() => {
570067
+ init_package();
570068
+ init_termux();
570069
+ });
570070
+
569562
570071
  // packages/eight/failover-provider-config.ts
569563
570072
  function providerConfigForStep(session, step) {
569564
570073
  if (step.provider === session.name) {
@@ -570076,8 +570585,8 @@ var init_local_turn_error = __esm(() => {
570076
570585
  });
570077
570586
 
570078
570587
  // packages/eight/output-gate.ts
570079
- import { existsSync as existsSync101 } from "node:fs";
570080
- import { isAbsolute as isAbsolute48, relative as relative35, resolve as resolve67 } from "node:path";
570588
+ import { existsSync as existsSync102 } from "node:fs";
570589
+ import { isAbsolute as isAbsolute49, relative as relative36, resolve as resolve68 } from "node:path";
570081
570590
  function isOutputGateEnabled(env = process.env, option) {
570082
570591
  if (option !== undefined)
570083
570592
  return option;
@@ -570109,10 +570618,10 @@ class OutputGate {
570109
570618
  events = [];
570110
570619
  constructor(task, cwd, enabled) {
570111
570620
  this.cwd = cwd;
570112
- this.required = !enabled ? [] : namedOutputs(task).map((shown) => ({ shown, abs: resolve67(cwd, shown) })).filter(({ abs }) => !relative35(cwd, abs).startsWith("..") && !isAbsolute48(relative35(cwd, abs))).filter(({ abs }) => !existsSync101(abs));
570621
+ this.required = !enabled ? [] : namedOutputs(task).map((shown) => ({ shown, abs: resolve68(cwd, shown) })).filter(({ abs }) => !relative36(cwd, abs).startsWith("..") && !isAbsolute49(relative36(cwd, abs))).filter(({ abs }) => !existsSync102(abs));
570113
570622
  }
570114
570623
  missing() {
570115
- return this.required.filter(({ abs }) => !existsSync101(abs)).map(({ shown }) => shown);
570624
+ return this.required.filter(({ abs }) => !existsSync102(abs)).map(({ shown }) => shown);
570116
570625
  }
570117
570626
  check(reply) {
570118
570627
  const missing = this.missing();
@@ -570150,7 +570659,7 @@ var init_output_gate = __esm(() => {
570150
570659
  function stripPunctuation(s) {
570151
570660
  return s.replace(/[.,;:!?]+$/g, "").trim();
570152
570661
  }
570153
- function isGreeting(message) {
570662
+ function isGreeting2(message) {
570154
570663
  const stripped = stripPunctuation(message.toLowerCase()).trim();
570155
570664
  if (stripped.length === 0)
570156
570665
  return true;
@@ -570171,7 +570680,7 @@ class PreToolRouter {
570171
570680
  classify(userMessage, _projectContext) {
570172
570681
  const msg = userMessage ?? "";
570173
570682
  const trimmed = msg.trim();
570174
- if (trimmed.length === 0 || isGreeting(trimmed)) {
570683
+ if (trimmed.length === 0 || isGreeting2(trimmed)) {
570175
570684
  return {
570176
570685
  strategy: "none",
570177
570686
  args: {},
@@ -570443,12 +570952,12 @@ __export(exports_system_prompt, {
570443
570952
  styleHasGuide: () => styleHasGuide,
570444
570953
  workingProjectNote: () => workingProjectNote
570445
570954
  });
570446
- import { readFileSync as readFileSync93 } from "node:fs";
570447
- import { basename as basename49, join as join146 } from "node:path";
570955
+ import { existsSync as existsSync103, readFileSync as readFileSync94 } from "node:fs";
570956
+ import { basename as basename50, join as join148, resolve as resolve69 } from "node:path";
570448
570957
  function buildBoardContextSegment(path = BOARD_CONTEXT_PATH) {
570449
570958
  let text;
570450
570959
  try {
570451
- text = readFileSync93(path, "utf-8").trim();
570960
+ text = readFileSync94(path, "utf-8").trim();
570452
570961
  } catch {
570453
570962
  return "";
570454
570963
  }
@@ -570475,8 +570984,20 @@ function communicationStyleLine(style) {
570475
570984
  function styleHasGuide(style) {
570476
570985
  return isCommunicationStyle(style) && STYLE_GUIDE[style] !== "";
570477
570986
  }
570987
+ function isPlainHome(dir, home = resolveHome()) {
570988
+ try {
570989
+ return home !== "" && resolve69(dir) === resolve69(home) && !existsSync103(join148(dir, ".git"));
570990
+ } catch {
570991
+ return false;
570992
+ }
570993
+ }
570478
570994
  function workingProjectNote(dir) {
570479
- const name = basename49(dir) || dir;
570995
+ const name = basename50(dir) || dir;
570996
+ if (isPlainHome(dir)) {
570997
+ return `
570998
+
570999
+ **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.**`;
571000
+ }
570480
571001
  if (name === "8gent-code") {
570481
571002
  return `
570482
571003
 
@@ -570820,7 +571341,7 @@ var init_system_prompt = __esm(() => {
570820
571341
  init_tool_registry();
570821
571342
  init_soul_layers();
570822
571343
  IDENTITY_SEGMENT = composeSoulPrompt("owner");
570823
- BOARD_CONTEXT_PATH = join146(resolveHome(), ".8gent", "board-context.md");
571344
+ BOARD_CONTEXT_PATH = join148(resolveHome(), ".8gent", "board-context.md");
570824
571345
  ACTION_FIRST_STYLE = [
570825
571346
  "Shape every reply so the reader can act without rereading:",
570826
571347
  ACTION_FIRST_PRECEDENCE,
@@ -572889,16 +573410,16 @@ var init_agent = __esm(() => {
572889
573410
  });
572890
573411
 
572891
573412
  // packages/ai/task-router.ts
572892
- import { join as join147 } from "node:path";
573413
+ import { join as join149 } from "node:path";
572893
573414
  var CONFIG_DIR2, ROUTER_CONFIG_PATH, ROUTER_STATS_PATH, ClassificationSchema;
572894
573415
  var init_task_router = __esm(() => {
572895
573416
  init_zod();
572896
573417
  init_providers2();
572897
573418
  init_local_model_server();
572898
573419
  init_text_tool_endpoint();
572899
- CONFIG_DIR2 = join147(process.env.HOME || "~", ".8gent");
572900
- ROUTER_CONFIG_PATH = join147(CONFIG_DIR2, "router.json");
572901
- ROUTER_STATS_PATH = join147(CONFIG_DIR2, "router-stats.json");
573420
+ CONFIG_DIR2 = join149(process.env.HOME || "~", ".8gent");
573421
+ ROUTER_CONFIG_PATH = join149(CONFIG_DIR2, "router.json");
573422
+ ROUTER_STATS_PATH = join149(CONFIG_DIR2, "router-stats.json");
572902
573423
  ClassificationSchema = object({
572903
573424
  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)"),
572904
573425
  confidence: number2().min(0).max(1).describe("How confident you are in this classification (0-1)"),
@@ -572912,11 +573433,11 @@ var init_toolshed_bridge = __esm(() => {
572912
573433
  });
572913
573434
 
572914
573435
  // packages/ai/embedding-cache.ts
572915
- import { join as join148 } from "node:path";
573436
+ import { join as join150 } from "node:path";
572916
573437
  var CACHE_DIR, CACHE_PATH;
572917
573438
  var init_embedding_cache = __esm(() => {
572918
- CACHE_DIR = join148(process.env.HOME || "~", ".8gent");
572919
- CACHE_PATH = join148(CACHE_DIR, "embedding-cache.json");
573439
+ CACHE_DIR = join150(process.env.HOME || "~", ".8gent");
573440
+ CACHE_PATH = join150(CACHE_DIR, "embedding-cache.json");
572920
573441
  });
572921
573442
 
572922
573443
  // packages/ai/edge-inference.ts
@@ -573197,13 +573718,13 @@ var init_quick_answer = __esm(() => {
573197
573718
  // packages/eight/session-scratch.ts
573198
573719
  import { lstatSync as lstatSync31, mkdirSync as mkdirSync72, rmSync as rmSync14 } from "node:fs";
573199
573720
  import { tmpdir as tmpdir17 } from "node:os";
573200
- import { join as join149 } from "node:path";
573721
+ import { join as join151 } from "node:path";
573201
573722
  function removeAllAtExit() {
573202
573723
  for (const dir of [...live2])
573203
573724
  removeSessionScratch(dir);
573204
573725
  }
573205
573726
  function sessionScratchPath(sessionId) {
573206
- return join149(tmpdir17(), `8gent-${sessionId}`);
573727
+ return join151(tmpdir17(), `8gent-${sessionId}`);
573207
573728
  }
573208
573729
  function createSessionScratch(sessionId) {
573209
573730
  const dir = sessionScratchPath(sessionId);
@@ -581108,19 +581629,19 @@ var init_opportunity_scanner = () => {};
581108
581629
  var init_capability_matcher = () => {};
581109
581630
 
581110
581631
  // packages/proactive/work-tracker.ts
581111
- import { join as join152 } from "node:path";
581632
+ import { join as join154 } from "node:path";
581112
581633
  var DATA_DIR3, STORE_PATH;
581113
581634
  var init_work_tracker = __esm(() => {
581114
- DATA_DIR3 = join152(process.env.HOME || "~", ".8gent");
581115
- STORE_PATH = join152(DATA_DIR3, "opportunities.json");
581635
+ DATA_DIR3 = join154(process.env.HOME || "~", ".8gent");
581636
+ STORE_PATH = join154(DATA_DIR3, "opportunities.json");
581116
581637
  });
581117
581638
 
581118
581639
  // packages/proactive/revenue-engine.ts
581119
- import { join as join153 } from "node:path";
581640
+ import { join as join155 } from "node:path";
581120
581641
  var DATA_DIR4, STORE_PATH2;
581121
581642
  var init_revenue_engine = __esm(() => {
581122
- DATA_DIR4 = join153(process.env.HOME || "~", ".8gent");
581123
- STORE_PATH2 = join153(DATA_DIR4, "revenue.json");
581643
+ DATA_DIR4 = join155(process.env.HOME || "~", ".8gent");
581644
+ STORE_PATH2 = join155(DATA_DIR4, "revenue.json");
581124
581645
  });
581125
581646
 
581126
581647
  // packages/proactive/deliverable-generator.ts
@@ -581134,10 +581655,10 @@ var init_content_packaging = () => {};
581134
581655
 
581135
581656
  // packages/tools/browser/cache.ts
581136
581657
  import { homedir as homedir77 } from "node:os";
581137
- import { join as join154 } from "node:path";
581658
+ import { join as join156 } from "node:path";
581138
581659
  var CACHE_DIR2, TTL_MS, MAX_CACHE_BYTES;
581139
581660
  var init_cache2 = __esm(() => {
581140
- CACHE_DIR2 = join154(process.env.EIGHT_DATA_DIR || join154(homedir77(), ".8gent"), "browser-cache");
581661
+ CACHE_DIR2 = join156(process.env.EIGHT_DATA_DIR || join156(homedir77(), ".8gent"), "browser-cache");
581141
581662
  TTL_MS = 60 * 60 * 1000;
581142
581663
  MAX_CACHE_BYTES = 100 * 1024 * 1024;
581143
581664
  });
@@ -581880,7 +582401,7 @@ var init_voice3 = __esm(() => {
581880
582401
 
581881
582402
  // packages/eight/observation-pack.ts
581882
582403
  import { createHash as createHash21 } from "node:crypto";
581883
- import { readFileSync as readFileSync95 } from "node:fs";
582404
+ import { readFileSync as readFileSync96 } from "node:fs";
581884
582405
  function observationPackEnabled(env = process.env) {
581885
582406
  return env.EIGHT_OBSERVATION_PACK === "1";
581886
582407
  }
@@ -581900,7 +582421,7 @@ class ObservationStore {
581900
582421
  const path = this.paths.get(handle);
581901
582422
  if (!path)
581902
582423
  throw new Error(`no saved output with handle "${handle}" in this session`);
581903
- return readFileSync95(path, "utf8").slice(offset, offset + limit);
582424
+ return readFileSync96(path, "utf8").slice(offset, offset + limit);
581904
582425
  }
581905
582426
  size(handle) {
581906
582427
  return this.read(handle).length;
@@ -582835,6 +583356,7 @@ class Agent {
582835
583356
  steerQueue = [];
582836
583357
  activeTurn = null;
582837
583358
  turnCounter = 0;
583359
+ welcomed = false;
582838
583360
  stopRequested = false;
582839
583361
  orchestratorBus;
582840
583362
  toolRegistry;
@@ -583302,14 +583824,15 @@ ${LOCAL_LOGIN_NOTE}`;
583302
583824
  instructions,
583303
583825
  localCoreTools,
583304
583826
  chatStartTime,
583305
- textForAgent
583827
+ textForAgent,
583828
+ smallTalk = false
583306
583829
  } = opts;
583307
583830
  const signal = this.armController().signal;
583308
583831
  const allow = new Set(localCoreTools);
583309
583832
  const specs = toolDefsToSpecs(this.executor.getToolDefinitions(), allow);
583310
583833
  let stepNumber = 0;
583311
583834
  let breakerStop = null;
583312
- if (this.extensionToolsAllowed()) {
583835
+ if (this.extensionToolsAllowed() && !smallTalk) {
583313
583836
  for (const t of this.extensionHost.listTools()) {
583314
583837
  if (this.modeAllows(t.name)) {
583315
583838
  specs.push({ name: t.name, description: t.description, parameters: t.parameters });
@@ -583873,6 +584396,21 @@ ${LOCAL_LOGIN_NOTE}`;
583873
584396
  console.log(`[turn-review] ${line}`);
583874
584397
  }
583875
584398
  }
584399
+ async greetingWelcome(text) {
584400
+ if (this.welcomed || this.config.headless || this.agentDepth > 0 || !isGreeting(text))
584401
+ return null;
584402
+ try {
584403
+ const facts = await gatherWelcomeFacts({
584404
+ model: String(this.config.model),
584405
+ provider: String(this.config.runtime),
584406
+ cwd: this.config.workingDirectory || process.cwd()
584407
+ });
584408
+ this.welcomed = true;
584409
+ return buildWelcome(facts);
584410
+ } catch {
584411
+ return null;
584412
+ }
584413
+ }
583876
584414
  async runTurn(userMessage, imageBase64, imageMimeType, imageOriginal) {
583877
584415
  await this.extensionsReady;
583878
584416
  this.loopDetector.reset();
@@ -583887,6 +584425,17 @@ ${LOCAL_LOGIN_NOTE}`;
583887
584425
  this.turnGitBaseline = asksForCommit(userMessage) ? gitSnapshot(this.config.workingDirectory || process.cwd()) : null;
583888
584426
  this.executor.beginTurn(userMessage);
583889
584427
  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);
584428
+ const smallTalkTurn = isSmallTalk(textForAgent) && !imageBase64 && this.config.agentScope !== "__table__";
584429
+ if (smallTalkTurn) {
584430
+ const welcome = await this.greetingWelcome(textForAgent);
584431
+ if (welcome) {
584432
+ this.messageHistory.push({ role: "user", content: textForAgent });
584433
+ this.messageHistory.push({ role: "assistant", content: welcome });
584434
+ this.sessionWriter.writeUserMessage(textForAgent);
584435
+ return welcome;
584436
+ }
584437
+ this.messageHistory.push({ role: "user", content: harnessNote(SMALL_TALK_NOTE) });
584438
+ }
583890
584439
  let visionId = null;
583891
584440
  let visionFailed = false;
583892
584441
  if (imageBase64 && await this.promptImageSeen()) {
@@ -583957,7 +584506,7 @@ ${result.description.slice(0, 200)}${result.description.length > 200 ? "..." : "
583957
584506
  }
583958
584507
  }
583959
584508
  const quickPrompt = quickLaneEnabled() && classifyPrompt(textForAgent) === "quick";
583960
- if (needsClarification(textForAgent) && !imageBase64 && !quickPrompt && !isNoToolScope(this.config.agentScope)) {
584509
+ if (needsClarification(textForAgent) && !imageBase64 && !quickPrompt && !smallTalkTurn && !isNoToolScope(this.config.agentScope)) {
583961
584510
  this.proactiveGatherer = createGatherer(textForAgent);
583962
584511
  const question = this.proactiveGatherer.getCurrentQuestion();
583963
584512
  if (question) {
@@ -583979,7 +584528,7 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
583979
584528
  this.kanban.moveTask(this.currentBmadTask.id, "ready");
583980
584529
  this.kanban.moveTask(this.currentBmadTask.id, "in_progress");
583981
584530
  }
583982
- if (!this.proactiveGatherer && !quickPrompt) {
584531
+ if (!this.proactiveGatherer && !quickPrompt && !smallTalkTurn) {
583983
584532
  await this.tryRunPreToolRouter(textForAgent);
583984
584533
  }
583985
584534
  const needsPlanningGate2 = !isVerbatimScope(this.config.agentScope) && needsPlanningGate(textForAgent);
@@ -584124,9 +584673,9 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
584124
584673
  "search_symbols",
584125
584674
  "recall"
584126
584675
  ]);
584127
- const scopedTools = isNoToolScope(this.config.agentScope) ? {} : this.config.agentScope === "__table__" ? Object.fromEntries(Object.entries(providerTools).filter(([k]) => TABLE_SESSION_TOOLS.has(k))) : providerTools;
584676
+ const scopedTools = isNoToolScope(this.config.agentScope) || smallTalkTurn ? {} : this.config.agentScope === "__table__" ? Object.fromEntries(Object.entries(providerTools).filter(([k]) => TABLE_SESSION_TOOLS.has(k))) : providerTools;
584128
584677
  const withExtensions = { ...scopedTools };
584129
- if (this.extensionToolsAllowed()) {
584678
+ if (this.extensionToolsAllowed() && !smallTalkTurn) {
584130
584679
  for (const t of this.extensionHost.listTools()) {
584131
584680
  if (t.name in withExtensions)
584132
584681
  continue;
@@ -584138,7 +584687,7 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
584138
584687
  }
584139
584688
  }
584140
584689
  const effectiveTools = this.modeFilter(withExtensions);
584141
- const textToolAllowlist = (isNoToolScope(this.config.agentScope) ? [] : this.config.agentScope === "__table__" ? [...TABLE_SESSION_TOOLS] : localCoreTools).filter((name) => getModeManager().isToolAllowed(name));
584690
+ const textToolAllowlist = (isNoToolScope(this.config.agentScope) || smallTalkTurn ? [] : this.config.agentScope === "__table__" ? [...TABLE_SESSION_TOOLS] : localCoreTools).filter((name) => getModeManager().isToolAllowed(name));
584142
584691
  const harness = this.harnessProfileFor(providerConfig.model, isLocalProvider);
584143
584692
  Object.assign(this.runtimeParams, {
584144
584693
  voiceChatActive: getRuntimeParams().voiceChatActive,
@@ -584163,7 +584712,8 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
584163
584712
  `),
584164
584713
  localCoreTools: textToolAllowlist,
584165
584714
  chatStartTime,
584166
- textForAgent
584715
+ textForAgent,
584716
+ smallTalk: smallTalkTurn
584167
584717
  });
584168
584718
  await this.readServerContextWindow();
584169
584719
  await this.compactIfNeeded(providerConfig);
@@ -584848,7 +585398,7 @@ ${summary || " (no provider errors recorded)"}`);
584848
585398
  };
584849
585399
  }
584850
585400
  const blankNative = gatedNative.content.trim() === "";
584851
- const content = blankNative ? emptyReplyNote(this.turnToolLedger.length) : gatedNative.content;
585401
+ const content = blankNative ? emptyReplyNote(this.turnToolLedger.length, this.turnToolLedger) : gatedNative.content;
584852
585402
  const flavor = voice.getFlavor("complete");
584853
585403
  const flavoredContent = fixCompletedLine(gatedNative.violated || isVerbatimScope(this.config.agentScope) ? content : flavorResponse(content, flavor)).text;
584854
585404
  this.messageHistory.push({ role: "assistant", content: flavoredContent });
@@ -585563,7 +586113,9 @@ var init_agent2 = __esm(() => {
585563
586113
  init_modes();
585564
586114
  init_planning_gate();
585565
586115
  init_registry();
586116
+ init_small_talk();
585566
586117
  init_verify_gate();
586118
+ init_welcome();
585567
586119
  init_local_tool_scope();
585568
586120
  init_local_turn_error();
585569
586121
  init_output_gate();
@@ -587061,9 +587613,9 @@ var init_throughput_tracker = __esm(() => {
587061
587613
  });
587062
587614
 
587063
587615
  // packages/orchestration/worktree-pool-agent.ts
587064
- import { execFileSync as execFileSync10, spawn as spawn21 } from "node:child_process";
587065
- import { appendFileSync as appendFileSync23, existsSync as existsSync106, mkdirSync as mkdirSync76, readFileSync as readFileSync99, writeFileSync as writeFileSync58 } from "node:fs";
587066
- import { join as join159 } from "node:path";
587616
+ import { execFileSync as execFileSync10, spawn as spawn22 } from "node:child_process";
587617
+ import { appendFileSync as appendFileSync23, existsSync as existsSync108, mkdirSync as mkdirSync76, readFileSync as readFileSync100, writeFileSync as writeFileSync58 } from "node:fs";
587618
+ import { join as join161 } from "node:path";
587067
587619
 
587068
587620
  class WorktreePoolAgent {
587069
587621
  task;
@@ -587079,16 +587631,16 @@ class WorktreePoolAgent {
587079
587631
  }
587080
587632
  start(onDone) {
587081
587633
  this.onDone = onDone;
587082
- const logDir = join159(this.task.worktreePath, ".8gent");
587634
+ const logDir = join161(this.task.worktreePath, ".8gent");
587083
587635
  mkdirSync76(logDir, { recursive: true });
587084
- const logPath = join159(logDir, "output.log");
587636
+ const logPath = join161(logDir, "output.log");
587085
587637
  const env = {
587086
587638
  ...process.env,
587087
587639
  EIGHT_WORKTREE_ID: this.task.id,
587088
587640
  EIGHT_WORKTREE_PATH: this.task.worktreePath,
587089
587641
  ...this.task.model ? { EIGHGENT_MODEL: this.task.model } : {}
587090
587642
  };
587091
- this.proc = spawn21("bun", [...safeBunFlags(), "run", "packages/eight/index.ts", this.task.prompt], {
587643
+ this.proc = spawn22("bun", [...safeBunFlags(), "run", "packages/eight/index.ts", this.task.prompt], {
587092
587644
  cwd: this.task.worktreePath,
587093
587645
  stdio: ["pipe", "pipe", "pipe"],
587094
587646
  env,
@@ -587123,7 +587675,7 @@ class WorktreePoolAgent {
587123
587675
  filesChanged,
587124
587676
  completedAt: Date.now()
587125
587677
  };
587126
- const resultPath = join159(this.task.worktreePath, ".8gent", "result.json");
587678
+ const resultPath = join161(this.task.worktreePath, ".8gent", "result.json");
587127
587679
  try {
587128
587680
  writeFileSync58(resultPath, JSON.stringify(result, null, 2));
587129
587681
  } catch {}
@@ -587142,11 +587694,11 @@ class WorktreePoolAgent {
587142
587694
  }
587143
587695
  }
587144
587696
  static readResult(worktreePath) {
587145
- const p = join159(worktreePath, ".8gent", "result.json");
587146
- if (!existsSync106(p))
587697
+ const p = join161(worktreePath, ".8gent", "result.json");
587698
+ if (!existsSync108(p))
587147
587699
  return null;
587148
587700
  try {
587149
- return JSON.parse(readFileSync99(p, "utf-8"));
587701
+ return JSON.parse(readFileSync100(p, "utf-8"));
587150
587702
  } catch {
587151
587703
  return null;
587152
587704
  }
@@ -587158,8 +587710,8 @@ var init_worktree_pool_agent = __esm(() => {
587158
587710
 
587159
587711
  // packages/orchestration/worktree-pool.ts
587160
587712
  import { execFileSync as execFileSync11 } from "node:child_process";
587161
- import { existsSync as existsSync107, mkdirSync as mkdirSync77 } from "node:fs";
587162
- import { join as join160, resolve as resolve68 } from "node:path";
587713
+ import { existsSync as existsSync109, mkdirSync as mkdirSync77 } from "node:fs";
587714
+ import { join as join162, resolve as resolve70 } from "node:path";
587163
587715
 
587164
587716
  class WorktreePool {
587165
587717
  projectRoot;
@@ -587172,8 +587724,8 @@ class WorktreePool {
587172
587724
  running = 0;
587173
587725
  queue = [];
587174
587726
  constructor(opts = {}) {
587175
- this.projectRoot = resolve68(opts.projectRoot ?? process.cwd());
587176
- this.worktreesDir = join160(this.projectRoot, ".8gent", "worktrees");
587727
+ this.projectRoot = resolve70(opts.projectRoot ?? process.cwd());
587728
+ this.worktreesDir = join162(this.projectRoot, ".8gent", "worktrees");
587177
587729
  this.maxConcurrent = opts.maxConcurrent ?? DEFAULT_MAX;
587178
587730
  this.taskTimeoutMs = opts.taskTimeoutMs ?? DEFAULT_TIMEOUT2;
587179
587731
  mkdirSync77(this.worktreesDir, { recursive: true });
@@ -587181,7 +587733,7 @@ class WorktreePool {
587181
587733
  async spawn(prompt, opts = {}) {
587182
587734
  const id = `wt-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
587183
587735
  const branch = opts.branch ?? `8gent/worktree-${id}`;
587184
- const worktreePath = join160(this.worktreesDir, id);
587736
+ const worktreePath = join162(this.worktreesDir, id);
587185
587737
  const task = {
587186
587738
  id,
587187
587739
  prompt,
@@ -587292,7 +587844,7 @@ class WorktreePool {
587292
587844
  }
587293
587845
  }
587294
587846
  gitWorktreeRemove(path) {
587295
- if (!existsSync107(path))
587847
+ if (!existsSync109(path))
587296
587848
  return;
587297
587849
  try {
587298
587850
  execFileSync11("git", ["worktree", "remove", path, "--force"], {
@@ -587317,19 +587869,19 @@ var init_worktree_pool = __esm(() => {
587317
587869
 
587318
587870
  // packages/orchestration/worktree-messaging.ts
587319
587871
  import {
587320
- existsSync as existsSync108,
587872
+ existsSync as existsSync110,
587321
587873
  mkdirSync as mkdirSync78,
587322
- readFileSync as readFileSync100,
587874
+ readFileSync as readFileSync101,
587323
587875
  readdirSync as readdirSync26,
587324
587876
  unlinkSync as unlinkSync3,
587325
587877
  writeFileSync as writeFileSync59
587326
587878
  } from "node:fs";
587327
- import { join as join161 } from "node:path";
587879
+ import { join as join163 } from "node:path";
587328
587880
 
587329
587881
  class WorktreeMessaging {
587330
587882
  base;
587331
587883
  constructor(projectRoot) {
587332
- this.base = join161(projectRoot, ".8gent", "messages");
587884
+ this.base = join163(projectRoot, ".8gent", "messages");
587333
587885
  mkdirSync78(this.base, { recursive: true });
587334
587886
  }
587335
587887
  send(message) {
@@ -587340,9 +587892,9 @@ class WorktreeMessaging {
587340
587892
  };
587341
587893
  const targets = message.to === "broadcast" ? this.listInboxes() : [message.to];
587342
587894
  for (const target of targets) {
587343
- const dir = join161(this.base, target);
587895
+ const dir = join163(this.base, target);
587344
587896
  mkdirSync78(dir, { recursive: true });
587345
- writeFileSync59(join161(dir, `${msg.id}.json`), JSON.stringify(msg, null, 2));
587897
+ writeFileSync59(join163(dir, `${msg.id}.json`), JSON.stringify(msg, null, 2));
587346
587898
  }
587347
587899
  return msg;
587348
587900
  }
@@ -587353,15 +587905,15 @@ class WorktreeMessaging {
587353
587905
  return this.readDir(agentId, true);
587354
587906
  }
587355
587907
  readDir(agentId, remove) {
587356
- const dir = join161(this.base, agentId);
587357
- if (!existsSync108(dir))
587908
+ const dir = join163(this.base, agentId);
587909
+ if (!existsSync110(dir))
587358
587910
  return [];
587359
587911
  const files = readdirSync26(dir).filter((f) => f.endsWith(".json")).sort();
587360
587912
  const messages = [];
587361
587913
  for (const f of files) {
587362
- const fp = join161(dir, f);
587914
+ const fp = join163(dir, f);
587363
587915
  try {
587364
- messages.push(JSON.parse(readFileSync100(fp, "utf-8")));
587916
+ messages.push(JSON.parse(readFileSync101(fp, "utf-8")));
587365
587917
  if (remove)
587366
587918
  unlinkSync3(fp);
587367
587919
  } catch {}
@@ -587369,7 +587921,7 @@ class WorktreeMessaging {
587369
587921
  return messages;
587370
587922
  }
587371
587923
  listInboxes() {
587372
- if (!existsSync108(this.base))
587924
+ if (!existsSync110(this.base))
587373
587925
  return [];
587374
587926
  return readdirSync26(this.base);
587375
587927
  }
@@ -588999,9 +589551,9 @@ var init_cli = __esm(async () => {
588999
589551
  });
589000
589552
 
589001
589553
  // packages/orchestration/adaptive-pipeline.ts
589002
- import { spawn as spawn22 } from "node:child_process";
589554
+ import { spawn as spawn23 } from "node:child_process";
589003
589555
  import { homedir as homedir81 } from "node:os";
589004
- import { join as join162 } from "node:path";
589556
+ import { join as join164 } from "node:path";
589005
589557
 
589006
589558
  class Obstacle {
589007
589559
  type;
@@ -589396,7 +589948,7 @@ async function callLMStudio(model, system, user, maxTokens) {
589396
589948
  }
589397
589949
  function callAppleFoundation(system, user) {
589398
589950
  return new Promise((resolve, reject) => {
589399
- const proc = spawn22(BRIDGE_PATH2, [], { stdio: ["pipe", "pipe", "ignore"] });
589951
+ const proc = spawn23(BRIDGE_PATH2, [], { stdio: ["pipe", "pipe", "ignore"] });
589400
589952
  let buf = "";
589401
589953
  const timer = setTimeout(() => {
589402
589954
  proc.kill();
@@ -589486,7 +590038,7 @@ var init_adaptive_pipeline = __esm(() => {
589486
590038
  init_role_config();
589487
590039
  OLLAMA_URL2 = process.env.OLLAMA_BASE_URL || "http://localhost:11434";
589488
590040
  LMSTUDIO_URL2 = process.env.LMSTUDIO_BASE_URL || "http://localhost:1234/v1";
589489
- BRIDGE_PATH2 = process.env.APPLE_FOUNDATION_BRIDGE || join162(homedir81(), ".8gent", "bin", "apple-foundation-bridge");
590041
+ BRIDGE_PATH2 = process.env.APPLE_FOUNDATION_BRIDGE || join164(homedir81(), ".8gent", "bin", "apple-foundation-bridge");
589490
590042
  ((Severity) => {
589491
590043
  Severity[Severity["Trivial"] = 1] = "Trivial";
589492
590044
  Severity[Severity["Moderate"] = 2] = "Moderate";
@@ -589497,13 +590049,13 @@ var init_adaptive_pipeline = __esm(() => {
589497
590049
 
589498
590050
  // packages/orchestration/pipeline-cli.ts
589499
590051
  import { mkdirSync as mkdirSync80, writeFileSync as writeFileSync61 } from "node:fs";
589500
- import { join as join163, resolve as resolve69 } from "node:path";
590052
+ import { join as join165, resolve as resolve71 } from "node:path";
589501
590053
  async function runPipelineCommand(args) {
589502
- let outDir = resolve69(process.cwd(), "pipeline-output");
590054
+ let outDir = resolve71(process.cwd(), "pipeline-output");
589503
590055
  const taskParts = [];
589504
590056
  for (let i = 0;i < args.length; i++) {
589505
590057
  if (args[i] === "--out" && args[i + 1]) {
589506
- outDir = resolve69(args[++i]);
590058
+ outDir = resolve71(args[++i]);
589507
590059
  } else if (!args[i].startsWith("-")) {
589508
590060
  taskParts.push(args[i]);
589509
590061
  }
@@ -589523,7 +590075,7 @@ async function runPipelineCommand(args) {
589523
590075
  });
589524
590076
  const result = await pipeline.run(task);
589525
590077
  mkdirSync80(outDir, { recursive: true });
589526
- const artifactPath = join163(outDir, "index.html");
590078
+ const artifactPath = join165(outDir, "index.html");
589527
590079
  writeFileSync61(artifactPath, result.artifact || "<!-- pipeline produced no artifact -->");
589528
590080
  console.log("");
589529
590081
  console.log(`stages : ${result.stages.length}`);
@@ -589625,7 +590177,7 @@ var init_port_probe = () => {};
589625
590177
  import { randomBytes as randomBytes10, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
589626
590178
  import { appendFileSync as appendFileSync24, mkdirSync as mkdirSync81 } from "node:fs";
589627
590179
  import { homedir as homedir82 } from "node:os";
589628
- import { join as join164 } from "node:path";
590180
+ import { join as join166 } from "node:path";
589629
590181
  function envMs(name, fallback) {
589630
590182
  const n = Number(process.env[name]);
589631
590183
  return Number.isFinite(n) && n > 0 ? n : fallback;
@@ -589656,9 +590208,9 @@ function allowable(command) {
589656
590208
  }
589657
590209
  function auditApproval(line) {
589658
590210
  try {
589659
- const dir = process.env.EIGHT_DATA_DIR || join164(homedir82(), ".8gent");
590211
+ const dir = process.env.EIGHT_DATA_DIR || join166(homedir82(), ".8gent");
589660
590212
  mkdirSync81(dir, { recursive: true });
589661
- appendFileSync24(join164(dir, "approvals-audit.jsonl"), `${JSON.stringify({ ts: new Date().toISOString(), ...line })}
590213
+ appendFileSync24(join166(dir, "approvals-audit.jsonl"), `${JSON.stringify({ ts: new Date().toISOString(), ...line })}
589662
590214
  `, { mode: 384 });
589663
590215
  } catch (err) {
589664
590216
  console.error("[channel-approvals] audit write failed:", err.message);
@@ -589820,19 +590372,19 @@ var init_classroom = __esm(() => {
589820
590372
  import { randomBytes as randomBytes11 } from "node:crypto";
589821
590373
  import {
589822
590374
  closeSync as closeSync21,
589823
- existsSync as existsSync110,
590375
+ existsSync as existsSync112,
589824
590376
  fchmodSync as fchmodSync5,
589825
590377
  fsyncSync as fsyncSync2,
589826
590378
  linkSync,
589827
590379
  mkdirSync as mkdirSync82,
589828
590380
  openSync as openSync21,
589829
- readFileSync as readFileSync101,
590381
+ readFileSync as readFileSync102,
589830
590382
  renameSync as renameSync15,
589831
590383
  unlinkSync as unlinkSync4,
589832
590384
  writeSync as writeSync6
589833
590385
  } from "node:fs";
589834
590386
  import { cpus } from "node:os";
589835
- import { dirname as dirname74 } from "node:path";
590387
+ import { dirname as dirname75 } from "node:path";
589836
590388
  function startLimitFor(maxSessions, requested) {
589837
590389
  const env = Number(process.env.EIGHT_WORK_QUEUE_STARTS);
589838
590390
  const n = requested ?? (Number.isInteger(env) && env > 0 ? env : Math.floor(cpus().length / 2));
@@ -589873,7 +590425,7 @@ function acquireLock(lockPath, opts = {}) {
589873
590425
  return;
589874
590426
  let judged;
589875
590427
  try {
589876
- judged = readFileSync101(lockPath, "utf8");
590428
+ judged = readFileSync102(lockPath, "utf8");
589877
590429
  } catch (err) {
589878
590430
  if (errCode2(err) === "ENOENT")
589879
590431
  continue;
@@ -589892,7 +590444,7 @@ function acquireLock(lockPath, opts = {}) {
589892
590444
  continue;
589893
590445
  throw err;
589894
590446
  }
589895
- const took = readFileSync101(moved, "utf8");
590447
+ const took = readFileSync102(moved, "utf8");
589896
590448
  if (took === judged) {
589897
590449
  unlinkSync4(moved);
589898
590450
  continue;
@@ -589920,15 +590472,15 @@ class WorkQueue {
589920
590472
  constructor(path, opts) {
589921
590473
  this.path = path;
589922
590474
  this.startLimit = startLimitFor(opts.maxSessions, opts.startLimit);
589923
- const dir = dirname74(path);
589924
- if (!existsSync110(dir))
590475
+ const dir = dirname75(path);
590476
+ if (!existsSync112(dir))
589925
590477
  mkdirSync82(dir, { recursive: true, mode: 448 });
589926
590478
  this.lockPath = `${path}.lock`;
589927
590479
  acquireLock(this.lockPath);
589928
590480
  let raw = "";
589929
590481
  try {
589930
- if (existsSync110(path))
589931
- raw = readFileSync101(path, "utf8");
590482
+ if (existsSync112(path))
590483
+ raw = readFileSync102(path, "utf8");
589932
590484
  this.replay(raw);
589933
590485
  this.fd = openSync21(path, "a", 384);
589934
590486
  fchmodSync5(this.fd, 384);
@@ -590050,7 +590602,7 @@ class WorkQueue {
590050
590602
  }
590051
590603
  releaseLock() {
590052
590604
  try {
590053
- if (readFileSync101(this.lockPath, "utf8").trim() === String(process.pid)) {
590605
+ if (readFileSync102(this.lockPath, "utf8").trim() === String(process.pid)) {
590054
590606
  unlinkSync4(this.lockPath);
590055
590607
  }
590056
590608
  } catch {}
@@ -591009,7 +591561,7 @@ var init_dispatch = __esm(() => {
591009
591561
  });
591010
591562
 
591011
591563
  // packages/harness/adapters/cli.ts
591012
- import { spawn as spawn23 } from "node:child_process";
591564
+ import { spawn as spawn24 } from "node:child_process";
591013
591565
 
591014
591566
  class CliHarness {
591015
591567
  name;
@@ -591052,7 +591604,7 @@ class CliHarness {
591052
591604
  const argv = buildArgv(this.config, task.prompt);
591053
591605
  let child;
591054
591606
  try {
591055
- child = spawn23(argv[0], argv.slice(1), {
591607
+ child = spawn24(argv[0], argv.slice(1), {
591056
591608
  cwd: task.cwd || process.cwd(),
591057
591609
  env: { ...process.env, ...this.config.env },
591058
591610
  detached: process.platform !== "win32",
@@ -592898,7 +593450,7 @@ var init_post_to_channel = __esm(() => {
592898
593450
 
592899
593451
  // packages/table/huddle-voice.ts
592900
593452
  import { spawnSync as spawnSync13 } from "node:child_process";
592901
- import { existsSync as existsSync112 } from "node:fs";
593453
+ import { existsSync as existsSync114 } from "node:fs";
592902
593454
  function voiceFor(code) {
592903
593455
  return VOICES[code.toUpperCase()] ?? HUMAN_VOICE;
592904
593456
  }
@@ -592913,11 +593465,11 @@ function inQuietHours(now) {
592913
593465
  }
592914
593466
  function findSupertonic() {
592915
593467
  for (const p of SUPERTONIC_CANDIDATES)
592916
- if (existsSync112(p))
593468
+ if (existsSync114(p))
592917
593469
  return p;
592918
593470
  const which = spawnSync13("which", ["supertonic"], { encoding: "utf8" });
592919
593471
  const found = which.stdout?.trim();
592920
- return found && existsSync112(found) ? found : null;
593472
+ return found && existsSync114(found) ? found : null;
592921
593473
  }
592922
593474
  function speechText(text, maxChars = 480) {
592923
593475
  const cleaned = text.replace(/\(verified:[^)]*\)/g, "").replace(/\[CLAIM STRIPPED:[^\]]*\]/g, "").replace(/`+/g, "").replace(/^[\s>*-]+/gm, "").replace(/\s+/g, " ").trim();
@@ -592950,7 +593502,7 @@ function narrateTurn(opts) {
592950
593502
  if (!bin)
592951
593503
  return { audioPath: null, durationMs: estimate, skipped: "no_tts" };
592952
593504
  const r = spawnSync13(bin, ["tts", text, "-o", opts.outPath, "--voice", opts.voice.supertonic, "--steps", String(opts.steps ?? 8)], { encoding: "utf8", timeout: 120000 });
592953
- if (r.status !== 0 || !existsSync112(opts.outPath)) {
593505
+ if (r.status !== 0 || !existsSync114(opts.outPath)) {
592954
593506
  return { audioPath: null, durationMs: estimate, skipped: "tts_failed" };
592955
593507
  }
592956
593508
  return { audioPath: opts.outPath, durationMs: probeDurationMs(opts.outPath) ?? estimate };
@@ -592976,7 +593528,7 @@ var init_huddle_voice = __esm(() => {
592976
593528
  });
592977
593529
 
592978
593530
  // packages/table/message-speak.ts
592979
- import { mkdtempSync as mkdtempSync10, readFileSync as readFileSync104, rmSync as rmSync15 } from "node:fs";
593531
+ import { mkdtempSync as mkdtempSync10, readFileSync as readFileSync105, rmSync as rmSync15 } from "node:fs";
592980
593532
  import * as os53 from "node:os";
592981
593533
  import * as path122 from "node:path";
592982
593534
  function voiceForAuthor(authorId, voiceFor) {
@@ -593000,7 +593552,7 @@ async function synthesizeMessageSpeech(message, deps = defaultDeps) {
593000
593552
  const reason = result.skipped === "empty_text" ? "empty_text" : "tts_failed";
593001
593553
  return { ok: false, reason: result.skipped === "no_tts" ? "no_tts" : reason };
593002
593554
  }
593003
- const bytes = readFileSync104(result.audioPath);
593555
+ const bytes = readFileSync105(result.audioPath);
593004
593556
  return { ok: true, bytes, durationMs: result.durationMs };
593005
593557
  } finally {
593006
593558
  rmSync15(dir, { recursive: true, force: true });
@@ -593051,7 +593603,7 @@ var init_message_speak = __esm(() => {
593051
593603
  });
593052
593604
 
593053
593605
  // packages/table/message-audio.ts
593054
- import { existsSync as existsSync113, mkdirSync as mkdirSync86, readFileSync as readFileSync105 } from "node:fs";
593606
+ import { existsSync as existsSync115, mkdirSync as mkdirSync86, readFileSync as readFileSync106 } from "node:fs";
593055
593607
  import * as os54 from "node:os";
593056
593608
  import * as path123 from "node:path";
593057
593609
  function messageAudioRoot() {
@@ -593067,10 +593619,10 @@ function handleTableAudioHttp(url) {
593067
593619
  return null;
593068
593620
  const [, messageId, file] = m;
593069
593621
  const filePath = path123.join(messageAudioDir(messageId), file);
593070
- if (!existsSync113(filePath))
593622
+ if (!existsSync115(filePath))
593071
593623
  return new Response("not found", { status: 404 });
593072
593624
  const ext = file.slice(file.lastIndexOf("."));
593073
- return new Response(readFileSync105(filePath), {
593625
+ return new Response(readFileSync106(filePath), {
593074
593626
  headers: {
593075
593627
  "content-type": MIME[ext] ?? "application/octet-stream",
593076
593628
  "cache-control": "no-store"
@@ -595189,7 +595741,7 @@ function fnv1a(text) {
595189
595741
  function draw(seedText, axis, options) {
595190
595742
  return options[fnv1a(`${axis}:${seedText}`) % options.length];
595191
595743
  }
595192
- function resolve70(intent) {
595744
+ function resolve72(intent) {
595193
595745
  const tone = intent.tone ?? "";
595194
595746
  if (tone && !TONES[tone]) {
595195
595747
  throw new DesignRefused("intent.tone", `unknown tone ${JSON.stringify(tone)}. Known tones: ${TONE_NAMES.join(", ")}.`);
@@ -595273,7 +595825,7 @@ function coordinateId(c) {
595273
595825
  return fnv1a(canonical).toString(16).padStart(8, "0");
595274
595826
  }
595275
595827
  function compose(intent) {
595276
- return composeAt(resolve70(intent), intent);
595828
+ return composeAt(resolve72(intent), intent);
595277
595829
  }
595278
595830
  var TONES, TONE_NAMES, BASE_PX;
595279
595831
  var init_compose = __esm(() => {
@@ -596062,18 +596614,18 @@ var init_slide_render = __esm(() => {
596062
596614
  // packages/table/bake.ts
596063
596615
  import { spawnSync as spawnSync14 } from "node:child_process";
596064
596616
  import { createHash as createHash26 } from "node:crypto";
596065
- import { existsSync as existsSync114, mkdirSync as mkdirSync87, readdirSync as readdirSync27, readFileSync as readFileSync106, rmSync as rmSync16, writeFileSync as writeFileSync63 } from "node:fs";
596066
- import { basename as basename50, join as join171 } from "node:path";
596617
+ import { existsSync as existsSync116, mkdirSync as mkdirSync87, readdirSync as readdirSync27, readFileSync as readFileSync107, rmSync as rmSync16, writeFileSync as writeFileSync63 } from "node:fs";
596618
+ import { basename as basename51, join as join173 } from "node:path";
596067
596619
  function findChrome3() {
596068
- return CHROME_CANDIDATES2.find((p) => existsSync114(p)) ?? null;
596620
+ return CHROME_CANDIDATES2.find((p) => existsSync116(p)) ?? null;
596069
596621
  }
596070
596622
  function huddleDir(huddleId) {
596071
- return join171(HUDDLES_DIR, huddleId);
596623
+ return join173(HUDDLES_DIR, huddleId);
596072
596624
  }
596073
596625
  function ensureHuddleDirs(huddleId) {
596074
596626
  const dir = huddleDir(huddleId);
596075
596627
  for (const sub of ["", "slides", "audio", "deck"])
596076
- mkdirSync87(join171(dir, sub), { recursive: true });
596628
+ mkdirSync87(join173(dir, sub), { recursive: true });
596077
596629
  return dir;
596078
596630
  }
596079
596631
  function slideToPng(htmlPath, pngPath, chrome) {
@@ -596087,7 +596639,7 @@ function slideToPng(htmlPath, pngPath, chrome) {
596087
596639
  `--screenshot=${pngPath}`,
596088
596640
  `file://${htmlPath}`
596089
596641
  ], { encoding: "utf8", timeout: 60000 });
596090
- return r.status === 0 && existsSync114(pngPath);
596642
+ return r.status === 0 && existsSync116(pngPath);
596091
596643
  }
596092
596644
  function emitDeckV2V(manifest) {
596093
596645
  const slides = manifest.turns.map((t) => {
@@ -596188,11 +596740,11 @@ function ffmpegClip(args) {
596188
596740
  return r.status === 0;
596189
596741
  }
596190
596742
  function sha256File(path) {
596191
- return createHash26("sha256").update(readFileSync106(path)).digest("hex");
596743
+ return createHash26("sha256").update(readFileSync107(path)).digest("hex");
596192
596744
  }
596193
596745
  function writeRecordingToManifest(manifestPath, manifest, videoPath) {
596194
596746
  const recording = {
596195
- file: basename50(videoPath),
596747
+ file: basename51(videoPath),
596196
596748
  sha256: sha256File(videoPath),
596197
596749
  bakedAt: Date.now()
596198
596750
  };
@@ -596207,13 +596759,13 @@ function slugify4(text, fallback = "huddle") {
596207
596759
  function bakeHuddle(manifest, stamp) {
596208
596760
  const dir = ensureHuddleDirs(manifest.huddleId);
596209
596761
  mkdirSync87(CREATIVE_DIR2, { recursive: true });
596210
- const manifestPath = join171(dir, "manifest.json");
596762
+ const manifestPath = join173(dir, "manifest.json");
596211
596763
  writeFileSync63(manifestPath, JSON.stringify(manifest, null, 2), "utf8");
596212
- const deckPath = join171(dir, "deck", "deck.html");
596764
+ const deckPath = join173(dir, "deck", "deck.html");
596213
596765
  writeFileSync63(deckPath, emitDeckHyperframes(manifest), "utf8");
596214
- const deckV2VPath = join171(dir, "deck", "deck-v2v.html");
596766
+ const deckV2VPath = join173(dir, "deck", "deck-v2v.html");
596215
596767
  writeFileSync63(deckV2VPath, emitDeckV2V(manifest), "utf8");
596216
- const transcriptPath = join171(dir, "transcript.md");
596768
+ const transcriptPath = join173(dir, "transcript.md");
596217
596769
  writeFileSync63(transcriptPath, emitTranscript(manifest), "utf8");
596218
596770
  const result = { manifestPath, deckPath, deckV2VPath, transcriptPath, videoPath: null, slidePngs: [] };
596219
596771
  if (manifest.turns.length === 0) {
@@ -596225,11 +596777,11 @@ function bakeHuddle(manifest, stamp) {
596225
596777
  result.videoError = "no Chrome/Chromium found for slide capture";
596226
596778
  return result;
596227
596779
  }
596228
- const work = join171(dir, "work");
596780
+ const work = join173(dir, "work");
596229
596781
  mkdirSync87(work, { recursive: true });
596230
596782
  for (const turn of manifest.turns) {
596231
- const htmlPath = join171(dir, "slides", `slide-${turn.turnId}.html`);
596232
- if (!existsSync114(htmlPath)) {
596783
+ const htmlPath = join173(dir, "slides", `slide-${turn.turnId}.html`);
596784
+ if (!existsSync116(htmlPath)) {
596233
596785
  const { html } = renderSlide(turn.spec, {
596234
596786
  code: turn.code,
596235
596787
  name: turn.name,
@@ -596240,7 +596792,7 @@ function bakeHuddle(manifest, stamp) {
596240
596792
  });
596241
596793
  writeFileSync63(htmlPath, html, "utf8");
596242
596794
  }
596243
- const png = join171(dir, "slides", `slide-${turn.turnId}.png`);
596795
+ const png = join173(dir, "slides", `slide-${turn.turnId}.png`);
596244
596796
  if (!slideToPng(htmlPath, png, chrome)) {
596245
596797
  result.videoError = `slide capture failed for turn ${turn.index}`;
596246
596798
  return result;
@@ -596249,11 +596801,11 @@ function bakeHuddle(manifest, stamp) {
596249
596801
  }
596250
596802
  const clips = [];
596251
596803
  for (const turn of manifest.turns) {
596252
- const png = join171(dir, "slides", `slide-${turn.turnId}.png`);
596253
- const clip = join171(work, `clip-${String(turn.index).padStart(3, "0")}.mp4`);
596804
+ const png = join173(dir, "slides", `slide-${turn.turnId}.png`);
596805
+ const clip = join173(work, `clip-${String(turn.index).padStart(3, "0")}.mp4`);
596254
596806
  const secs = (turn.durationMs / 1000).toFixed(3);
596255
596807
  const video = ["-loop", "1", "-framerate", "30", "-t", secs, "-i", png];
596256
- const audio = turn.audioPath && existsSync114(turn.audioPath) ? ["-ss", (turn.audioOffsetMs / 1000).toFixed(3), "-t", secs, "-i", turn.audioPath] : ["-f", "lavfi", "-t", secs, "-i", "anullsrc=r=44100:cl=stereo"];
596808
+ const audio = turn.audioPath && existsSync116(turn.audioPath) ? ["-ss", (turn.audioOffsetMs / 1000).toFixed(3), "-t", secs, "-i", turn.audioPath] : ["-f", "lavfi", "-t", secs, "-i", "anullsrc=r=44100:cl=stereo"];
596257
596809
  const ok = ffmpegClip([
596258
596810
  "-y",
596259
596811
  ...video,
@@ -596283,19 +596835,19 @@ function bakeHuddle(manifest, stamp) {
596283
596835
  "-shortest",
596284
596836
  clip
596285
596837
  ]);
596286
- if (!ok || !existsSync114(clip)) {
596838
+ if (!ok || !existsSync116(clip)) {
596287
596839
  result.videoError = `ffmpeg clip failed for turn ${turn.index}`;
596288
596840
  return result;
596289
596841
  }
596290
596842
  clips.push(clip);
596291
596843
  }
596292
- const listPath = join171(work, "clips.txt");
596844
+ const listPath = join173(work, "clips.txt");
596293
596845
  writeFileSync63(listPath, clips.map((c) => `file '${c.replace(/'/g, "'\\''")}'`).join(`
596294
596846
  `), "utf8");
596295
596847
  const outName = `huddle-${slugify4(manifest.topic)}-${stamp}.mp4`;
596296
- const outPath = join171(CREATIVE_DIR2, outName);
596848
+ const outPath = join173(CREATIVE_DIR2, outName);
596297
596849
  const ok = ffmpegClip(["-y", "-f", "concat", "-safe", "0", "-i", listPath, "-c", "copy", "-movflags", "+faststart", outPath]);
596298
- if (!ok || !existsSync114(outPath)) {
596850
+ if (!ok || !existsSync116(outPath)) {
596299
596851
  result.videoError = "ffmpeg concat failed";
596300
596852
  return result;
596301
596853
  }
@@ -596314,8 +596866,8 @@ var CREATIVE_DIR2, HUDDLES_DIR, CHROME_CANDIDATES2;
596314
596866
  var init_bake = __esm(() => {
596315
596867
  init_home();
596316
596868
  init_slide_render();
596317
- CREATIVE_DIR2 = join171(resolveHome(), ".8gent", "creative");
596318
- HUDDLES_DIR = join171(resolveHome(), ".8gent", "huddles");
596869
+ CREATIVE_DIR2 = join173(resolveHome(), ".8gent", "creative");
596870
+ HUDDLES_DIR = join173(resolveHome(), ".8gent", "huddles");
596319
596871
  CHROME_CANDIDATES2 = [
596320
596872
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
596321
596873
  "/Applications/Chromium.app/Contents/MacOS/Chromium",
@@ -597764,8 +598316,8 @@ var init_zen = __esm(() => {
597764
598316
  });
597765
598317
 
597766
598318
  // packages/daemon/huddle-stage.ts
597767
- import { existsSync as existsSync115, mkdirSync as mkdirSync88, readFileSync as readFileSync108, writeFileSync as writeFileSync64 } from "node:fs";
597768
- import { join as join173 } from "node:path";
598319
+ import { existsSync as existsSync117, mkdirSync as mkdirSync88, readFileSync as readFileSync109, writeFileSync as writeFileSync64 } from "node:fs";
598320
+ import { join as join175 } from "node:path";
597769
598321
  function openStage(huddleId, channelId, topic) {
597770
598322
  ensureHuddleDirs(huddleId);
597771
598323
  stages.set(huddleId, {
@@ -597815,7 +598367,7 @@ function nameOf2(holder) {
597815
598367
  }
597816
598368
  function claimRoots() {
597817
598369
  const home = resolveHome();
597818
- return [join173(home, "8gent-code"), join173(home, "8gi-governance"), getDataDir()];
598370
+ return [join175(home, "8gent-code"), join175(home, "8gi-governance"), getDataDir()];
597819
598371
  }
597820
598372
  async function runTurnPipeline(huddleId, turnId, holder, replyText, broadcast, opts = {}) {
597821
598373
  const state = stages.get(huddleId);
@@ -597836,7 +598388,7 @@ async function runTurnPipeline(huddleId, turnId, holder, replyText, broadcast, o
597836
598388
  };
597837
598389
  const { html, sha256 } = renderSlide(verified.spec, ctx);
597838
598390
  const dir = ensureHuddleDirs(huddleId);
597839
- writeFileSync64(join173(dir, "slides", `slide-${turnId}.html`), html, "utf8");
598391
+ writeFileSync64(join175(dir, "slides", `slide-${turnId}.html`), html, "utf8");
597840
598392
  broadcast(state.channelId, {
597841
598393
  type: "huddle:slide",
597842
598394
  huddleId,
@@ -597851,7 +598403,7 @@ async function runTurnPipeline(huddleId, turnId, holder, replyText, broadcast, o
597851
598403
  });
597852
598404
  await waitForStage(state, huddleId, turnId);
597853
598405
  const voice = voiceFor(code);
597854
- const wav = join173(dir, "audio", `turn-${turnId}.wav`);
598406
+ const wav = join175(dir, "audio", `turn-${turnId}.wav`);
597855
598407
  const speech = speechText(resolved.speech);
597856
598408
  const narration = mediaEnabled ? narrateTurn({ text: speech, voice, outPath: wav, interactive: opts.interactive ?? true }) : { audioPath: null, durationMs: estimateReadingMs(speech), skipped: "no_tts" };
597857
598409
  try {
@@ -597895,9 +598447,9 @@ function ingestDictation(huddleId, holder, wavPath, whisperJsonPath, broadcast)
597895
598447
  const state = stages.get(huddleId);
597896
598448
  if (!state)
597897
598449
  return 0;
597898
- if (!existsSync115(whisperJsonPath))
598450
+ if (!existsSync117(whisperJsonPath))
597899
598451
  return 0;
597900
- const segments = parseWhisperJson(readFileSync108(whisperJsonPath, "utf8"));
598452
+ const segments = parseWhisperJson(readFileSync109(whisperJsonPath, "utf8"));
597901
598453
  const slides = zenSlides(segments, Object.keys(OFFICERS));
597902
598454
  const dir = ensureHuddleDirs(huddleId);
597903
598455
  const name = nameOf2(holder);
@@ -597906,7 +598458,7 @@ function ingestDictation(huddleId, holder, wavPath, whisperJsonPath, broadcast)
597906
598458
  const index = state.turns.length;
597907
598459
  const ctx = { code: "HUMAN", name, index: index + 1, huddleId };
597908
598460
  const { html, sha256 } = renderSlide(slide.spec, ctx);
597909
- writeFileSync64(join173(dir, "slides", `slide-${turnId}.html`), html, "utf8");
598461
+ writeFileSync64(join175(dir, "slides", `slide-${turnId}.html`), html, "utf8");
597910
598462
  broadcast(state.channelId, {
597911
598463
  type: "huddle:slide",
597912
598464
  huddleId,
@@ -597953,11 +598505,11 @@ function closeStage(huddleId) {
597953
598505
  turns: state.turns
597954
598506
  };
597955
598507
  if (!mediaEnabled) {
597956
- writeFileSync64(join173(ensureHuddleDirs(huddleId), "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
598508
+ writeFileSync64(join175(ensureHuddleDirs(huddleId), "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
597957
598509
  return {
597958
598510
  videoPath: null,
597959
598511
  videoError: "media disabled for this process",
597960
- transcriptPath: join173(huddleDir(huddleId), "transcript.md"),
598512
+ transcriptPath: join175(huddleDir(huddleId), "transcript.md"),
597961
598513
  turnCount: state.turns.length,
597962
598514
  hashes: state.turns.map((t) => t.sha256)
597963
598515
  };
@@ -597976,7 +598528,7 @@ function closeStage(huddleId) {
597976
598528
  return {
597977
598529
  videoPath: null,
597978
598530
  videoError: err.message,
597979
- transcriptPath: join173(huddleDir(huddleId), "transcript.md"),
598531
+ transcriptPath: join175(huddleDir(huddleId), "transcript.md"),
597980
598532
  turnCount: state.turns.length,
597981
598533
  hashes: state.turns.map((t) => t.sha256)
597982
598534
  };
@@ -598000,11 +598552,11 @@ function handleStageHttp(url, wsUrl) {
598000
598552
  }
598001
598553
  if (!file || file.includes(".."))
598002
598554
  return new Response("not found", { status: 404 });
598003
- const path = join173(huddleDir(huddleId), kind, file);
598004
- if (!existsSync115(path))
598555
+ const path = join175(huddleDir(huddleId), kind, file);
598556
+ if (!existsSync117(path))
598005
598557
  return new Response("not found", { status: 404 });
598006
598558
  const ext = file.slice(file.lastIndexOf("."));
598007
- return new Response(readFileSync108(path), {
598559
+ return new Response(readFileSync109(path), {
598008
598560
  headers: { "content-type": MIME2[ext] ?? "application/octet-stream", "cache-control": "no-store" }
598009
598561
  });
598010
598562
  }
@@ -598327,7 +598879,7 @@ var init_shared_sessions = __esm(() => {
598327
598879
 
598328
598880
  // packages/daemon/live-anatomy.ts
598329
598881
  import { timingSafeEqual as timingSafeEqual5 } from "node:crypto";
598330
- import { readFileSync as readFileSync109 } from "node:fs";
598882
+ import { readFileSync as readFileSync110 } from "node:fs";
598331
598883
  function obj(v) {
598332
598884
  return v && typeof v === "object" && !Array.isArray(v) ? v : {};
598333
598885
  }
@@ -598672,7 +599224,7 @@ function liveClose(ws) {
598672
599224
  }
598673
599225
  function mermaidScript() {
598674
599226
  try {
598675
- mermaidJs ??= readFileSync109(Bun.resolveSync("mermaid/dist/mermaid.min.js", import.meta.dirname + "/../../packages/daemon"), "utf8");
599227
+ mermaidJs ??= readFileSync110(Bun.resolveSync("mermaid/dist/mermaid.min.js", import.meta.dirname + "/../../packages/daemon"), "utf8");
598676
599228
  } catch {
598677
599229
  return new Response("mermaid is not installed next to the daemon", { status: 503 });
598678
599230
  }
@@ -599880,13 +600432,13 @@ var init_workspace_db = __esm(() => {
599880
600432
  });
599881
600433
 
599882
600434
  // packages/daemon/routes/store/audit.ts
599883
- import { appendFileSync as appendFileSync26, existsSync as existsSync117, mkdirSync as mkdirSync90 } from "node:fs";
600435
+ import { appendFileSync as appendFileSync26, existsSync as existsSync119, mkdirSync as mkdirSync90 } from "node:fs";
599884
600436
  import * as path127 from "node:path";
599885
600437
  function auditDir() {
599886
600438
  if (_auditDir)
599887
600439
  return _auditDir;
599888
600440
  const dir = path127.join(getDataDir(), "audit");
599889
- if (!existsSync117(dir)) {
600441
+ if (!existsSync119(dir)) {
599890
600442
  try {
599891
600443
  mkdirSync90(dir, { recursive: true });
599892
600444
  } catch (err) {
@@ -601226,7 +601778,7 @@ var init_session2 = __esm(() => {
601226
601778
  });
601227
601779
 
601228
601780
  // packages/daemon/routes/store/index.ts
601229
- import { existsSync as existsSync121, mkdirSync as mkdirSync94, readFileSync as readFileSync112, writeFileSync as writeFileSync67 } from "node:fs";
601781
+ import { existsSync as existsSync123, mkdirSync as mkdirSync94, readFileSync as readFileSync113, writeFileSync as writeFileSync67 } from "node:fs";
601230
601782
  import * as crypto13 from "node:crypto";
601231
601783
  import * as path131 from "node:path";
601232
601784
  function ensureServerToken(tokenPath) {
@@ -601234,10 +601786,10 @@ function ensureServerToken(tokenPath) {
601234
601786
  return _cachedToken;
601235
601787
  const file = tokenPath ?? path131.join(getDataDir(), "server.token");
601236
601788
  const dir = path131.dirname(file);
601237
- if (!existsSync121(dir))
601789
+ if (!existsSync123(dir))
601238
601790
  mkdirSync94(dir, { recursive: true });
601239
- if (existsSync121(file)) {
601240
- const t = readFileSync112(file, "utf-8").trim();
601791
+ if (existsSync123(file)) {
601792
+ const t = readFileSync113(file, "utf-8").trim();
601241
601793
  if (t.length >= 32) {
601242
601794
  if (!tokenPath)
601243
601795
  _cachedToken = t;
@@ -603111,7 +603663,7 @@ var PREPARE_BUDGET_MS = 120000, SPEAK_GRACE_MS = 500, SPEAK_BUDGET_MS = 120000,
603111
603663
 
603112
603664
  // packages/daemon/huddle-minutes.ts
603113
603665
  import { writeFileSync as writeFileSync68 } from "node:fs";
603114
- import { join as join180 } from "node:path";
603666
+ import { join as join182 } from "node:path";
603115
603667
  function turnsBlock(turns) {
603116
603668
  const lines = turns.map((t) => `${t.code === "HUMAN" ? t.name : `${t.code} ${t.name}`}: ${t.text.slice(0, TURN_TEXT_CAP)}`);
603117
603669
  let block = lines.join(`
@@ -603276,7 +603828,7 @@ Your previous reply was not valid JSON matching the contract. Reply again with O
603276
603828
  }
603277
603829
  function writeMinutesFile(minutes) {
603278
603830
  const dir = ensureHuddleDirs(minutes.huddleId);
603279
- const path = join180(dir, "minutes.json");
603831
+ const path = join182(dir, "minutes.json");
603280
603832
  writeFileSync68(path, JSON.stringify(minutes, null, 2), "utf8");
603281
603833
  return path;
603282
603834
  }
@@ -605126,12 +605678,12 @@ var init_gateway = __esm(() => {
605126
605678
  });
605127
605679
 
605128
605680
  // packages/daemon/heartbeat.ts
605129
- import { join as join181 } from "node:path";
605681
+ import { join as join183 } from "node:path";
605130
605682
  function taskQueuePath() {
605131
- return join181(getDataDir(), "task-queue.json");
605683
+ return join183(getDataDir(), "task-queue.json");
605132
605684
  }
605133
605685
  function inboxPath() {
605134
- return join181(getDataDir(), "inbox.json");
605686
+ return join183(getDataDir(), "inbox.json");
605135
605687
  }
605136
605688
  function defaultConfig() {
605137
605689
  return {
@@ -606061,14 +606613,14 @@ import { createHash as createHash31, createHmac as createHmac4, randomBytes as r
606061
606613
  import {
606062
606614
  appendFileSync as appendFileSync27,
606063
606615
  chmodSync as chmodSync6,
606064
- existsSync as existsSync122,
606616
+ existsSync as existsSync124,
606065
606617
  mkdirSync as mkdirSync96,
606066
- readFileSync as readFileSync114,
606618
+ readFileSync as readFileSync115,
606067
606619
  rmSync as rmSync18,
606068
606620
  truncateSync as truncateSync2,
606069
606621
  writeFileSync as writeFileSync69
606070
606622
  } from "node:fs";
606071
- import { dirname as dirname80 } from "node:path";
606623
+ import { dirname as dirname81 } from "node:path";
606072
606624
  function digest(line) {
606073
606625
  return createHash31("sha256").update(line.prev).update(`
606074
606626
  `).update(JSON.stringify(line)).digest("hex");
@@ -606087,15 +606639,15 @@ class AuditLog {
606087
606639
  constructor(path, saltPath, clock = Date.now, onRepair = () => {}) {
606088
606640
  this.path = path;
606089
606641
  this.clock = clock;
606090
- ensurePrivateDir(dirname80(path));
606091
- if (existsSync122(saltPath)) {
606092
- this.salt = readFileSync114(saltPath);
606642
+ ensurePrivateDir(dirname81(path));
606643
+ if (existsSync124(saltPath)) {
606644
+ this.salt = readFileSync115(saltPath);
606093
606645
  } else {
606094
606646
  this.salt = randomBytes16(32);
606095
606647
  writeFileSync69(saltPath, this.salt, { mode: 384 });
606096
606648
  chmodSync6(saltPath, 384);
606097
606649
  }
606098
- if (existsSync122(path)) {
606650
+ if (existsSync124(path)) {
606099
606651
  const dropped = repairTornTail(path);
606100
606652
  if (dropped > 0)
606101
606653
  onRepair(dropped);
@@ -606138,7 +606690,7 @@ class AuditLog {
606138
606690
  }
606139
606691
  }
606140
606692
  function repairTornTail(path) {
606141
- const buf = readFileSync114(path);
606693
+ const buf = readFileSync115(path);
606142
606694
  if (buf.length === 0 || buf[buf.length - 1] === 10)
606143
606695
  return 0;
606144
606696
  const cut = buf.lastIndexOf(10) + 1;
@@ -606153,9 +606705,9 @@ function repairTornTail(path) {
606153
606705
  return buf.length - cut;
606154
606706
  }
606155
606707
  function verifyAudit(path) {
606156
- if (!existsSync122(path))
606708
+ if (!existsSync124(path))
606157
606709
  return { ok: true, count: 0, lastHash: GENESIS };
606158
- const lines = readFileSync114(path, "utf8").split(`
606710
+ const lines = readFileSync115(path, "utf8").split(`
606159
606711
  `).filter(Boolean);
606160
606712
  let prev = GENESIS;
606161
606713
  for (let i = 0;i < lines.length; i++) {
@@ -606187,15 +606739,15 @@ import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv
606187
606739
  import {
606188
606740
  chmodSync as chmodSync7,
606189
606741
  closeSync as closeSync24,
606190
- existsSync as existsSync123,
606742
+ existsSync as existsSync125,
606191
606743
  fsyncSync as fsyncSync4,
606192
606744
  openSync as openSync24,
606193
- readFileSync as readFileSync115,
606745
+ readFileSync as readFileSync116,
606194
606746
  renameSync as renameSync17,
606195
606747
  unlinkSync as unlinkSync7,
606196
606748
  writeSync as writeSync8
606197
606749
  } from "node:fs";
606198
- import { dirname as dirname81, join as join182 } from "node:path";
606750
+ import { dirname as dirname82, join as join184 } from "node:path";
606199
606751
  function seal(plain, key) {
606200
606752
  const iv = randomBytes17(12);
606201
606753
  const c = createCipheriv2("aes-256-gcm", key, iv);
@@ -606222,15 +606774,15 @@ class MemoryVault {
606222
606774
  constructor(dir, store, key) {
606223
606775
  this.store = store;
606224
606776
  this.key = key;
606225
- this.file = join182(dir, "memory.db.enc");
606777
+ this.file = join184(dir, "memory.db.enc");
606226
606778
  }
606227
606779
  static open(dir, keyProvider = keychainKey) {
606228
606780
  const key = keyProvider();
606229
606781
  if (!key || key.length !== 32)
606230
606782
  throw new Error("vault: no encryption key available");
606231
606783
  ensurePrivateDir(dir);
606232
- const file = join182(dir, "memory.db.enc");
606233
- const db = existsSync123(file) ? Database.deserialize(unseal(readFileSync115(file), key)) : new Database(":memory:");
606784
+ const file = join184(dir, "memory.db.enc");
606785
+ const db = existsSync125(file) ? Database.deserialize(unseal(readFileSync116(file), key)) : new Database(":memory:");
606234
606786
  db.exec("PRAGMA secure_delete = ON");
606235
606787
  const vault = new MemoryVault(dir, new MemoryStore(db), key);
606236
606788
  vault.persist();
@@ -606249,7 +606801,7 @@ class MemoryVault {
606249
606801
  }
606250
606802
  chmodSync7(tmp, 384);
606251
606803
  renameSync17(tmp, this.file);
606252
- const dfd = openSync24(dirname81(this.file), "r");
606804
+ const dfd = openSync24(dirname82(this.file), "r");
606253
606805
  try {
606254
606806
  fsyncSync4(dfd);
606255
606807
  } finally {
@@ -606337,8 +606889,8 @@ function validateTenant(memory, scope) {
606337
606889
 
606338
606890
  // packages/memory/telegram-memory.ts
606339
606891
  import { randomInt, timingSafeEqual as timingSafeEqual8 } from "node:crypto";
606340
- import { chmodSync as chmodSync8, existsSync as existsSync124, readFileSync as readFileSync116, statSync as statSync38, unlinkSync as unlinkSync8, writeFileSync as writeFileSync70 } from "node:fs";
606341
- import { join as join183 } from "node:path";
606892
+ import { chmodSync as chmodSync8, existsSync as existsSync126, readFileSync as readFileSync117, statSync as statSync38, unlinkSync as unlinkSync8, writeFileSync as writeFileSync70 } from "node:fs";
606893
+ import { join as join185 } from "node:path";
606342
606894
  function parseMatrix(raw) {
606343
606895
  try {
606344
606896
  const m = JSON.parse(raw);
@@ -606406,20 +606958,20 @@ class TelegramMemory {
606406
606958
  this.keyProvider = opts.keyProvider ?? keychainKey;
606407
606959
  }
606408
606960
  get flagFile() {
606409
- return join183(this.opts.dir, "disabled");
606961
+ return join185(this.opts.dir, "disabled");
606410
606962
  }
606411
606963
  disabledByEnv() {
606412
606964
  const v = (this.env.TELEGRAM_MEMORY_DISABLED ?? "").trim().toLowerCase();
606413
606965
  return v === "1" || v === "true" || v === "yes";
606414
606966
  }
606415
606967
  isDisabled() {
606416
- return this.disabledByEnv() || existsSync124(this.flagFile);
606968
+ return this.disabledByEnv() || existsSync126(this.flagFile);
606417
606969
  }
606418
606970
  isOperator(fromId) {
606419
606971
  return typeof fromId === "number" && splitIds(this.env.TELEGRAM_OPERATOR_USER_IDS).includes(String(fromId));
606420
606972
  }
606421
606973
  matrix() {
606422
- const file = join183(this.opts.dir, "matrix.json");
606974
+ const file = join185(this.opts.dir, "matrix.json");
606423
606975
  let sig;
606424
606976
  try {
606425
606977
  const st = statSync38(file);
@@ -606431,7 +606983,7 @@ class TelegramMemory {
606431
606983
  }
606432
606984
  if (this.matrixCache?.sig === sig)
606433
606985
  return this.matrixCache.matrix;
606434
- const parsed = parseMatrix(readFileSync116(file, "utf8"));
606986
+ const parsed = parseMatrix(readFileSync117(file, "utf8"));
606435
606987
  if (parsed) {
606436
606988
  this.matrixCache = { sig, matrix: parsed };
606437
606989
  this.noteMatrix("ok");
@@ -606475,7 +607027,7 @@ class TelegramMemory {
606475
607027
  }
606476
607028
  ensureAudit() {
606477
607029
  if (!this.audit) {
606478
- this.audit = new AuditLog(join183(this.opts.dir, "audit.jsonl"), join183(this.opts.dir, "audit.salt"), this.clock, (n) => this.log(`audit: dropped ${n} byte(s) of a torn last line`));
607030
+ this.audit = new AuditLog(join185(this.opts.dir, "audit.jsonl"), join185(this.opts.dir, "audit.salt"), this.clock, (n) => this.log(`audit: dropped ${n} byte(s) of a torn last line`));
606479
607031
  }
606480
607032
  return this.audit;
606481
607033
  }
@@ -606602,7 +607154,7 @@ class TelegramMemory {
606602
607154
  const uid = String(ctx.fromId);
606603
607155
  const chat = String(ctx.chatId);
606604
607156
  const listed = splitIds(this.env.TELEGRAM_MEMORY_CHAT_IDS).includes(chat);
606605
- const hasState = existsSync124(this.opts.dir);
607157
+ const hasState = existsSync126(this.opts.dir);
606606
607158
  if (!listed && !hasState) {
606607
607159
  return "Memory is not enabled for this chat and nothing is stored, so there is nothing to change or erase.";
606608
607160
  }
@@ -606618,7 +607170,7 @@ class TelegramMemory {
606618
607170
  if (this.disabledByEnv()) {
606619
607171
  return "Memory is disabled by TELEGRAM_MEMORY_DISABLED in the bot environment. /memon cannot override it.";
606620
607172
  }
606621
- if (existsSync124(this.flagFile))
607173
+ if (existsSync126(this.flagFile))
606622
607174
  unlinkSync8(this.flagFile);
606623
607175
  this.auditEvent(uid, chat, "memon", "0", {}, "ok");
606624
607176
  return "Memory is on.";
@@ -606626,7 +607178,7 @@ class TelegramMemory {
606626
607178
  const now = this.clock();
606627
607179
  const given = arg.trim();
606628
607180
  if (!given) {
606629
- if (!existsSync124(join183(this.opts.dir, "memory.db.enc"))) {
607181
+ if (!existsSync126(join185(this.opts.dir, "memory.db.enc"))) {
606630
607182
  return "Nothing is stored, so there is nothing to erase.";
606631
607183
  }
606632
607184
  const code = String(randomInt(1e5, 1e6));
@@ -606715,53 +607267,53 @@ var init_formatters = () => {};
606715
607267
 
606716
607268
  // packages/telegram-bot/memory.ts
606717
607269
  import { homedir as homedir90 } from "node:os";
606718
- import { dirname as dirname82, join as join184 } from "node:path";
607270
+ import { dirname as dirname83, join as join186 } from "node:path";
606719
607271
  var DEFAULT_MEMORY_PATH;
606720
607272
  var init_memory3 = __esm(() => {
606721
- DEFAULT_MEMORY_PATH = join184(homedir90(), ".8gent", "bot-memory.json");
607273
+ DEFAULT_MEMORY_PATH = join186(homedir90(), ".8gent", "bot-memory.json");
606722
607274
  });
606723
607275
 
606724
607276
  // packages/telegram-bot/agent-mode.ts
606725
607277
  import { homedir as homedir91 } from "node:os";
606726
- import { join as join185 } from "node:path";
607278
+ import { join as join187 } from "node:path";
606727
607279
  var HOME3, LOOP_STATE, LEGACY_STATE, CONFIG_FILE2, RUN_PID_FILE, KNOWLEDGE_DIR;
606728
607280
  var init_agent_mode = __esm(() => {
606729
607281
  init_bun_flags();
606730
607282
  init_formatters();
606731
607283
  init_memory3();
606732
607284
  HOME3 = homedir91();
606733
- LOOP_STATE = join185(HOME3, "8gent-code/benchmarks/autoresearch/loop-state.json");
606734
- LEGACY_STATE = join185(HOME3, "iris-observatory/benchmarks/autoresearch/loop-state.json");
606735
- CONFIG_FILE2 = join185(HOME3, ".8gent/config.json");
606736
- RUN_PID_FILE = join185(HOME3, ".8gent/run.pid");
606737
- KNOWLEDGE_DIR = join185(HOME3, ".8gent/intelligence");
607285
+ LOOP_STATE = join187(HOME3, "8gent-code/benchmarks/autoresearch/loop-state.json");
607286
+ LEGACY_STATE = join187(HOME3, "iris-observatory/benchmarks/autoresearch/loop-state.json");
607287
+ CONFIG_FILE2 = join187(HOME3, ".8gent/config.json");
607288
+ RUN_PID_FILE = join187(HOME3, ".8gent/run.pid");
607289
+ KNOWLEDGE_DIR = join187(HOME3, ".8gent/intelligence");
606738
607290
  });
606739
607291
 
606740
607292
  // packages/telegram-bot/intelligence.ts
606741
607293
  import { homedir as homedir92 } from "node:os";
606742
- import { join as join186 } from "node:path";
607294
+ import { join as join188 } from "node:path";
606743
607295
  var HOME4, INTEL_DIR, REPOS_FILE, DIGEST_FILE;
606744
607296
  var init_intelligence = __esm(() => {
606745
607297
  HOME4 = homedir92();
606746
- INTEL_DIR = join186(HOME4, ".8gent/intelligence");
606747
- REPOS_FILE = join186(INTEL_DIR, "repos.json");
606748
- DIGEST_FILE = join186(INTEL_DIR, "latest-digest.json");
607298
+ INTEL_DIR = join188(HOME4, ".8gent/intelligence");
607299
+ REPOS_FILE = join188(INTEL_DIR, "repos.json");
607300
+ DIGEST_FILE = join188(INTEL_DIR, "latest-digest.json");
606749
607301
  });
606750
607302
 
606751
607303
  // packages/telegram-bot/commands.ts
606752
607304
  import { homedir as homedir93 } from "node:os";
606753
- import { join as join187 } from "node:path";
607305
+ import { join as join189 } from "node:path";
606754
607306
  var HOME5, LOOP_STATE2, LEGACY_STATE2, NIGHTLY_LOG, CONFIG_FILE3, RUN_PID_FILE2;
606755
607307
  var init_commands = __esm(() => {
606756
607308
  init_bun_flags();
606757
607309
  init_formatters();
606758
607310
  init_intelligence();
606759
607311
  HOME5 = homedir93();
606760
- LOOP_STATE2 = join187(HOME5, "8gent-code/benchmarks/autoresearch/loop-state.json");
606761
- LEGACY_STATE2 = join187(HOME5, "iris-observatory/benchmarks/autoresearch/loop-state.json");
606762
- NIGHTLY_LOG = join187(HOME5, ".8gent/nightly.log");
606763
- CONFIG_FILE3 = join187(HOME5, ".8gent/config.json");
606764
- RUN_PID_FILE2 = join187(HOME5, ".8gent/run.pid");
607312
+ LOOP_STATE2 = join189(HOME5, "8gent-code/benchmarks/autoresearch/loop-state.json");
607313
+ LEGACY_STATE2 = join189(HOME5, "iris-observatory/benchmarks/autoresearch/loop-state.json");
607314
+ NIGHTLY_LOG = join189(HOME5, ".8gent/nightly.log");
607315
+ CONFIG_FILE3 = join189(HOME5, ".8gent/config.json");
607316
+ RUN_PID_FILE2 = join189(HOME5, ".8gent/run.pid");
606765
607317
  });
606766
607318
 
606767
607319
  // packages/telegram-bot/live-dashboard.ts
@@ -607178,8 +607730,8 @@ function truncate2(text, max) {
607178
607730
  var MAX_MOBILE_LEN = 1800, MAX_CHUNK_LEN = 3800;
607179
607731
 
607180
607732
  // packages/telegram-bot/file-sender.ts
607181
- import { existsSync as existsSync125, statSync as statSync39 } from "node:fs";
607182
- import { basename as basename53 } from "node:path";
607733
+ import { existsSync as existsSync127, statSync as statSync39 } from "node:fs";
607734
+ import { basename as basename54 } from "node:path";
607183
607735
 
607184
607736
  class FileSender {
607185
607737
  token;
@@ -607262,7 +607814,7 @@ class FileSender {
607262
607814
  if (attachment.buffer)
607263
607815
  return attachment.buffer;
607264
607816
  if (attachment.path) {
607265
- if (!existsSync125(attachment.path))
607817
+ if (!existsSync127(attachment.path))
607266
607818
  return null;
607267
607819
  return await Bun.file(attachment.path).bytes().then((b) => Buffer.from(b));
607268
607820
  }
@@ -607274,7 +607826,7 @@ class FileSender {
607274
607826
  if (!stat.isFile())
607275
607827
  throw new Error(`file-sender: ${input} is not a file`);
607276
607828
  const bytes = await Bun.file(input).bytes();
607277
- return { buffer: Buffer.from(bytes), name: basename53(input) };
607829
+ return { buffer: Buffer.from(bytes), name: basename54(input) };
607278
607830
  }
607279
607831
  return { buffer: input, name: fallback };
607280
607832
  }
@@ -607291,8 +607843,8 @@ var init_file_sender = __esm(() => {
607291
607843
  });
607292
607844
 
607293
607845
  // packages/telegram-bot/session-store.ts
607294
- import { existsSync as existsSync126, mkdirSync as mkdirSync97, readFileSync as readFileSync117, writeFileSync as writeFileSync71 } from "node:fs";
607295
- import { dirname as dirname83 } from "node:path";
607846
+ import { existsSync as existsSync128, mkdirSync as mkdirSync97, readFileSync as readFileSync118, writeFileSync as writeFileSync71 } from "node:fs";
607847
+ import { dirname as dirname84 } from "node:path";
607296
607848
 
607297
607849
  class SessionStore2 {
607298
607850
  sessions = new Map;
@@ -607366,7 +607918,7 @@ class SessionStore2 {
607366
607918
  if (!this.persistPath)
607367
607919
  return;
607368
607920
  try {
607369
- mkdirSync97(dirname83(this.persistPath), { recursive: true });
607921
+ mkdirSync97(dirname84(this.persistPath), { recursive: true });
607370
607922
  const data = JSON.stringify({ version: 1, savedAt: Date.now(), sessions: Array.from(this.sessions.values()) }, null, 2);
607371
607923
  writeFileSync71(this.persistPath, data, "utf-8");
607372
607924
  } catch {}
@@ -607385,9 +607937,9 @@ class SessionStore2 {
607385
607937
  if (!this.persistPath)
607386
607938
  return;
607387
607939
  try {
607388
- if (!existsSync126(this.persistPath))
607940
+ if (!existsSync128(this.persistPath))
607389
607941
  return;
607390
- const raw = readFileSync117(this.persistPath, "utf-8");
607942
+ const raw = readFileSync118(this.persistPath, "utf-8");
607391
607943
  const parsed = JSON.parse(raw);
607392
607944
  if (!parsed?.sessions)
607393
607945
  return;
@@ -607915,7 +608467,7 @@ var init_telegram_bot = __esm(() => {
607915
608467
  });
607916
608468
 
607917
608469
  // packages/telegram-bot/boardroom.ts
607918
- import { spawn as spawn24 } from "node:child_process";
608470
+ import { spawn as spawn25 } from "node:child_process";
607919
608471
  function renderBoard(topic, rows, opts = {}) {
607920
608472
  const done = rows.filter((r) => r.status === "done").length;
607921
608473
  const lines = [];
@@ -608081,7 +608633,7 @@ function askVerdictViaClaude(cwd) {
608081
608633
  }
608082
608634
  function runClaude(args, cwd, signal) {
608083
608635
  return new Promise((resolve, reject) => {
608084
- const child = spawn24("claude", [...args, "--disallowedTools", ...OFFICER_DENIED_TOOLS], {
608636
+ const child = spawn25("claude", [...args, "--disallowedTools", ...OFFICER_DENIED_TOOLS], {
608085
608637
  cwd,
608086
608638
  stdio: ["ignore", "pipe", "pipe"]
608087
608639
  });
@@ -608385,16 +608937,16 @@ var init_flow_bot = __esm(() => {
608385
608937
  });
608386
608938
 
608387
608939
  // packages/telegram-bot/voice-mode.ts
608388
- import { spawn as spawn25 } from "node:child_process";
608940
+ import { spawn as spawn26 } from "node:child_process";
608389
608941
  import { createHash as createHash32 } from "node:crypto";
608390
- import { existsSync as existsSync127, mkdirSync as mkdirSync98, readFileSync as readFileSync118, writeFileSync as writeFileSync72 } from "node:fs";
608942
+ import { existsSync as existsSync129, mkdirSync as mkdirSync98, readFileSync as readFileSync119, writeFileSync as writeFileSync72 } from "node:fs";
608391
608943
  import { homedir as homedir94 } from "node:os";
608392
- import { dirname as dirname84, join as join188 } from "node:path";
608944
+ import { dirname as dirname85, join as join190 } from "node:path";
608393
608945
  function readVoiceState(path = VOICE_STATE_PATH) {
608394
- if (!existsSync127(path))
608946
+ if (!existsSync129(path))
608395
608947
  return { ...DEFAULT_STATE };
608396
608948
  try {
608397
- const parsed = JSON.parse(readFileSync118(path, "utf-8"));
608949
+ const parsed = JSON.parse(readFileSync119(path, "utf-8"));
608398
608950
  const notices = {};
608399
608951
  if (parsed?.groupNotices && typeof parsed.groupNotices === "object") {
608400
608952
  for (const [k, v] of Object.entries(parsed.groupNotices)) {
@@ -608418,7 +608970,7 @@ function writeVoiceState(enabled, path = VOICE_STATE_PATH) {
608418
608970
  groupNotices: readVoiceState(path).groupNotices ?? {}
608419
608971
  };
608420
608972
  try {
608421
- mkdirSync98(dirname84(path), { recursive: true });
608973
+ mkdirSync98(dirname85(path), { recursive: true });
608422
608974
  writeFileSync72(path, `${JSON.stringify(state, null, 2)}
608423
608975
  `, "utf-8");
608424
608976
  } catch (err) {
@@ -608437,7 +608989,7 @@ function recordGroupNotice(chatId, path = VOICE_STATE_PATH) {
608437
608989
  groupNotices: { ...prev.groupNotices ?? {}, [chatId]: groupNoticeHash() }
608438
608990
  };
608439
608991
  try {
608440
- mkdirSync98(dirname84(path), { recursive: true });
608992
+ mkdirSync98(dirname85(path), { recursive: true });
608441
608993
  writeFileSync72(path, `${JSON.stringify(state, null, 2)}
608442
608994
  `, "utf-8");
608443
608995
  } catch (err) {
@@ -608461,7 +609013,7 @@ function decideVoice(markdown, opts) {
608461
609013
  }
608462
609014
  async function sendVoiceNote(opts) {
608463
609015
  const bin = opts.bin ?? KITTENTTS_BIN;
608464
- if (!existsSync127(bin))
609016
+ if (!existsSync129(bin))
608465
609017
  return { sent: false, reason: "kittentts-telegram not installed" };
608466
609018
  const args = ["--voice", opts.voice];
608467
609019
  if (opts.explicitChat !== undefined) {
@@ -608473,7 +609025,7 @@ async function sendVoiceNote(opts) {
608473
609025
  if (opts.threadId !== undefined) {
608474
609026
  let supportsThread = false;
608475
609027
  try {
608476
- supportsThread = readFileSync118(bin, "utf-8").includes("--thread)");
609028
+ supportsThread = readFileSync119(bin, "utf-8").includes("--thread)");
608477
609029
  } catch {}
608478
609030
  if (!supportsThread)
608479
609031
  return { sent: false, reason: "TTS bridge cannot address a topic" };
@@ -608491,7 +609043,7 @@ async function sendVoiceNote(opts) {
608491
609043
  if (opts.caption)
608492
609044
  args.push("--caption", opts.caption);
608493
609045
  return new Promise((resolve) => {
608494
- const child = spawn25(bin, args, { stdio: ["pipe", "ignore", "pipe"] });
609046
+ const child = spawn26(bin, args, { stdio: ["pipe", "ignore", "pipe"] });
608495
609047
  let stderr = "";
608496
609048
  child.stderr?.on("data", (d) => {
608497
609049
  stderr += String(d);
@@ -608501,11 +609053,11 @@ async function sendVoiceNote(opts) {
608501
609053
  child.stdin?.end(opts.text);
608502
609054
  });
608503
609055
  }
608504
- function readConfiguredChatId(envPath = join188(homedir94(), ".claude", ".env")) {
608505
- if (!existsSync127(envPath))
609056
+ function readConfiguredChatId(envPath = join190(homedir94(), ".claude", ".env")) {
609057
+ if (!existsSync129(envPath))
608506
609058
  return null;
608507
609059
  try {
608508
- for (const line of readFileSync118(envPath, "utf-8").split(`
609060
+ for (const line of readFileSync119(envPath, "utf-8").split(`
608509
609061
  `)) {
608510
609062
  const m = line.match(/^\s*(?:export\s+)?TELEGRAM_CHAT_ID\s*=\s*["']?([^"'#\s]+)/);
608511
609063
  if (m)
@@ -608516,8 +609068,8 @@ function readConfiguredChatId(envPath = join188(homedir94(), ".claude", ".env"))
608516
609068
  }
608517
609069
  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;
608518
609070
  var init_voice_mode = __esm(() => {
608519
- VOICE_STATE_PATH = process.env.EIGHT_TG_VOICE_STATE || join188(homedir94(), ".8gent", "telegram-voice.json");
608520
- KITTENTTS_BIN = join188(homedir94(), ".claude", "bin", "kittentts-telegram");
609071
+ VOICE_STATE_PATH = process.env.EIGHT_TG_VOICE_STATE || join190(homedir94(), ".8gent", "telegram-voice.json");
609072
+ KITTENTTS_BIN = join190(homedir94(), ".claude", "bin", "kittentts-telegram");
608521
609073
  DEFAULT_STATE = { enabled: false, updatedAt: "", groupNotices: {} };
608522
609074
  });
608523
609075
 
@@ -608559,11 +609111,11 @@ var init_types8 = __esm(() => {
608559
609111
  });
608560
609112
 
608561
609113
  // packages/voice/model-manager.ts
608562
- import { existsSync as existsSync128, mkdirSync as mkdirSync99, realpathSync as realpathSync37, unlinkSync as unlinkSync9 } from "node:fs";
609114
+ import { existsSync as existsSync130, mkdirSync as mkdirSync99, realpathSync as realpathSync37, unlinkSync as unlinkSync9 } from "node:fs";
608563
609115
  import { homedir as homedir95 } from "node:os";
608564
- import { join as join189, sep as sep31 } from "node:path";
609116
+ import { join as join191, sep as sep31 } from "node:path";
608565
609117
  function resolveWhisperModel(opts = {}) {
608566
- const exists = opts.exists ?? existsSync128;
609118
+ const exists = opts.exists ?? existsSync130;
608567
609119
  const dirs = [
608568
609120
  resolveModelsPath(opts.modelsDir ?? "~/.8gent/models/whisper"),
608569
609121
  ...opts.extraDirs ?? []
@@ -608573,7 +609125,7 @@ function resolveWhisperModel(opts = {}) {
608573
609125
  for (const m of WHISPER_MODEL_RANK) {
608574
609126
  if (!english && m.filename.endsWith(".en.bin"))
608575
609127
  continue;
608576
- const path = join189(dir, m.filename);
609128
+ const path = join191(dir, m.filename);
608577
609129
  if (!exists(path))
608578
609130
  continue;
608579
609131
  if (!opts.exists && !isInside2(dir, path))
@@ -608602,7 +609154,7 @@ function missingWhisperModelMessage(modelsDir = "~/.8gent/models/whisper") {
608602
609154
  }
608603
609155
  function resolveModelsPath(configPath) {
608604
609156
  if (configPath.startsWith("~")) {
608605
- return join189(homedir95(), configPath.slice(1));
609157
+ return join191(homedir95(), configPath.slice(1));
608606
609158
  }
608607
609159
  return configPath;
608608
609160
  }
@@ -608620,7 +609172,7 @@ var init_model_manager = __esm(() => {
608620
609172
  });
608621
609173
 
608622
609174
  // packages/voice/spoken-draft.ts
608623
- function basename54(p) {
609175
+ function basename55(p) {
608624
609176
  const parts = p.replace(/[/\\]+$/, "").split(/[/\\]/);
608625
609177
  return parts[parts.length - 1] || p;
608626
609178
  }
@@ -608636,7 +609188,7 @@ There is a code block on screen.
608636
609188
  t = t.replace(/\b(?:https?|ftp):\/\/[^\s)>\]]+/gi, "a link");
608637
609189
  t = t.replace(/\bwww\.[^\s)>\]]+/gi, "a link");
608638
609190
  t = t.replace(/(?:~|\.{1,2}|[A-Za-z]:)?(?:[\\/][\w.@+-]+){2,}[\\/]?(?::\d+(?::\d+)?)?/g, (m) => {
608639
- const name = basename54(m.replace(/:\d+(?::\d+)?$/, ""));
609191
+ const name = basename55(m.replace(/:\d+(?::\d+)?$/, ""));
608640
609192
  return name ? `the file ${name}` : "a file";
608641
609193
  });
608642
609194
  t = t.replace(/`([^`\n]+)`/g, "$1");
@@ -608767,22 +609319,22 @@ var init_voice_ack = __esm(() => {
608767
609319
  });
608768
609320
 
608769
609321
  // packages/daemon/task-registry.ts
608770
- import { existsSync as existsSync129, mkdirSync as mkdirSync100, readFileSync as readFileSync119, writeFileSync as writeFileSync73 } from "node:fs";
608771
- import { join as join190 } from "node:path";
609322
+ import { existsSync as existsSync131, mkdirSync as mkdirSync100, readFileSync as readFileSync120, writeFileSync as writeFileSync73 } from "node:fs";
609323
+ import { join as join192 } from "node:path";
608772
609324
  function tasksPath() {
608773
- return join190(getDataDir(), "tasks.json");
609325
+ return join192(getDataDir(), "tasks.json");
608774
609326
  }
608775
609327
  function ensureDir8() {
608776
609328
  const dir = getDataDir();
608777
- if (!existsSync129(dir))
609329
+ if (!existsSync131(dir))
608778
609330
  mkdirSync100(dir, { recursive: true });
608779
609331
  }
608780
609332
  function load3() {
608781
609333
  if (loaded)
608782
609334
  return;
608783
609335
  try {
608784
- if (existsSync129(tasksPath())) {
608785
- tasks = JSON.parse(readFileSync119(tasksPath(), "utf-8"));
609336
+ if (existsSync131(tasksPath())) {
609337
+ tasks = JSON.parse(readFileSync120(tasksPath(), "utf-8"));
608786
609338
  }
608787
609339
  } catch {
608788
609340
  tasks = [];
@@ -608846,14 +609398,14 @@ var init_task_registry = __esm(() => {
608846
609398
  });
608847
609399
 
608848
609400
  // packages/daemon/cos-router.ts
608849
- import { execSync as execSync5 } from "node:child_process";
608850
- import { existsSync as existsSync130, readFileSync as readFileSync120, writeFileSync as writeFileSync74 } from "node:fs";
608851
- import { join as join191 } from "node:path";
609401
+ import { execSync as execSync6 } from "node:child_process";
609402
+ import { existsSync as existsSync132, readFileSync as readFileSync121, writeFileSync as writeFileSync74 } from "node:fs";
609403
+ import { join as join193 } from "node:path";
608852
609404
  function goalsPath() {
608853
- return join191(getDataDir(), "goals.json");
609405
+ return join193(getDataDir(), "goals.json");
608854
609406
  }
608855
609407
  function cosWorkspace() {
608856
- return join191(getDataDir(), "workspace");
609408
+ return join193(getDataDir(), "workspace");
608857
609409
  }
608858
609410
 
608859
609411
  class CoSRouter {
@@ -608928,12 +609480,12 @@ Error: ${payload.error}`);
608928
609480
  ID: \`${task.id}\`
608929
609481
  Repo: ${repo}
608930
609482
  Priority: ${priority}`);
608931
- const repoPath = join191(cosWorkspace(), repo);
609483
+ const repoPath = join193(cosWorkspace(), repo);
608932
609484
  let issueUrl = "";
608933
609485
  let issueNumber = 0;
608934
- if (existsSync130(repoPath)) {
609486
+ if (existsSync132(repoPath)) {
608935
609487
  try {
608936
- const result = execSync5(`cd "${repoPath}" && gh issue create --title "${description.replace(/"/g, "\\\"")}" --body "Delegated by CEO via Telegram.
609488
+ const result = execSync6(`cd "${repoPath}" && gh issue create --title "${description.replace(/"/g, "\\\"")}" --body "Delegated by CEO via Telegram.
608937
609489
 
608938
609490
  Task ID: ${task.id}
608939
609491
  Priority: ${priority}"`, { encoding: "utf-8", timeout: 15000 }).trim();
@@ -609127,8 +609679,8 @@ Total: ${goals.length} objectives`);
609127
609679
  }
609128
609680
  loadGoals() {
609129
609681
  try {
609130
- if (existsSync130(goalsPath())) {
609131
- return JSON.parse(readFileSync120(goalsPath(), "utf-8"));
609682
+ if (existsSync132(goalsPath())) {
609683
+ return JSON.parse(readFileSync121(goalsPath(), "utf-8"));
609132
609684
  }
609133
609685
  } catch {}
609134
609686
  return [];
@@ -609144,20 +609696,20 @@ var init_cos_router = __esm(() => {
609144
609696
  });
609145
609697
 
609146
609698
  // packages/daemon/telegram-bridge.ts
609147
- import { spawn as spawn26 } from "node:child_process";
609699
+ import { spawn as spawn27 } from "node:child_process";
609148
609700
  import { createHash as createHash33 } from "node:crypto";
609149
609701
  import {
609150
609702
  appendFileSync as appendFileSync28,
609151
609703
  chmodSync as chmodSync9,
609152
- existsSync as existsSync131,
609704
+ existsSync as existsSync133,
609153
609705
  mkdirSync as mkdirSync101,
609154
- readFileSync as readFileSync121,
609706
+ readFileSync as readFileSync122,
609155
609707
  statSync as statSync40,
609156
609708
  unlinkSync as unlinkSync10,
609157
609709
  writeFileSync as writeFileSync75
609158
609710
  } from "node:fs";
609159
609711
  import { tmpdir as tmpdir19 } from "node:os";
609160
- import { dirname as dirname85, join as join192 } from "node:path";
609712
+ import { dirname as dirname86, join as join194 } from "node:path";
609161
609713
  function observeUnauthorized(update) {
609162
609714
  try {
609163
609715
  const u = update;
@@ -609171,9 +609723,9 @@ function observeUnauthorized(update) {
609171
609723
  if (statSync40(OBSERVED_LOG).size > OBSERVED_MAX_BYTES)
609172
609724
  return;
609173
609725
  } catch {
609174
- mkdirSync101(dirname85(OBSERVED_LOG), { recursive: true, mode: 448 });
609726
+ mkdirSync101(dirname86(OBSERVED_LOG), { recursive: true, mode: 448 });
609175
609727
  }
609176
- if (!existsSync131(OBSERVED_LOG))
609728
+ if (!existsSync133(OBSERVED_LOG))
609177
609729
  writeFileSync75(OBSERVED_LOG, "", { mode: 384 });
609178
609730
  chmodSync9(OBSERVED_LOG, 384);
609179
609731
  appendFileSync28(OBSERVED_LOG, `${JSON.stringify({
@@ -609190,7 +609742,7 @@ function observeUnauthorized(update) {
609190
609742
  } catch {}
609191
609743
  }
609192
609744
  function sessionStorePath() {
609193
- return process.env.EIGHT_TG_SESSIONS || join192(getDataDir(), "telegram-sessions.json");
609745
+ return process.env.EIGHT_TG_SESSIONS || join194(getDataDir(), "telegram-sessions.json");
609194
609746
  }
609195
609747
  function bindChatThread(chatId, threadId) {
609196
609748
  chatThreads.clear();
@@ -609241,12 +609793,12 @@ async function tgSend(token, chatId, text, parseMode = "Markdown") {
609241
609793
  }
609242
609794
  function whisperModelDirs() {
609243
609795
  return {
609244
- modelsDir: join192(getDataDir(), "models", "whisper"),
609245
- extraDirs: [join192(resolveHome(), "models")]
609796
+ modelsDir: join194(getDataDir(), "models", "whisper"),
609797
+ extraDirs: [join194(resolveHome(), "models")]
609246
609798
  };
609247
609799
  }
609248
609800
  function cosPoolWorkspace() {
609249
- return join192(getDataDir(), "workspace");
609801
+ return join194(getDataDir(), "workspace");
609250
609802
  }
609251
609803
  function localWhisperModel() {
609252
609804
  return resolveWhisperModel(whisperModelDirs())?.path ?? null;
@@ -609285,7 +609837,7 @@ function runAsync(cmd, args, timeoutMs) {
609285
609837
  pid: child.pid
609286
609838
  });
609287
609839
  };
609288
- const child = spawn26(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
609840
+ const child = spawn27(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
609289
609841
  const timer = setTimeout(() => {
609290
609842
  child.kill("SIGKILL");
609291
609843
  finish(null);
@@ -609320,13 +609872,13 @@ async function transcribeVoice(token, fileId) {
609320
609872
  const audioUrl = `https://api.telegram.org/file/bot${token}/${fileData.result.file_path}`;
609321
609873
  const audioRes = await fetch(audioUrl);
609322
609874
  const audioBuffer = await audioRes.arrayBuffer();
609323
- const stem = join192(tmpdir19(), `tg-voice-${Date.now()}-${Math.floor(performance.now())}`);
609875
+ const stem = join194(tmpdir19(), `tg-voice-${Date.now()}-${Math.floor(performance.now())}`);
609324
609876
  const ogg = `${stem}.ogg`;
609325
609877
  const wav = `${stem}.wav`;
609326
609878
  try {
609327
609879
  writeFileSync75(ogg, Buffer.from(audioBuffer));
609328
609880
  const conv = await runAsync("ffmpeg", ["-y", "-i", ogg, "-ar", "16000", "-ac", "1", wav], 30000);
609329
- if (conv.status !== 0 || !existsSync131(wav)) {
609881
+ if (conv.status !== 0 || !existsSync133(wav)) {
609330
609882
  console.error(subprocessFailure("ffmpeg", conv.status, conv.stderr));
609331
609883
  return "[voice message received - could not decode the audio]";
609332
609884
  }
@@ -609343,7 +609895,7 @@ async function transcribeVoice(token, fileId) {
609343
609895
  } finally {
609344
609896
  for (const f of [ogg, wav]) {
609345
609897
  try {
609346
- if (existsSync131(f))
609898
+ if (existsSync133(f))
609347
609899
  unlinkSync10(f);
609348
609900
  } catch {}
609349
609901
  }
@@ -609513,7 +610065,7 @@ function localSpokenModel(env, fetchImpl = fetch, json = false) {
609513
610065
  }
609514
610066
  function assertNotAiJamesToken(token, env = process.env, readRef = (p) => {
609515
610067
  try {
609516
- return readFileSync121(p, "utf8");
610068
+ return readFileSync122(p, "utf8");
609517
610069
  } catch {
609518
610070
  return null;
609519
610071
  }
@@ -609593,7 +610145,7 @@ class TelegramDaemonBridge {
609593
610145
  get memory() {
609594
610146
  if (!this.memoryStore) {
609595
610147
  this.memoryStore = new TelegramMemory({
609596
- dir: join192(getDataDir(), "memory"),
610148
+ dir: join194(getDataDir(), "memory"),
609597
610149
  env: this.config.env ?? process.env,
609598
610150
  scrubSessions: (uid) => this.scrubSessionTurns(uid)
609599
610151
  });
@@ -609972,8 +610524,8 @@ What do we work on next?`);
609972
610524
  observeVoiceDrop(message) {
609973
610525
  try {
609974
610526
  const path = this.config.observeLogPath ?? OBSERVED_LOG;
609975
- mkdirSync101(dirname85(path), { recursive: true, mode: 448 });
609976
- if (!existsSync131(path))
610527
+ mkdirSync101(dirname86(path), { recursive: true, mode: 448 });
610528
+ if (!existsSync133(path))
609977
610529
  writeFileSync75(path, "", { mode: 384 });
609978
610530
  chmodSync9(path, 384);
609979
610531
  appendFileSync28(path, `${JSON.stringify({
@@ -610984,7 +611536,7 @@ var init_telegram_bridge = __esm(() => {
610984
611536
  init_input_gate();
610985
611537
  init_notifications();
610986
611538
  init_voice_ack();
610987
- OBSERVED_LOG = join192(resolveHome(), ".8gent", "telegram-observed.jsonl");
611539
+ OBSERVED_LOG = join194(resolveHome(), ".8gent", "telegram-observed.jsonl");
610988
611540
  OBSERVED_MAX_BYTES = 5 * 1024 * 1024;
610989
611541
  MULTI_STEP_ENABLED = process.env.EIGHT_TG_LEGACY !== "1";
610990
611542
  chatThreads = new Map;
@@ -611027,7 +611579,7 @@ var init_telegram_bridge = __esm(() => {
611027
611579
  });
611028
611580
 
611029
611581
  // packages/daemon/index.ts
611030
- import { appendFileSync as appendFileSync29, existsSync as existsSync132, mkdirSync as mkdirSync102 } from "node:fs";
611582
+ import { appendFileSync as appendFileSync29, existsSync as existsSync134, mkdirSync as mkdirSync102 } from "node:fs";
611031
611583
  async function loadConfig2() {
611032
611584
  const defaults = {
611033
611585
  port: PORT,
@@ -611052,7 +611604,7 @@ async function loadConfig2() {
611052
611604
  }
611053
611605
  }
611054
611606
  function setupLogging() {
611055
- if (!existsSync132(DATA_DIR5)) {
611607
+ if (!existsSync134(DATA_DIR5)) {
611056
611608
  mkdirSync102(DATA_DIR5, { recursive: true });
611057
611609
  }
611058
611610
  const events = [
@@ -611356,7 +611908,7 @@ var init_daemon = __esm(() => {
611356
611908
  });
611357
611909
 
611358
611910
  // packages/daemon/service.ts
611359
- import { existsSync as existsSync133, mkdirSync as mkdirSync103, rmSync as rmSync19, writeFileSync as writeFileSync76 } from "node:fs";
611911
+ import { existsSync as existsSync135, mkdirSync as mkdirSync103, rmSync as rmSync19, writeFileSync as writeFileSync76 } from "node:fs";
611360
611912
  import * as os65 from "node:os";
611361
611913
  import * as path139 from "node:path";
611362
611914
  function paths(ctx) {
@@ -611515,7 +612067,7 @@ async function serviceStatus(ctx) {
611515
612067
  const query = backend.statusQuery(ctx);
611516
612068
  const res = await exec4(query.kind === "powershell" ? powershellArgv(query.script) : query.argv);
611517
612069
  const definition = backend.definitionPath(ctx);
611518
- return backend.parseStatus(res, definition !== null && existsSync133(definition));
612070
+ return backend.parseStatus(res, definition !== null && existsSync135(definition));
611519
612071
  }
611520
612072
  async function runOperation(op, ctx, log = console.log) {
611521
612073
  if (op !== "uninstall") {
@@ -612478,11 +613030,11 @@ var init_install = __esm(() => {
612478
613030
  });
612479
613031
 
612480
613032
  // packages/eight/self-update.ts
612481
- import { spawn as spawn27 } from "node:child_process";
613033
+ import { spawn as spawn28 } from "node:child_process";
612482
613034
  import { createHash as createHash36, createPublicKey as createPublicKey2, verify as cryptoVerify, randomBytes as randomBytes19 } from "node:crypto";
612483
- import { chmodSync as chmodSync10, existsSync as existsSync137, mkdtempSync as mkdtempSync12, renameSync as renameSync19, rmSync as rmSync21, writeFileSync as writeFileSync81 } from "node:fs";
613035
+ import { chmodSync as chmodSync10, existsSync as existsSync139, mkdtempSync as mkdtempSync12, renameSync as renameSync19, rmSync as rmSync21, writeFileSync as writeFileSync81 } from "node:fs";
612484
613036
  import { tmpdir as tmpdir20 } from "node:os";
612485
- import { join as join196, resolve as resolve76 } from "node:path";
613037
+ import { join as join198, resolve as resolve78 } from "node:path";
612486
613038
  import { fileURLToPath as fileURLToPath7 } from "node:url";
612487
613039
  function parseVersion(v) {
612488
613040
  const m = /^v?(\d+)\.(\d+)\.(\d+)$/.exec(v.trim());
@@ -612514,7 +613066,7 @@ function detectChannel(p) {
612514
613066
  return "binary";
612515
613067
  if (/[\\/]node_modules[\\/]/.test(p.modulePath))
612516
613068
  return "npm";
612517
- const hasGit = p.isGitCheckout ?? ((dir) => existsSync137(`${dir}/.git`));
613069
+ const hasGit = p.isGitCheckout ?? ((dir) => existsSync139(`${dir}/.git`));
612518
613070
  const parts = p.modulePath.replace(/^file:\/\//, "").split(/[\\/]/);
612519
613071
  for (let i = parts.length - 1;i > 0; i--) {
612520
613072
  if (hasGit(parts.slice(0, i).join("/") || "/"))
@@ -612755,7 +613307,7 @@ function npmHint(spec, prefix, ignoreScripts = false) {
612755
613307
  }
612756
613308
  function defaultRun2(cmd, args, opts) {
612757
613309
  return new Promise((resolve) => {
612758
- const p = spawn27(cmd, args, { stdio: "inherit", shell: opts.shell });
613310
+ const p = spawn28(cmd, args, { stdio: "inherit", shell: opts.shell });
612759
613311
  p.on("exit", (code) => resolve(code ?? 1));
612760
613312
  p.on("error", () => resolve(127));
612761
613313
  });
@@ -612774,7 +613326,7 @@ function probeVersionWithTimeout(file, timeoutMs = PROBE_TIMEOUT_MS3) {
612774
613326
  };
612775
613327
  let p;
612776
613328
  try {
612777
- p = spawn27(file, ["--version"], { stdio: ["ignore", "pipe", "ignore"] });
613329
+ p = spawn28(file, ["--version"], { stdio: ["ignore", "pipe", "ignore"] });
612778
613330
  } catch {
612779
613331
  finish("");
612780
613332
  return;
@@ -612820,13 +613372,13 @@ function swapInto(staged, target, platform) {
612820
613372
  } catch {
612821
613373
  old = `${target}.old-${randomBytes19(4).toString("hex")}`;
612822
613374
  }
612823
- const hadTarget = existsSync137(target);
613375
+ const hadTarget = existsSync139(target);
612824
613376
  if (hadTarget)
612825
613377
  renameSync19(target, old);
612826
613378
  try {
612827
613379
  renameSync19(staged, target);
612828
613380
  } catch (err) {
612829
- if (hadTarget && !existsSync137(target))
613381
+ if (hadTarget && !existsSync139(target))
612830
613382
  renameSync19(old, target);
612831
613383
  throw err;
612832
613384
  }
@@ -612864,9 +613416,9 @@ async function updateNpmFromRelease(o, rel, platform) {
612864
613416
  if (actual !== expected)
612865
613417
  return `checksum mismatch for ${name} (expected ${expected}, got ${actual}); nothing changed`;
612866
613418
  o.log(`SHA256 matches SHA256SUMS: ${actual}`);
612867
- const dir = mkdtempSync12(join196(resolve76(o.tmpDir ?? tmpdir20()), "8gent-update-"));
613419
+ const dir = mkdtempSync12(join198(resolve78(o.tmpDir ?? tmpdir20()), "8gent-update-"));
612868
613420
  try {
612869
- const file = join196(dir, name);
613421
+ const file = join198(dir, name);
612870
613422
  writeFileSync81(file, bytes, { flag: "wx", mode: 384 });
612871
613423
  o.log(`Installing with npm, package scripts off: npm install -g ${file} --ignore-scripts`);
612872
613424
  const code = await runNpmInstall(o, rel.version, platform, file);
@@ -613024,7 +613576,7 @@ var init_changelog_view = __esm(() => {
613024
613576
 
613025
613577
  // packages/eight/source-update.ts
613026
613578
  import { execFile as execFile6 } from "node:child_process";
613027
- import { existsSync as existsSync138, realpathSync as realpathSync39, statSync as statSync42 } from "node:fs";
613579
+ import { existsSync as existsSync140, realpathSync as realpathSync39, statSync as statSync42 } from "node:fs";
613028
613580
  import { homedir as homedir97 } from "node:os";
613029
613581
  import * as nodePath from "node:path";
613030
613582
  function scrubbedEnv2(base) {
@@ -613123,7 +613675,7 @@ function modulePathToFs(modulePath) {
613123
613675
  }
613124
613676
  return s;
613125
613677
  }
613126
- function findCheckoutRoot(modulePath, platform, hasGit = (d) => existsSync138(lib(platform).join(d, ".git"))) {
613678
+ function findCheckoutRoot(modulePath, platform, hasGit = (d) => existsSync140(lib(platform).join(d, ".git"))) {
613127
613679
  const p = lib(platform);
613128
613680
  const fsPath = modulePathToFs(modulePath);
613129
613681
  let dir = p.dirname(platform === "win32" ? fsPath.replace(/\//g, "\\") : fsPath);
@@ -613139,7 +613691,7 @@ function findCheckoutRoot(modulePath, platform, hasGit = (d) => existsSync138(li
613139
613691
  }
613140
613692
  function findBrowserCheckout(o) {
613141
613693
  const p = lib(o.platform);
613142
- const hasGit = o.hasGit ?? ((d) => existsSync138(p.join(d, ".git")));
613694
+ const hasGit = o.hasGit ?? ((d) => existsSync140(p.join(d, ".git")));
613143
613695
  const looked = [];
613144
613696
  let note;
613145
613697
  const cands = [];
@@ -613442,7 +613994,7 @@ async function runSourceUpdate(deps, opts, report) {
613442
613994
  git,
613443
613995
  bun: bun ?? "bun",
613444
613996
  platform,
613445
- fileExists: deps.fileExists ?? ((f) => existsSync138(f)),
613997
+ fileExists: deps.fileExists ?? ((f) => existsSync140(f)),
613446
613998
  now: deps.now ?? (() => new Date),
613447
613999
  baseEnv: env,
613448
614000
  forgeHost: env.EIGHT_FORGE_HOST,
@@ -613929,122 +614481,6 @@ var init_read_hidden = __esm(() => {
613929
614481
  MAX_PIPED_BYTES = 64 * 1024;
613930
614482
  });
613931
614483
 
613932
- // apps/tui/src/lib/external-agent-runner.ts
613933
- import { execSync as execSync6, spawn as spawn28 } from "node:child_process";
613934
- function getPreset(id) {
613935
- return EXTERNAL_AGENT_PRESETS[id.toLowerCase()] ?? null;
613936
- }
613937
- function isInstalled(preset) {
613938
- try {
613939
- execSync6(`command -v "${preset.command}"`, {
613940
- stdio: "ignore",
613941
- timeout: 1500
613942
- });
613943
- return true;
613944
- } catch {
613945
- return false;
613946
- }
613947
- }
613948
- var stripAnsi = (s) => s.replace(/\[[0-9;?]*[a-zA-Z]/g, "").replace(/\][^]*/g, ""), EXTERNAL_AGENT_PRESETS;
613949
- var init_external_agent_runner = __esm(() => {
613950
- init_shell();
613951
- EXTERNAL_AGENT_PRESETS = {
613952
- claude: {
613953
- id: "claude",
613954
- label: "Sparring",
613955
- command: "claude",
613956
- promptMode: "flag",
613957
- flagName: "-p",
613958
- args: [],
613959
- timeoutMs: 120000,
613960
- parseStdout: stripAnsi,
613961
- homepage: "https://docs.claude.com/en/docs/claude-code",
613962
- preferWindow: true,
613963
- install: {
613964
- command: "npm install -g --prefix=$HOME/.npm-global @anthropic-ai/claude-code",
613965
- 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.'
613966
- }
613967
- },
613968
- codex: {
613969
- id: "codex",
613970
- label: "OpenAI Codex",
613971
- command: "codex",
613972
- promptMode: "arg",
613973
- args: ["exec"],
613974
- timeoutMs: 120000,
613975
- parseStdout: stripAnsi,
613976
- homepage: "https://github.com/openai/codex",
613977
- preferWindow: true,
613978
- install: {
613979
- command: "npm install -g --prefix=$HOME/.npm-global @openai/codex",
613980
- notes: "Binary at ~/.npm-global/bin/codex. Add `~/.npm-global/bin` to PATH if needed. Requires `export OPENAI_API_KEY=sk-...` before /spawn."
613981
- }
613982
- },
613983
- hermes: {
613984
- id: "hermes",
613985
- label: "Hermes Agent",
613986
- command: "hermes",
613987
- preferWindow: true,
613988
- promptMode: "flag",
613989
- flagName: "-z",
613990
- args: [],
613991
- timeoutMs: 120000,
613992
- parseStdout: stripAnsi,
613993
- homepage: "https://github.com/NousResearch/hermes-agent",
613994
- install: {
613995
- command: "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash -s -- --skip-setup --no-venv",
613996
- notes: "Hermes needs Python ≥ 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)."
613997
- }
613998
- },
613999
- openclaw: {
614000
- id: "openclaw",
614001
- label: "OpenClaw",
614002
- command: "openclaw",
614003
- preferWindow: true,
614004
- promptMode: "arg",
614005
- args: ["run", "--headless"],
614006
- timeoutMs: 120000,
614007
- parseStdout: stripAnsi,
614008
- homepage: "https://github.com/openclaw/openclaw",
614009
- install: {
614010
- command: "npm install -g --prefix=$HOME/.npm-global openclaw@latest",
614011
- 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.)"
614012
- },
614013
- requiresNodeVersion: "22.14.0"
614014
- },
614015
- pi: {
614016
- preferWindow: true,
614017
- id: "pi",
614018
- label: "Pi (pi-mono)",
614019
- command: "pi",
614020
- promptMode: "flag",
614021
- flagName: "-p",
614022
- args: [],
614023
- timeoutMs: 120000,
614024
- parseStdout: stripAnsi,
614025
- homepage: "https://pi.dev",
614026
- install: {
614027
- command: "npm install -g --prefix=$HOME/.npm-global @mariozechner/pi-coding-agent",
614028
- 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)."
614029
- }
614030
- },
614031
- "8gent": {
614032
- id: "8gent",
614033
- label: "8gent (nested)",
614034
- command: "8gent",
614035
- promptMode: "arg",
614036
- args: ["run"],
614037
- timeoutMs: 180000,
614038
- parseStdout: stripAnsi,
614039
- homepage: "https://8gent.dev",
614040
- install: {
614041
- command: "npm install -g --prefix=$HOME/.npm-global @8gi-foundation/8gent-code --force",
614042
- 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."
614043
- }
614044
- }
614045
- };
614046
- });
614047
-
614048
614484
  // packages/install-runner/install-runner.ts
614049
614485
  function planInstallRun(args) {
614050
614486
  const { preset } = args;
@@ -615418,15 +615854,15 @@ var init_companion = __esm(() => {
615418
615854
  });
615419
615855
 
615420
615856
  // packages/eight/update-resume.ts
615421
- import { mkdirSync as mkdirSync107, readFileSync as readFileSync126, rmSync as rmSync22, writeFileSync as writeFileSync82 } from "node:fs";
615422
- import { join as join199 } from "node:path";
615857
+ import { mkdirSync as mkdirSync107, readFileSync as readFileSync127, rmSync as rmSync22, writeFileSync as writeFileSync82 } from "node:fs";
615858
+ import { join as join201 } from "node:path";
615423
615859
  function dataDir4(env = process.env) {
615424
- return join199(resolveHome(env), ".8gent");
615860
+ return join201(resolveHome(env), ".8gent");
615425
615861
  }
615426
615862
  function consumeResumeRequest(env = process.env) {
615427
615863
  const f = file(env);
615428
615864
  try {
615429
- const raw = JSON.parse(readFileSync126(f, "utf8"));
615865
+ const raw = JSON.parse(readFileSync127(f, "utf8"));
615430
615866
  rmSync22(f, { force: true });
615431
615867
  const id = typeof raw.sessionId === "string" && /^[A-Za-z0-9_.-]{1,128}$/.test(raw.sessionId) ? raw.sessionId : undefined;
615432
615868
  return {
@@ -615449,7 +615885,7 @@ function relaunchCommand(o) {
615449
615885
  env: { ...o.env ?? process.env, [UPDATE_NOTE_ENV]: o.req.note }
615450
615886
  };
615451
615887
  }
615452
- var UPDATE_NOTE_ENV = "EIGHT_UPDATE_NOTE", file = (env) => join199(dataDir4(env), "update-resume.json");
615888
+ var UPDATE_NOTE_ENV = "EIGHT_UPDATE_NOTE", file = (env) => join201(dataDir4(env), "update-resume.json");
615453
615889
  var init_update_resume = __esm(() => {
615454
615890
  init_home();
615455
615891
  });
@@ -616866,7 +617302,7 @@ var init_routines = __esm(() => {
616866
617302
  });
616867
617303
 
616868
617304
  // packages/ai/text-tool-demo-tools.ts
616869
- import { readdirSync as readdirSync31, readFileSync as readFileSync132, statSync as statSync43 } from "node:fs";
617305
+ import { readdirSync as readdirSync31, readFileSync as readFileSync133, statSync as statSync43 } from "node:fs";
616870
617306
  function str5(args, key) {
616871
617307
  const v = args[key];
616872
617308
  return typeof v === "string" ? v : "";
@@ -616897,7 +617333,7 @@ var init_text_tool_demo_tools = __esm(() => {
616897
617333
  if (info.isDirectory()) {
616898
617334
  return `Error: "${path}" is a directory, not a file. Use list_files.`;
616899
617335
  }
616900
- const text = readFileSync132(path, "utf-8");
617336
+ const text = readFileSync133(path, "utf-8");
616901
617337
  if (text.length > MAX_FILE_BYTES) {
616902
617338
  return `${text.slice(0, MAX_FILE_BYTES)}
616903
617339
  [...truncated, ${text.length} bytes total]`;
@@ -616961,7 +617397,7 @@ var init_text_tool_demo_tools = __esm(() => {
616961
617397
  if (info.isDirectory()) {
616962
617398
  return `Error: grep only searches a single file; "${path}" is a directory.`;
616963
617399
  }
616964
- const text = readFileSync132(path, "utf-8");
617400
+ const text = readFileSync133(path, "utf-8");
616965
617401
  const matches = [];
616966
617402
  const lines = text.split(`
616967
617403
  `);
@@ -617812,7 +618248,7 @@ function nodeExecPath(execPath = process.execPath, env = process.env, exists = e
617812
618248
 
617813
618249
  // bin/8gent.ts
617814
618250
  refuseIfNested();
617815
- var VERSION5 = "0.20.15";
618251
+ var VERSION5 = "0.20.17";
617816
618252
  var RELAUNCH_EXIT_CODE = 75;
617817
618253
  var MODULE_DIR = path158.dirname(fileURLToPath8(import.meta.url));
617818
618254
  var EXEC_DIR = path158.dirname(process.execPath);