agentix-cli 0.127.0 → 0.128.0
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/{App-FF66N2KH.js → App-BOLQUKCN.js} +2 -2
- package/dist/{ChatApp-HMHQZVVD.js → ChatApp-72HXQV24.js} +2 -2
- package/dist/absorb-eval-O3HA6XA5.js +2 -0
- package/dist/{agent-UAWDO3I2.js → agent-S2DXXALS.js} +2 -2
- package/dist/{board-dashboard-Y2OECKDG.js → board-dashboard-ZKXXK5CG.js} +4 -4
- package/dist/{chunk-COWAAE54.js → chunk-2SV4RKRW.js} +2 -2
- package/dist/{chunk-YV22EOGL.js → chunk-4V7SWL2S.js} +2 -2
- package/dist/chunk-5DAEJF5S.js +36 -0
- package/dist/chunk-5DAEJF5S.js.map +1 -0
- package/dist/{chunk-VBJTGTF5.js → chunk-6GGGXCOY.js} +2 -2
- package/dist/{chunk-4WZGZ2Z6.js → chunk-6KIUVVKX.js} +2 -2
- package/dist/{chunk-NUSROFTJ.js → chunk-C5MTLW7O.js} +2 -2
- package/dist/{chunk-73WQ42PO.js → chunk-D2WX3BET.js} +2 -2
- package/dist/chunk-DN3RLR5Z.js +17 -0
- package/dist/chunk-DN3RLR5Z.js.map +1 -0
- package/dist/{chunk-EJT3F6QM.js → chunk-DQ2LNQ2D.js} +2 -2
- package/dist/{chunk-HYRBBH6T.js → chunk-EJT4MA3J.js} +9 -9
- package/dist/chunk-EJT4MA3J.js.map +1 -0
- package/dist/chunk-FSW4FUMW.js +55 -0
- package/dist/chunk-FSW4FUMW.js.map +1 -0
- package/dist/chunk-FXBMFGOV.js +6 -0
- package/dist/chunk-FXBMFGOV.js.map +1 -0
- package/dist/{chunk-PH43FUU7.js → chunk-HKW56YZK.js} +2 -2
- package/dist/{chunk-LTH3AYXC.js → chunk-LDS4SZBU.js} +2 -2
- package/dist/chunk-MRYA4J5F.js +54 -0
- package/dist/chunk-MRYA4J5F.js.map +1 -0
- package/dist/{chunk-HNBW5Q47.js → chunk-O2BS6N3T.js} +2 -2
- package/dist/{chunk-EHLTZ6IB.js → chunk-P4XGM7ZM.js} +2 -2
- package/dist/{chunk-QWQOI4G4.js → chunk-QACEFESP.js} +6 -6
- package/dist/{chunk-CKYPQMUD.js → chunk-QFZU5CEO.js} +2 -2
- package/dist/{chunk-XX5QKBX4.js → chunk-QQFURUMS.js} +2 -2
- package/dist/{chunk-I4DGMFQG.js → chunk-TG6CT54D.js} +2 -2
- package/dist/{chunk-O6FP3LPC.js → chunk-TPNTFCSQ.js} +2 -2
- package/dist/{chunk-56KNKUFF.js → chunk-VD7IO653.js} +3 -3
- package/dist/{chunk-56KNKUFF.js.map → chunk-VD7IO653.js.map} +1 -1
- package/dist/{chunk-3KYZOC7N.js → chunk-YWKLUQDC.js} +2 -2
- package/dist/chunk-Z3W7D5RR.js +4 -0
- package/dist/chunk-Z3W7D5RR.js.map +1 -0
- package/dist/{chunk-XYT6XY7G.js → chunk-ZLC4TSXF.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/{client-2VVRJ3UF.js → client-VBV7Q43P.js} +2 -2
- package/dist/config-52C3DJD2.js +2 -0
- package/dist/{config-mutate-47WZDZBO.js → config-mutate-DKQESY6F.js} +2 -2
- package/dist/config-mutator-BF4D4QGN.js +2 -0
- package/dist/contributions-5OEZWYXI.js +57 -0
- package/dist/contributions-5OEZWYXI.js.map +1 -0
- package/dist/{doctor-Q3QNZVLC.js → doctor-VLRC4HW2.js} +2 -2
- package/dist/{follow-up-tool-GKZVG4L2.js → follow-up-tool-235LDEMP.js} +2 -2
- package/dist/{hub-DNPINTIF.js → hub-5QK7KYTZ.js} +2 -2
- package/dist/index.d.ts +224 -0
- package/dist/index.js +1 -1
- package/dist/{program-4QWUOJE3.js → program-MVD57PKP.js} +226 -222
- package/dist/program-MVD57PKP.js.map +1 -0
- package/dist/{promote-PETKX7KR.js → promote-UPPQ4BQE.js} +2 -2
- package/dist/query-XQS5JN6E.js +2 -0
- package/dist/{registry-2XDO53AJ.js → registry-MOMTLJ6R.js} +2 -2
- package/dist/{request-planner-A3WJNPXO.js → request-planner-QGZJEAKY.js} +2 -2
- package/dist/{review-candidates-A6ID2RDX.js → review-candidates-PAKF2JQF.js} +2 -2
- package/dist/{rotation-memo-6UW6DTBQ.js → rotation-memo-7VLREGS6.js} +2 -2
- package/dist/{routing-NPP3MEUW.js → routing-JG3EV4O4.js} +2 -2
- package/dist/schedule-tool-O7ZZ2A7X.js +2 -0
- package/dist/{scheduler-T6VLBM3U.js → scheduler-LMPBAA34.js} +2 -2
- package/dist/score-KDNIUTNV.js +3 -0
- package/dist/score-KDNIUTNV.js.map +1 -0
- package/dist/{seat-D3DBYTSC.js → seat-JN3IVZ3G.js} +2 -2
- package/dist/{select-RFY64RY7.js → select-ZMMRFMNO.js} +2 -2
- package/dist/{set-enabled-AU66DR5C.js → set-enabled-7Y3TW6Z4.js} +2 -2
- package/dist/{tool-F3YA2ZZQ.js → tool-OCYXCDOK.js} +2 -2
- package/dist/{tool-PCHIVR27.js → tool-S7QI6HRA.js} +2 -2
- package/dist/wiki-OCLFFZG6.js +2 -0
- package/package.json +1 -1
- package/dist/absorb-eval-ERKVVTGG.js +0 -2
- package/dist/chunk-HYRBBH6T.js.map +0 -1
- package/dist/chunk-PLIT25TH.js +0 -51
- package/dist/chunk-PLIT25TH.js.map +0 -1
- package/dist/chunk-TJ4P4WW2.js +0 -4
- package/dist/chunk-TJ4P4WW2.js.map +0 -1
- package/dist/chunk-UJXS4MS3.js +0 -49
- package/dist/chunk-UJXS4MS3.js.map +0 -1
- package/dist/chunk-Y27RUOD2.js +0 -54
- package/dist/chunk-Y27RUOD2.js.map +0 -1
- package/dist/config-YSKHOV44.js +0 -2
- package/dist/config-mutator-7DIEQUB5.js +0 -2
- package/dist/program-4QWUOJE3.js.map +0 -1
- package/dist/query-D44BUTH3.js +0 -2
- package/dist/schedule-tool-ZECUQMQK.js +0 -2
- package/dist/wiki-NI3ZPUZS.js +0 -2
- /package/dist/{App-FF66N2KH.js.map → App-BOLQUKCN.js.map} +0 -0
- /package/dist/{ChatApp-HMHQZVVD.js.map → ChatApp-72HXQV24.js.map} +0 -0
- /package/dist/{absorb-eval-ERKVVTGG.js.map → absorb-eval-O3HA6XA5.js.map} +0 -0
- /package/dist/{agent-UAWDO3I2.js.map → agent-S2DXXALS.js.map} +0 -0
- /package/dist/{board-dashboard-Y2OECKDG.js.map → board-dashboard-ZKXXK5CG.js.map} +0 -0
- /package/dist/{chunk-COWAAE54.js.map → chunk-2SV4RKRW.js.map} +0 -0
- /package/dist/{chunk-YV22EOGL.js.map → chunk-4V7SWL2S.js.map} +0 -0
- /package/dist/{chunk-VBJTGTF5.js.map → chunk-6GGGXCOY.js.map} +0 -0
- /package/dist/{chunk-4WZGZ2Z6.js.map → chunk-6KIUVVKX.js.map} +0 -0
- /package/dist/{chunk-NUSROFTJ.js.map → chunk-C5MTLW7O.js.map} +0 -0
- /package/dist/{chunk-73WQ42PO.js.map → chunk-D2WX3BET.js.map} +0 -0
- /package/dist/{chunk-EJT3F6QM.js.map → chunk-DQ2LNQ2D.js.map} +0 -0
- /package/dist/{chunk-PH43FUU7.js.map → chunk-HKW56YZK.js.map} +0 -0
- /package/dist/{chunk-LTH3AYXC.js.map → chunk-LDS4SZBU.js.map} +0 -0
- /package/dist/{chunk-HNBW5Q47.js.map → chunk-O2BS6N3T.js.map} +0 -0
- /package/dist/{chunk-EHLTZ6IB.js.map → chunk-P4XGM7ZM.js.map} +0 -0
- /package/dist/{chunk-QWQOI4G4.js.map → chunk-QACEFESP.js.map} +0 -0
- /package/dist/{chunk-CKYPQMUD.js.map → chunk-QFZU5CEO.js.map} +0 -0
- /package/dist/{chunk-XX5QKBX4.js.map → chunk-QQFURUMS.js.map} +0 -0
- /package/dist/{chunk-I4DGMFQG.js.map → chunk-TG6CT54D.js.map} +0 -0
- /package/dist/{chunk-O6FP3LPC.js.map → chunk-TPNTFCSQ.js.map} +0 -0
- /package/dist/{chunk-3KYZOC7N.js.map → chunk-YWKLUQDC.js.map} +0 -0
- /package/dist/{chunk-XYT6XY7G.js.map → chunk-ZLC4TSXF.js.map} +0 -0
- /package/dist/{client-2VVRJ3UF.js.map → client-VBV7Q43P.js.map} +0 -0
- /package/dist/{config-YSKHOV44.js.map → config-52C3DJD2.js.map} +0 -0
- /package/dist/{config-mutate-47WZDZBO.js.map → config-mutate-DKQESY6F.js.map} +0 -0
- /package/dist/{config-mutator-7DIEQUB5.js.map → config-mutator-BF4D4QGN.js.map} +0 -0
- /package/dist/{doctor-Q3QNZVLC.js.map → doctor-VLRC4HW2.js.map} +0 -0
- /package/dist/{follow-up-tool-GKZVG4L2.js.map → follow-up-tool-235LDEMP.js.map} +0 -0
- /package/dist/{hub-DNPINTIF.js.map → hub-5QK7KYTZ.js.map} +0 -0
- /package/dist/{promote-PETKX7KR.js.map → promote-UPPQ4BQE.js.map} +0 -0
- /package/dist/{query-D44BUTH3.js.map → query-XQS5JN6E.js.map} +0 -0
- /package/dist/{registry-2XDO53AJ.js.map → registry-MOMTLJ6R.js.map} +0 -0
- /package/dist/{request-planner-A3WJNPXO.js.map → request-planner-QGZJEAKY.js.map} +0 -0
- /package/dist/{review-candidates-A6ID2RDX.js.map → review-candidates-PAKF2JQF.js.map} +0 -0
- /package/dist/{rotation-memo-6UW6DTBQ.js.map → rotation-memo-7VLREGS6.js.map} +0 -0
- /package/dist/{routing-NPP3MEUW.js.map → routing-JG3EV4O4.js.map} +0 -0
- /package/dist/{schedule-tool-ZECUQMQK.js.map → schedule-tool-O7ZZ2A7X.js.map} +0 -0
- /package/dist/{scheduler-T6VLBM3U.js.map → scheduler-LMPBAA34.js.map} +0 -0
- /package/dist/{seat-D3DBYTSC.js.map → seat-JN3IVZ3G.js.map} +0 -0
- /package/dist/{select-RFY64RY7.js.map → select-ZMMRFMNO.js.map} +0 -0
- /package/dist/{set-enabled-AU66DR5C.js.map → set-enabled-7Y3TW6Z4.js.map} +0 -0
- /package/dist/{tool-F3YA2ZZQ.js.map → tool-OCYXCDOK.js.map} +0 -0
- /package/dist/{tool-PCHIVR27.js.map → tool-S7QI6HRA.js.map} +0 -0
- /package/dist/{wiki-NI3ZPUZS.js.map → wiki-OCLFFZG6.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/workspace-env.ts"],"sourcesContent":["import { readFileSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\n\n// Loads per-agent secrets from the agent's workspace and tells the runtime\n// which keys the daemon's own .env injected, so we can strip those before\n// spawning the agent's claude process. Without this, every agent inherits\n// the daemon's GITLAB_TOKEN regardless of whether their workspace has its\n// own .env.gitlab — defeating per-agent identity boundaries (each agent\n// should commit/push as itself, not as the daemon's account).\n\n/**\n * Parse a dotenv-style file. Tolerates the `export KEY=VALUE` form used by\n * shell-sourced files like .env.gitlab on peer-server.\n */\nfunction parseDotEnv(content: string): Array<[string, string]> {\n const out: Array<[string, string]> = []\n for (const raw of content.split(\"\\n\")) {\n const trimmed = raw.trim()\n if (!trimmed || trimmed.startsWith(\"#\")) continue\n const stripped = trimmed.startsWith(\"export \") ? trimmed.slice(7).trim() : trimmed\n const eq = stripped.indexOf(\"=\")\n if (eq === -1) continue\n const key = stripped.slice(0, eq).trim()\n let value = stripped.slice(eq + 1).trim()\n if (value.length >= 2 && ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\")))) {\n value = value.slice(1, -1)\n }\n if (key) out.push([key, value])\n }\n return out\n}\n\n/**\n * Read .env then .env.gitlab from a workspace and return their merged keys.\n * .env.gitlab wins on collision — it's the more specific per-channel file.\n */\nexport function loadWorkspaceEnv(workspace: string): Record<string, string> {\n const merged: Record<string, string> = {}\n for (const fname of [\".env\", \".env.gitlab\"]) {\n const path = resolve(workspace, fname)\n if (!existsSync(path)) continue\n try {\n for (const [k, v] of parseDotEnv(readFileSync(path, \"utf-8\"))) {\n merged[k] = v\n }\n } catch { /* best-effort */ }\n }\n return merged\n}\n\n/**\n * Keys defined in the daemon's own .env file, cached per daemonCwd. The\n * runtime uses this to strip those keys from the child env before adding\n * the workspace overrides — so a daemon-level GITLAB_TOKEN never leaks to\n * an agent that hasn't put one in its own workspace.\n */\nconst daemonEnvKeysCache = new Map<string, Set<string>>()\n\nexport function getDaemonEnvKeys(daemonCwd: string = process.cwd()): Set<string> {\n const cached = daemonEnvKeysCache.get(daemonCwd)\n if (cached) return cached\n const path = resolve(daemonCwd, \".env\")\n let keys: Set<string>\n if (!existsSync(path)) {\n keys = new Set()\n } else {\n try {\n keys = new Set(parseDotEnv(readFileSync(path, \"utf-8\")).map(([k]) => k))\n } catch {\n keys = new Set()\n }\n }\n daemonEnvKeysCache.set(daemonCwd, keys)\n return keys\n}\n\n/** Test-only: clear the cache so a different daemonCwd is re-read. */\nexport function _resetDaemonEnvKeysCache(): void {\n daemonEnvKeysCache.clear()\n}\n\n/**\n * Build the env object passed to a spawned agent process. Starts from\n * parentEnv (default process.env), removes any keys that came from the\n * daemon's own .env (so daemon-level secrets don't leak), then layers in\n * workspace .env / .env.gitlab.\n *\n * - System env (PATH, HOME, USER, …) survives untouched.\n * - Daemon-level secrets (e.g. GITLAB_TOKEN in /home/peer/agentx/.env) are\n * stripped UNLESS the workspace provides its own value for that key.\n * - Workspace env (per-agent .env / .env.gitlab) wins on the final merge.\n */\nexport function buildAgentEnv(\n workspace: string,\n parentEnv: NodeJS.ProcessEnv = process.env,\n daemonCwd: string = process.cwd(),\n): NodeJS.ProcessEnv {\n const workspaceEnv = loadWorkspaceEnv(workspace)\n const daemonOwnedKeys = getDaemonEnvKeys(daemonCwd)\n const child: NodeJS.ProcessEnv = { ...parentEnv }\n for (const k of daemonOwnedKeys) {\n if (!(k in workspaceEnv)) delete child[k]\n }\n for (const [k, v] of Object.entries(workspaceEnv)) {\n child[k] = v\n }\n return child\n}\n\n// Force the `claude` CLI to use OAuth/subscription billing. When\n// ANTHROPIC_API_KEY is present (env, systemd EnvironmentFile, daemon .env not\n// stripped because the workspace also defines it), the CLI silently switches\n// to the API-key path and any usage caps on that key surface as\n// \"You have reached your specified API usage limits...\". This caused\n// claude-code-tier agents to bypass the user's subscription. The same\n// stripping pattern lives in src/agent/providers/claude-code.ts for the\n// in-process provider — keep them in sync.\nexport function stripAnthropicApiKey(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n delete env.ANTHROPIC_API_KEY\n delete env.ANTHROPIC_API_KEY_OLD\n return env\n}\n\n/** `env` with the folders the fleet's CLIs install to added to PATH. A\n * process started by launchd, or the MCP server Claude Code starts, does\n * not get a login shell's PATH, and `claude` usually lives in\n * ~/.local/bin. */\nexport function withToolPath(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const home = env.HOME || process.env.HOME\n const parts = [\n env.PATH || \"\",\n home ? `${home}/.local/bin` : \"\",\n \"/opt/homebrew/bin\",\n \"/usr/local/bin\",\n ]\n env.PATH = Array.from(new Set(parts.flatMap((p) => p.split(\":\")).filter(Boolean))).join(\":\")\n return env\n}\n\n/** The env for a one-shot `claude -p` call: subscription billing and a\n * PATH that can find the CLI. */\nexport function claudeCliEnv(): NodeJS.ProcessEnv {\n return withToolPath(stripAnthropicApiKey({ ...process.env }))\n}\n\n/** How an agent's `claude` CLI is billed. \"subscription\" (the default) is\n * the OAuth login shared by the fleet. \"api\" bills ANTHROPIC_API_KEY\n * instead, for agents that must not draw on that shared quota, such as\n * benchmark runs. */\nexport type ClaudeBilling = \"subscription\" | \"api\"\n\n/** Shape a `claude` spawn env for the agent's billing. Each mode removes the\n * other's credential, because the CLI silently uses whichever it finds. An\n * \"api\" agent with no key throws rather than falling back to the\n * subscription. */\nexport function claudeBillingEnv(\n env: NodeJS.ProcessEnv,\n billing: ClaudeBilling = \"subscription\",\n): NodeJS.ProcessEnv {\n if (billing !== \"api\") return stripAnthropicApiKey(env)\n if (!env.ANTHROPIC_API_KEY) {\n throw new Error('billing \"api\" needs ANTHROPIC_API_KEY in the agent\\'s environment')\n }\n delete env.ANTHROPIC_API_KEY_OLD\n delete env.CLAUDE_CODE_OAUTH_TOKEN\n return env\n}\n\n/**\n * Load a dotenv file into process.env for the CURRENT process. Variables\n * already present win, so a systemd/launchd override always beats the file.\n *\n * `agentx daemon start` has always done this; `agentx board serve` did not,\n * so `${MESH_TOKEN}` in agentx.json expanded to \"\" inside the dashboard and\n * every proxied mesh call went out with an empty Bearer (401 from peers).\n */\nexport function loadEnvFileIntoProcess(path: string): void {\n if (!existsSync(path)) return\n for (const [key, value] of parseDotEnv(readFileSync(path, \"utf-8\"))) {\n if (process.env[key] === undefined) process.env[key] = value\n }\n}\n"],"mappings":"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","names":["readFileSync","existsSync","resolve","parseDotEnv","content","out","raw","trimmed","stripped","eq","key","value","loadWorkspaceEnv","workspace","merged","fname","path","k","v","daemonEnvKeysCache","getDaemonEnvKeys","daemonCwd","cached","keys","buildAgentEnv","workspace","parentEnv","daemonCwd","workspaceEnv","loadWorkspaceEnv","daemonOwnedKeys","getDaemonEnvKeys","child","k","v","stripAnthropicApiKey","env","withToolPath","home","parts","p","claudeCliEnv","claudeBillingEnv","billing","loadEnvFileIntoProcess","path","existsSync","key","value","parseDotEnv","readFileSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/workspace-env.ts"],"sourcesContent":["import { readFileSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\n\n// Loads per-agent secrets from the agent's workspace and tells the runtime\n// which keys the daemon's own .env injected, so we can strip those before\n// spawning the agent's claude process. Without this, every agent inherits\n// the daemon's GITLAB_TOKEN regardless of whether their workspace has its\n// own .env.gitlab — defeating per-agent identity boundaries (each agent\n// should commit/push as itself, not as the daemon's account).\n\n/**\n * Parse a dotenv-style file. Tolerates the `export KEY=VALUE` form used by\n * shell-sourced files like .env.gitlab on peer-server.\n */\nfunction parseDotEnv(content: string): Array<[string, string]> {\n const out: Array<[string, string]> = []\n for (const raw of content.split(\"\\n\")) {\n const trimmed = raw.trim()\n if (!trimmed || trimmed.startsWith(\"#\")) continue\n const stripped = trimmed.startsWith(\"export \") ? trimmed.slice(7).trim() : trimmed\n const eq = stripped.indexOf(\"=\")\n if (eq === -1) continue\n const key = stripped.slice(0, eq).trim()\n let value = stripped.slice(eq + 1).trim()\n if (value.length >= 2 && ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\")))) {\n value = value.slice(1, -1)\n }\n if (key) out.push([key, value])\n }\n return out\n}\n\n/**\n * Read .env then .env.gitlab from a workspace and return their merged keys.\n * .env.gitlab wins on collision — it's the more specific per-channel file.\n */\nexport function loadWorkspaceEnv(workspace: string): Record<string, string> {\n const merged: Record<string, string> = {}\n for (const fname of [\".env\", \".env.gitlab\"]) {\n const path = resolve(workspace, fname)\n if (!existsSync(path)) continue\n try {\n for (const [k, v] of parseDotEnv(readFileSync(path, \"utf-8\"))) {\n merged[k] = v\n }\n } catch { /* best-effort */ }\n }\n return merged\n}\n\n/**\n * Keys defined in the daemon's own .env file, cached per daemonCwd. The\n * runtime uses this to strip those keys from the child env before adding\n * the workspace overrides — so a daemon-level GITLAB_TOKEN never leaks to\n * an agent that hasn't put one in its own workspace.\n */\nconst daemonEnvKeysCache = new Map<string, Set<string>>()\n\nexport function getDaemonEnvKeys(daemonCwd: string = process.cwd()): Set<string> {\n const cached = daemonEnvKeysCache.get(daemonCwd)\n if (cached) return cached\n const path = resolve(daemonCwd, \".env\")\n let keys: Set<string>\n if (!existsSync(path)) {\n keys = new Set()\n } else {\n try {\n keys = new Set(parseDotEnv(readFileSync(path, \"utf-8\")).map(([k]) => k))\n } catch {\n keys = new Set()\n }\n }\n daemonEnvKeysCache.set(daemonCwd, keys)\n return keys\n}\n\n/** Test-only: clear the cache so a different daemonCwd is re-read. */\nexport function _resetDaemonEnvKeysCache(): void {\n daemonEnvKeysCache.clear()\n}\n\n/**\n * Build the env object passed to a spawned agent process. Starts from\n * parentEnv (default process.env), removes any keys that came from the\n * daemon's own .env (so daemon-level secrets don't leak), then layers in\n * workspace .env / .env.gitlab.\n *\n * - System env (PATH, HOME, USER, …) survives untouched.\n * - Daemon-level secrets (e.g. GITLAB_TOKEN in /home/peer/agentx/.env) are\n * stripped UNLESS the workspace provides its own value for that key.\n * - Workspace env (per-agent .env / .env.gitlab) wins on the final merge.\n */\nexport function buildAgentEnv(\n workspace: string,\n parentEnv: NodeJS.ProcessEnv = process.env,\n daemonCwd: string = process.cwd(),\n): NodeJS.ProcessEnv {\n const workspaceEnv = loadWorkspaceEnv(workspace)\n const daemonOwnedKeys = getDaemonEnvKeys(daemonCwd)\n const child: NodeJS.ProcessEnv = { ...parentEnv }\n for (const k of daemonOwnedKeys) {\n if (!(k in workspaceEnv)) delete child[k]\n }\n for (const [k, v] of Object.entries(workspaceEnv)) {\n child[k] = v\n }\n return child\n}\n\n// Force the `claude` CLI to use OAuth/subscription billing. When\n// ANTHROPIC_API_KEY is present (env, systemd EnvironmentFile, daemon .env not\n// stripped because the workspace also defines it), the CLI silently switches\n// to the API-key path and any usage caps on that key surface as\n// \"You have reached your specified API usage limits...\". This caused\n// claude-code-tier agents to bypass the user's subscription. The same\n// stripping pattern lives in src/agent/providers/claude-code.ts for the\n// in-process provider — keep them in sync.\nexport function stripAnthropicApiKey(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n delete env.ANTHROPIC_API_KEY\n delete env.ANTHROPIC_API_KEY_OLD\n return env\n}\n\n/** `env` with the folders the fleet's CLIs install to added to PATH. A\n * process started by launchd, or the MCP server Claude Code starts, does\n * not get a login shell's PATH, and `claude` usually lives in\n * ~/.local/bin. */\nexport function withToolPath(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const home = env.HOME || process.env.HOME\n const parts = [\n env.PATH || \"\",\n home ? `${home}/.local/bin` : \"\",\n \"/opt/homebrew/bin\",\n \"/usr/local/bin\",\n ]\n env.PATH = Array.from(new Set(parts.flatMap((p) => p.split(\":\")).filter(Boolean))).join(\":\")\n return env\n}\n\n/** The env for a one-shot `claude -p` call: subscription billing, a\n * PATH that can find the CLI, and no CLAUDECODE marker. Inside an\n * agent's session (the MCP server, an agent's own shell) the marker is\n * inherited and the CLI refuses to start a nested session, which is how\n * `agentx_wiki_patch` and `agentx_wiki_interview` failed at `claude -p`\n * (#824). session-monitor and talk-model drop it for the same reason. */\nexport function claudeCliEnv(): NodeJS.ProcessEnv {\n const env = withToolPath(stripAnthropicApiKey({ ...process.env }))\n delete env.CLAUDECODE\n return env\n}\n\n/** How an agent's `claude` CLI is billed. \"subscription\" (the default) is\n * the OAuth login shared by the fleet. \"api\" bills ANTHROPIC_API_KEY\n * instead, for agents that must not draw on that shared quota, such as\n * benchmark runs. */\nexport type ClaudeBilling = \"subscription\" | \"api\"\n\n/** Shape a `claude` spawn env for the agent's billing. Each mode removes the\n * other's credential, because the CLI silently uses whichever it finds. An\n * \"api\" agent with no key throws rather than falling back to the\n * subscription. */\nexport function claudeBillingEnv(\n env: NodeJS.ProcessEnv,\n billing: ClaudeBilling = \"subscription\",\n): NodeJS.ProcessEnv {\n if (billing !== \"api\") return stripAnthropicApiKey(env)\n if (!env.ANTHROPIC_API_KEY) {\n throw new Error('billing \"api\" needs ANTHROPIC_API_KEY in the agent\\'s environment')\n }\n delete env.ANTHROPIC_API_KEY_OLD\n delete env.CLAUDE_CODE_OAUTH_TOKEN\n return env\n}\n\n/**\n * Load a dotenv file into process.env for the CURRENT process. Variables\n * already present win, so a systemd/launchd override always beats the file.\n *\n * `agentx daemon start` has always done this; `agentx board serve` did not,\n * so `${MESH_TOKEN}` in agentx.json expanded to \"\" inside the dashboard and\n * every proxied mesh call went out with an empty Bearer (401 from peers).\n */\nexport function loadEnvFileIntoProcess(path: string): void {\n if (!existsSync(path)) return\n for (const [key, value] of parseDotEnv(readFileSync(path, \"utf-8\"))) {\n if (process.env[key] === undefined) process.env[key] = value\n }\n}\n"],"mappings":"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","names":["readFileSync","existsSync","resolve","parseDotEnv","content","out","raw","trimmed","stripped","eq","key","value","loadWorkspaceEnv","workspace","merged","fname","path","k","v","daemonEnvKeysCache","getDaemonEnvKeys","daemonCwd","cached","keys","buildAgentEnv","workspace","parentEnv","daemonCwd","workspaceEnv","loadWorkspaceEnv","daemonOwnedKeys","getDaemonEnvKeys","child","k","v","stripAnthropicApiKey","env","withToolPath","home","parts","p","claudeCliEnv","claudeBillingEnv","billing","loadEnvFileIntoProcess","path","existsSync","key","value","parseDotEnv","readFileSync"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as rt,b as ot,c as st,d as x,e as A,f as v}from"./chunk-72SZI2UW.js";import{a as ne,b as et}from"./chunk-FCPTN6NF.js";import{a as Te,b as ht}from"./chunk-MCI3DIWW.js";import{o as we,p as Ze}from"./chunk-2PJKGZWP.js";import{
|
|
1
|
+
import{a as rt,b as ot,c as st,d as x,e as A,f as v}from"./chunk-72SZI2UW.js";import{a as ne,b as et}from"./chunk-FCPTN6NF.js";import{a as Te,b as ht}from"./chunk-MCI3DIWW.js";import{o as we,p as Ze}from"./chunk-2PJKGZWP.js";import{ta as tt,ua as nt}from"./chunk-MRYA4J5F.js";import{a as it,b as at,c as ct,d as ut,e as lt,f as dt,g as pt,h as mt,i as bt,j as ft,k as gt,l as yt}from"./chunk-RGDKHYY2.js";import{a as E,b as We,c as he}from"./chunk-QIJLFPWE.js";function R(e,t){$.set(e,t),X.delete(e)}function D(e){let t=X.get(e);if(t)return t;let r=$.get(e);if(!r){let o=Ee();throw new Error(`unknown decision backend "${e}"`+(o.length>0?` \u2014 registered: ${o.join(", ")}`:" \u2014 none registered"))}let n=r();return X.set(e,n),n}function Ee(){return[...$.keys()].sort()}function wt(){$.clear(),X.clear()}var $,X,C=E(()=>{"use strict";$=new Map,X=new Map});import Tt from"better-sqlite3";import{createHash as Et}from"crypto";import{mkdirSync as kt}from"fs";import{dirname as St,resolve as xt}from"path";function Q(e){if(e.type==="noul"){let r=e.noul,n={yes:r,no:1-r},o=r>=.5?"yes":"no",s=Math.abs(r-.5)*2;return{predicted:o,confidence:s,probabilities:n,topLabel:o,topProb:Math.max(r,1-r),expectedScore:null,pMax:Math.max(r,1-r),negEntropy:s}}if(e.type==="choice")return{predicted:e.choice,confidence:e.confidence,probabilities:{...e.probabilities},topLabel:e.choice,topProb:e.probabilities[e.choice]??0,expectedScore:null,pMax:e.pMax,negEntropy:e.negEntropy};let t=String(Math.round(e.score));return{predicted:t,confidence:e.confidence,probabilities:{...e.probabilities},topLabel:t,topProb:e.probabilities[t]??0,expectedScore:e.score,pMax:e.pMax,negEntropy:e.negEntropy}}function At(e){if(typeof e!="string"||e.length===0)return{};try{let t=JSON.parse(e);return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function Rt(e){e.exec("CREATE TABLE IF NOT EXISTS schema_version (v INTEGER PRIMARY KEY);");let t=e.prepare("SELECT MAX(v) AS v FROM schema_version").get().v??0;t<1&&vt(e),t<2&&Ot(e),t<3&&_t(e)}function _t(e){e.exec(`
|
|
2
2
|
ALTER TABLE decision_calls ADD COLUMN features_json TEXT;
|
|
3
3
|
INSERT INTO schema_version (v) VALUES (3);
|
|
4
4
|
`)}function Ot(e){e.exec(`
|
|
@@ -111,4 +111,4 @@ import{a as rt,b as ot,c as st,d as x,e as A,f as v}from"./chunk-72SZI2UW.js";im
|
|
|
111
111
|
`)}if(!m)throw new Error(`local decision backend could not get a valid answer after ${f+1} attempt(s): ${w}`);let M={},L=!1;for(let[k,q]of Object.entries(s.questions)){let S=_(q,m[k],{normalize:e.normalizeProbabilities??!0});M[k]=S.answer,S.repaired&&(L=!0)}return{model:a,answers:M,usage:h,meta:{backend:"local",structureMode:c,answerMode:"probabilities",repaired:L,retries:f,stateTruncated:l.truncated,latencyMs:Date.now()-i}}}finally{b()}}}}async function Jt(e,t,r,n,o){if(!e.generateRaw)throw new Error(`provider "${e.name}" has no generateRaw(); use structureMode "text"`);let s=[{role:"user",content:r},...n?[{role:"user",content:n}]:[]],i=await e.generateRaw(s,J,[{name:F,description:"Report a probability distribution for every question.",input_schema:se(t)}],{...o,toolChoice:{type:"tool",name:F}}),a=i.content.find(c=>c.type==="tool_use"&&c.name===F),u=a&&a.type==="tool_use"?a.input:null;return{answers:Be(u),usage:{inputTokens:i.usage.input_tokens,outputTokens:i.usage.output_tokens}}}async function Gt(e,t,r,n,o){let s=[r,ae(t)].join(`
|
|
112
112
|
`),i=[{role:"system",content:J},{role:"user",content:s},...n?[{role:"user",content:n}]:[]],a=await e.generate(i,o);return{answers:Be(Te(a.content??"")),usage:{inputTokens:0,outputTokens:a.tokensUsed??0}}}function Be(e){if(e&&typeof e=="object"&&!Array.isArray(e)){let t=e;if(t.answers&&typeof t.answers=="object")return t.answers}return e}function Yt(e,t){return e!=="auto"?e:t.generateRaw&&me[t.name]?.structuredOutput?"tool":"text"}function Kt(e,t){let r=new AbortController,n=setTimeout(()=>r.abort(new Error(`decision timed out after ${t}ms`)),t),o=()=>r.abort(e?.reason);return e&&(e.aborted?o():e.addEventListener("abort",o,{once:!0})),{signal:r.signal,dispose:()=>{clearTimeout(n),e?.removeEventListener("abort",o)}}}var Xt,$t,Vt,Fe,zt,be=E(()=>{"use strict";Ze();Ue();ht();j();Y();v();z();Xt="claude-code",$t="claude-haiku-4-5-20251001",Vt=24e3,Fe=2e3,zt=3e4});import{readFileSync as Ht}from"fs";import{homedir as Wt}from"os";import{join as Zt}from"path";function N(e={}){let t=(e.baseUrl??en).replace(/\/+$/,""),r=e.path??"/classifier",n=e.name??"simple-jev",o=e.maxStateChars??nn,s=e.maxChoiceOptions??rn,i={probabilitySource:e.probabilitySource??"logits",calibratedProbabilities:!1,maxChoiceOptions:s,maxStateChars:o,parallelQuestions:!0,images:!1};return{name:n,capabilities:i,async decide(a){A(a.questions),cn(a.questions,s);let u=Date.now(),c=a.model??e.model;if(!c)throw new Error("simple-jev backend needs a model id");let l=G(a.state,o),p=e.fetchImpl??fetch,{signal:g,dispose:d}=un(a.abortSignal,a.timeoutMs??e.timeoutMs??tn);try{let b={"Content-Type":"application/json"},h=an(e.apiKeyEnv,e.apiKeyFile);h&&(b.Authorization=`Bearer ${h}`);let T=await qe(p(`${t}${r}`,{method:"POST",headers:b,body:JSON.stringify({model:c,state:l.text,questions:sn(a.questions)}),signal:g}),g);if(!T.ok){let k=await T.text().catch(()=>"");throw new Error(`${n} ${T.status}: ${k.slice(0,300)}`)}let f=await qe(T.json(),g),m=P(a.questions).safeParse(f.answers);if(!m.success)throw new Error(`${n} returned a response that does not match the requested questions (contract drift, not a model slip \u2014 retrying will not help):
|
|
113
113
|
${U(m.error)}`);let w=m.data,M={},L=!1;for(let[k,q]of Object.entries(a.questions)){let S=_(q,w[k]);M[k]=S.answer,S.repaired&&(L=!0)}return{model:f.model??c,answers:M,usage:{inputTokens:f.usage?.input_tokens??0,outputTokens:f.usage?.output_tokens??0},meta:{backend:n,structureMode:i.probabilitySource==="native"?"native":"logprobs",answerMode:"probabilities",repaired:L,retries:0,stateTruncated:l.truncated,latencyMs:Date.now()-u}}}finally{d()}}}}function sn(e){let t={};for(let[r,n]of Object.entries(e))t[r]=n.instructions?n:{...n,instructions:on[n.type]};return t}function an(e,t){let r=e?process.env[e]:void 0;if(r)return r;if(!t)return;let n=t.startsWith("~/")?Zt(Wt(),t.slice(2)):t;if(!Z.has(n))try{let o=Ht(n,"utf-8").trim();Z.set(n,o.length>0?o:null)}catch{Z.set(n,null)}return Z.get(n)??void 0}function cn(e,t){for(let[r,n]of Object.entries(e))if(n.type==="choice"){let o=Object.keys(n.criteria).length;if(o>t)throw new Error(`question "${r}": accepts at most ${t} choice options, got ${o}`)}else if(n.type==="score"&&n.criteria.length>t)throw new Error(`question "${r}": accepts at most ${t} score levels, got ${n.criteria.length}`)}function qe(e,t){return t.aborted?Promise.reject(t.reason??new Error("aborted")):new Promise((r,n)=>{let o=()=>n(t.reason??new Error("aborted"));t.addEventListener("abort",o,{once:!0}),e.then(s=>{t.removeEventListener("abort",o),r(s)},s=>{t.removeEventListener("abort",o),n(s)})})}function un(e,t){let r=new AbortController,n=setTimeout(()=>r.abort(new Error(`decision timed out after ${t}ms`)),t),o=()=>r.abort(e?.reason);return e&&(e.aborted?o():e.addEventListener("abort",o,{once:!0})),{signal:r.signal,dispose:()=>{clearTimeout(n),e?.removeEventListener("abort",o)}}}var en,tn,nn,rn,on,Z,fe=E(()=>{"use strict";j();v();z();Y();en="http://127.0.0.1:8000/v1",tn=3e4,nn=6e3,rn=50;on={choice:"Which option best fits?",score:"Which level best fits?",noul:"Is this true of the state?"};Z=new Map});var Xe={};We(Xe,{DEFAULT_SEAT_TIMEOUT_MS:()=>Ve,DecisionStore:()=>I,MAX_CHOICE_OPTIONS:()=>MAX_CHOICE_OPTIONS,SYSTEM_PROMPT:()=>J,TOOL_NAME:()=>F,UNCERTAINTY_HIGH:()=>Ce,UNCERTAINTY_LOW:()=>De,_resetDecisionBackendsForTesting:()=>wt,agreement:()=>it,answerView:()=>Q,applyRecalibrator:()=>ue,applyTemperature:()=>mt,askSeat:()=>yn,band:()=>Ie,bootstrapInterval:()=>ft,brier:()=>lt,buildDesign:()=>ve,calibrationReport:()=>gt,choice:()=>ot,compareCalibrators:()=>It,confidenceFor:()=>re,configureDecisions:()=>pn,configuredSeatTimeout:()=>dn,coverageCurve:()=>pt,createLocalDecisionBackend:()=>W,createMockDecisionBackend:()=>H,createSimpleJevBackend:()=>N,decisionsRuntime:()=>bn,describeIssues:()=>U,ece:()=>ct,expectedScore:()=>Ae,finalizeAnswer:()=>_,fitLogistic:()=>Ne,fitRecalibrator:()=>B,fitTemperature:()=>bt,getDecisionBackend:()=>D,getSeatMode:()=>Je,labelSeatCall:()=>fn,labelsOf:()=>x,listDecisionBackends:()=>Ee,logLoss:()=>dt,logit:()=>le,mce:()=>ut,measureConsistency:()=>Ut,normalizeDistribution:()=>Se,normalizedNegEntropy:()=>oe,noul:()=>rt,pMax:()=>xe,parseSeatMode:()=>ge,rawAnswerSchema:()=>Re,rawAnswersSchema:()=>P,recordSeatOutcome:()=>gn,registerBuiltinDecisionBackends:()=>ln,registerDecisionBackend:()=>R,reliabilityBins:()=>at,renderQuestions:()=>_e,renderShapeInstructions:()=>ae,renderState:()=>G,renderUserPrompt:()=>ie,resetDecisionsRuntime:()=>mn,score:()=>st,seatEnvVar:()=>ze,sigmoid:()=>de,toolInputSchema:()=>se,validateQuestions:()=>A,withUid:()=>Qe});function ln(e={},t={},r={},n={}){R("mock",()=>H()),R("local",()=>W(e)),R("simple-jev",()=>N(t)),R("jev",()=>N({name:"jev",baseUrl:"https://openrouter.ai/api/alpha",path:"/decisions",model:"jev-latest",apiKeyEnv:"OPENROUTER_API_KEY",apiKeyFile:"~/.agentx/openrouter-key.txt",probabilitySource:"native",maxChoiceOptions:255,maxStateChars:9e4,...r})),R("typesafe",()=>N({name:"typesafe",baseUrl:"https://api.typesafe.ai/v1",path:"/systemone",model:"jev-latest",apiKeyEnv:"TYPESAFE_API_KEY",apiKeyFile:"~/.agentx/typesafe-key.txt",probabilitySource:"native",maxChoiceOptions:255,maxStateChars:9e4,...n}))}var $e=E(()=>{"use strict";ke();v();j();z();C();Y();V();yt();Me();je();Ge();pe();be();fe();C();pe();be();fe()});function dn(e){return Ke(),y.seats[e]?.timeoutMs}function pn(e){y={...ye,...y,...e},ee=!0}function mn(){y={...ye,seats:{}},ee=!1}function Ke(){if(!ee){ee=!0;try{let{loadDaemonConfig:e}=(nt(),he(tt)),t=e()?.decisions;if(!t?.enabled)return;let{registerBuiltinDecisionBackends:r}=($e(),he(Xe)),n=t.backends??{};r(n.local,n.simpleJev,n.jev,n.typesafe);let o=null;try{o=new I({path:t.dbPath})}catch{}y={enabled:!0,defaultBackend:t.defaultBackend,store:o,seats:Object.fromEntries(Object.entries(t.seats??{}).map(([s,i])=>[s,{...i,redactState:t.redactState,keepStateRows:t.keepStateRows}]))}}catch{}}}function bn(){return y}function ge(e){if(typeof e!="string")return null;let t=e.trim().toLowerCase();return hn.includes(t)?t:null}function ze(e){return`AGENTX_DECISION_SEAT_${e.toUpperCase().replace(/[^A-Z0-9]+/g,"_")}`}function Je(e,t=process.env){Ke();let r=ge(t[ze(e)]);return r||(y.enabled?ge(y.seats[e]?.mode)??"off":"off")}function fn(e,t,r,n={}){if(!(!e||!y.store))try{y.store.label(e,t,r,n)}catch{}}function gn(e,t,r=!1){if(!(!e||!y.store))try{y.store.recordOutcome(e,t,r)}catch{}}async function yn(e,t,r,n={}){let o=Je(e);if(o==="off")return null;let s=y.seats[e]??{mode:o},i=n.backend??s.backend??y.defaultBackend,a=Date.now();try{let c=await D(i).decide({state:t,questions:r,model:n.model??s.model,abortSignal:n.signal,timeoutMs:n.timeoutMs??s.timeoutMs??(y.seats[e]?Ve:void 0)}),l=wn(e,o,t,r,c,n,s);return{answers:c.answers,callId:l,mode:o}}catch(u){return Tn(e,o,t,r,i,n,s,a,u),En(e,i,u),null}}function wn(e,t,r,n,o,s,i){if(!y.store)return null;try{return y.store.recordCall({seat:e,mode:t,backend:o.meta.backend,model:o.model,meta:o.meta,state:r,questions:n,answers:o.answers,usage:o.usage,incumbent:He(s.incumbent),links:s.links,features:s.features,keepState:!i.redactState})}catch{return null}}function Tn(e,t,r,n,o,s,i,a,u){if(y.store)try{y.store.recordCall({seat:e,mode:t,backend:o,model:s.model??i.model??"unknown",meta:{structureMode:"text",answerMode:"probabilities",retries:0,stateTruncated:!1,latencyMs:Date.now()-a},state:r,questions:n,answers:{},incumbent:He(s.incumbent),links:s.links,features:s.features,error:String(u?.message??u).slice(0,500),keepState:!i.redactState})}catch{}}function He(e){if(!e)return;let t={};for(let[r,n]of Object.entries(e))n!==void 0&&(t[r]={value:n});return t}function En(e,t,r){let n=Date.now();n-Ye<6e4||(Ye=n,console.warn(`[decisions] seat "${e}" on backend "${t}" failed: ${r?.message??r}`))}var Ve,ye,y,ee,hn,Ye,Ge=E(()=>{C();V();Ve=1e4;ye={enabled:!1,defaultBackend:"local",seats:{},store:null},y={...ye},ee=!1;hn=["off","shadow","active"];Ye=0});export{D as a,Ee as b,C as c,I as d,V as e,It as f,Me as g,Ut as h,je as i,me as j,Xn as k,Ue as l,ln as m,$e as n,Ve as o,dn as p,pn as q,mn as r,bn as s,ge as t,ze as u,Je as v,fn as w,gn as x,yn as y,Ge as z};
|
|
114
|
-
//# sourceMappingURL=chunk-
|
|
114
|
+
//# sourceMappingURL=chunk-YWKLUQDC.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{a as h}from"./chunk-P4XGM7ZM.js";import{resolve as n}from"path";import{existsSync as c,readdirSync as u,mkdirSync as l,readFileSync as p,writeFileSync as f,renameSync as S}from"fs";var m=class{baseDir;agentsDir;mode;sharedStore;agentStores=new Map;log;constructor(e=n(process.cwd(),".agentx/wiki"),r=console.error.bind(console,"[wiki-hub]"),t="graph"){this.baseDir=e,this.agentsDir=n(e,"agents"),this.mode=t,this.log=r,l(this.agentsDir,{recursive:!0}),this.sharedStore=new h(e,r)}getMode(){return this.mode}getAgentWiki(e){let r=`${e}:${this.mode}`;if(this.agentStores.has(r))return this.agentStores.get(r);let t=n(this.agentsDir,e,this.mode),s=new h(t,this.log);return this.agentStores.set(r,s),s}getBaseDir(){return this.baseDir}getSharedStore(){return this.sharedStore}sharedScope(e){return[...this.listAgentDirs().filter(t=>t!==e).map(t=>({id:t,store:this.getAgentWiki(t)})),{id:"shared",store:this.sharedStore,skip:t=>t.startsWith("agents/")}]}listAgentDirs(){return c(this.agentsDir)?u(this.agentsDir).filter(e=>!e.startsWith("_")&&!e.startsWith(".")&&c(n(this.agentsDir,e,this.mode))).sort():[]}listAgents(e=this.sharedStore.listEntries()){let r=new Set;for(let t of e)r.add(t.agentId);if(c(this.agentsDir))for(let t of u(this.agentsDir))!t.startsWith("_")&&!t.startsWith(".")&&r.add(t);return[...r].sort()}getAgentEntries(e){return this.sharedStore.listEntries({agentId:e})}getUnabsorbedEntries(e){return this.classifyEntries(e).pending}markProcessed(e,r,t){let s=new Set(t),g=this.readLedger(e),d=new Date().toISOString();for(let i of r)g.entries[i]={at:d,cited:s.has(i)};let o=this.ledgerPath(e);l(n(o,".."),{recursive:!0});let a=`${o}.tmp`;f(a,`${JSON.stringify(g,null,2)}
|
|
2
|
+
`),S(a,o)}summary(){let e=this.sharedStore.listEntries(),r=new Map;for(let t of e){let s=r.get(t.agentId);s?s.push(t):r.set(t.agentId,[t])}return this.listAgents(e).map(t=>{let{all:s,cited:g,read:d,pending:o,articles:a}=this.classifyEntries(t,r.get(t)??[]);return{agentId:t,totalEntries:s.length,totalArticles:a.length,cited:g.length,readNotCited:d.length,unabsorbed:o.length,articles:a}})}classifyEntries(e,r=this.getAgentEntries(e)){let t=this.getAgentWiki(e).rebuildIndex().articles,s=new Set;for(let i of t)if(i.sources)for(let y of i.sources)s.add(y);let g=this.readLedger(e).entries,d=[],o=[],a=[];for(let i of r)s.has(i.id)?d.push(i):g[i.id]?o.push(i):a.push(i);return{all:r,cited:d,read:o,pending:a,articles:t}}syncedFrom(e){let r=n(this.agentsDir,e,"_synced.json");if(!c(r))return null;try{return JSON.parse(p(r,"utf-8"))}catch(t){return this.log(`synced marker ${r} is not valid JSON: ${t.message}`),{node:"unknown",peerUrl:"",at:""}}}markSynced(e,r){let t=n(this.agentsDir,e,"_synced.json");l(n(t,".."),{recursive:!0});let s=`${t}.tmp`;f(s,`${JSON.stringify(r,null,2)}
|
|
3
|
+
`),S(s,t)}ledgerPath(e){return n(this.agentsDir,e,"_absorbed.json")}readLedger(e){let r=this.ledgerPath(e);if(!c(r))return{entries:{}};try{return{entries:JSON.parse(p(r,"utf-8")).entries??{}}}catch(t){throw new Error(`absorb ledger ${r} is not valid JSON: ${t.message}`)}}};export{m as a};
|
|
4
|
+
//# sourceMappingURL=chunk-Z3W7D5RR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/wiki/hub.ts"],"sourcesContent":["import { WikiStore } from \"./store\"\nimport { resolve } from \"path\"\nimport { existsSync, readdirSync, mkdirSync, readFileSync, writeFileSync, renameSync } from \"fs\"\nimport type { WikiEntry } from \"./types\"\nimport type { SharedWikiStore } from \"./query\"\n\nexport type WikiMode = \"flat\" | \"graph\" | \"unified\"\n\n/**\n * WikiHub: manages per-agent wikis with a shared raw entry pool.\n * Supports two compilation modes:\n * - flat: Karpathy pattern — tags, LLM-chosen paths, worldview, gap detection\n * - graph: Knowledge graph — kind, parent, hierarchy, events, entities\n *\n * Both modes share the same raw entries. Articles stored separately:\n * agents/<id>/flat/ ← Karpathy compilation\n * agents/<id>/graph/ ← Knowledge graph compilation\n */\nexport class WikiHub {\n private baseDir: string\n private agentsDir: string\n private mode: WikiMode\n private sharedStore: WikiStore\n private agentStores: Map<string, WikiStore> = new Map()\n private log: (...args: unknown[]) => void\n\n constructor(\n baseDir: string = resolve(process.cwd(), \".agentx/wiki\"),\n log: (...args: unknown[]) => void = console.error.bind(console, \"[wiki-hub]\"),\n mode: WikiMode = \"graph\",\n ) {\n this.baseDir = baseDir\n this.agentsDir = resolve(baseDir, \"agents\")\n this.mode = mode\n this.log = log\n\n mkdirSync(this.agentsDir, { recursive: true })\n this.sharedStore = new WikiStore(baseDir, log)\n }\n\n getMode(): WikiMode { return this.mode }\n\n /**\n * Get or create the wiki store for a specific agent (mode-aware).\n * flat: agents/<id>/flat/\n * graph: agents/<id>/graph/\n */\n getAgentWiki(agentId: string): WikiStore {\n const key = `${agentId}:${this.mode}`\n if (this.agentStores.has(key)) return this.agentStores.get(key)!\n\n const agentDir = resolve(this.agentsDir, agentId, this.mode)\n const store = new WikiStore(agentDir, this.log)\n this.agentStores.set(key, store)\n return store\n }\n\n /** The wiki root: shared sidecars (_facts.json, _questions.json) live here. */\n getBaseDir(): string {\n return this.baseDir\n }\n\n getSharedStore(): WikiStore {\n return this.sharedStore\n }\n\n /**\n * The wikis a query by `agentId` reads besides its own: every other\n * agent's articles and the root store's own (promoted lessons). Which\n * articles of theirs it may read is still decided per article by access.\n * Without this an agent's query missed answers the shared wiki had (#824).\n */\n sharedScope(agentId: string): SharedWikiStore[] {\n const others = this.listAgentDirs()\n .filter((id) => id !== agentId)\n .map((id) => ({ id, store: this.getAgentWiki(id) }))\n // The root store's walk also reaches agents/<id>/…; those are read\n // through their own store above.\n return [...others, { id: \"shared\", store: this.sharedStore, skip: (p: string) => p.startsWith(\"agents/\") }]\n }\n\n /** Agents with a wiki folder here, without reading the raw entries. */\n private listAgentDirs(): string[] {\n if (!existsSync(this.agentsDir)) return []\n return readdirSync(this.agentsDir)\n .filter((d) => !d.startsWith(\"_\") && !d.startsWith(\".\") && existsSync(resolve(this.agentsDir, d, this.mode)))\n .sort()\n }\n\n listAgents(entries: WikiEntry[] = this.sharedStore.listEntries()): string[] {\n const agents = new Set<string>()\n\n for (const e of entries) agents.add(e.agentId)\n\n if (existsSync(this.agentsDir)) {\n for (const dir of readdirSync(this.agentsDir)) {\n if (!dir.startsWith(\"_\") && !dir.startsWith(\".\")) {\n agents.add(dir)\n }\n }\n }\n\n return [...agents].sort()\n }\n\n getAgentEntries(agentId: string): WikiEntry[] {\n return this.sharedStore.listEntries({ agentId })\n }\n\n /**\n * Entries absorb has not dealt with yet: no article cites them and no\n * successful absorb run has read them. Without the second check an\n * entry absorb read and chose not to cite came back on every run, and\n * a backfill kept re-reading the head of the queue (#762).\n */\n getUnabsorbedEntries(agentId: string): WikiEntry[] {\n return this.classifyEntries(agentId).pending\n }\n\n /**\n * Record every entry handed to the model in a successful absorb run,\n * cited or not. Callers must not call this for a failed run, so those\n * entries are offered again.\n */\n markProcessed(agentId: string, entryIds: string[], citedIds: Iterable<string>): void {\n const cited = new Set(citedIds)\n const ledger = this.readLedger(agentId)\n const at = new Date().toISOString()\n for (const id of entryIds) ledger.entries[id] = { at, cited: cited.has(id) }\n\n const file = this.ledgerPath(agentId)\n mkdirSync(resolve(file, \"..\"), { recursive: true })\n const tmp = `${file}.tmp`\n writeFileSync(tmp, `${JSON.stringify(ledger, null, 2)}\\n`)\n renameSync(tmp, file)\n }\n\n /**\n * Counts and articles per agent, for `GET /wiki/agents` and the mesh.\n * The raw entries are read once and grouped here: reading them again\n * per agent made the endpoint take 25 to 75 s on a fleet with 30\n * agents and 10k entries, past the mesh client's 5 s timeout (#603).\n */\n summary(): AgentWikiSummary[] {\n const entries = this.sharedStore.listEntries()\n const byAgent = new Map<string, WikiEntry[]>()\n for (const e of entries) {\n const list = byAgent.get(e.agentId)\n if (list) list.push(e)\n else byAgent.set(e.agentId, [e])\n }\n return this.listAgents(entries).map(agentId => {\n const { all, cited, read, pending, articles } = this.classifyEntries(agentId, byAgent.get(agentId) ?? [])\n return {\n agentId,\n totalEntries: all.length,\n totalArticles: articles.length,\n cited: cited.length,\n readNotCited: read.length,\n unabsorbed: pending.length,\n articles,\n }\n })\n }\n\n /** Split an agent's entries into cited by an article, read but not cited, and pending. */\n private classifyEntries(agentId: string, all: WikiEntry[] = this.getAgentEntries(agentId)) {\n const articles = this.getAgentWiki(agentId).rebuildIndex().articles\n\n const citedIds = new Set<string>()\n for (const article of articles) {\n if (article.sources) {\n for (const s of article.sources) citedIds.add(s)\n }\n }\n const ledger = this.readLedger(agentId).entries\n\n const cited: WikiEntry[] = []\n const read: WikiEntry[] = []\n const pending: WikiEntry[] = []\n for (const e of all) {\n if (citedIds.has(e.id)) cited.push(e)\n else if (ledger[e.id]) read.push(e)\n else pending.push(e)\n }\n return { all, cited, read, pending, articles }\n }\n\n /**\n * The peer an agent's articles were copied from by `wiki sync --articles`,\n * or null for an agent this node absorbs itself. A copied agent is\n * read-only here: absorb and patch leave it to its home node.\n */\n syncedFrom(agentId: string): SyncedFrom | null {\n const file = resolve(this.agentsDir, agentId, \"_synced.json\")\n if (!existsSync(file)) return null\n try {\n return JSON.parse(readFileSync(file, \"utf-8\")) as SyncedFrom\n } catch (err) {\n // A damaged marker still means the agent lives elsewhere.\n this.log(`synced marker ${file} is not valid JSON: ${(err as Error).message}`)\n return { node: \"unknown\", peerUrl: \"\", at: \"\" }\n }\n }\n\n markSynced(agentId: string, from: SyncedFrom): void {\n const file = resolve(this.agentsDir, agentId, \"_synced.json\")\n mkdirSync(resolve(file, \"..\"), { recursive: true })\n const tmp = `${file}.tmp`\n writeFileSync(tmp, `${JSON.stringify(from, null, 2)}\\n`)\n renameSync(tmp, file)\n }\n\n /** agents/<id>/_absorbed.json — shared by every mode, like the raw entries. */\n private ledgerPath(agentId: string): string {\n return resolve(this.agentsDir, agentId, \"_absorbed.json\")\n }\n\n private readLedger(agentId: string): AbsorbLedger {\n const file = this.ledgerPath(agentId)\n if (!existsSync(file)) return { entries: {} }\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf-8\")) as AbsorbLedger\n return { entries: parsed.entries ?? {} }\n } catch (err) {\n // Treating a damaged ledger as empty would let the next run\n // overwrite it and re-queue everything it recorded.\n throw new Error(`absorb ledger ${file} is not valid JSON: ${(err as Error).message}`)\n }\n }\n}\n\nexport interface SyncedFrom {\n /** The peer's node id. */\n node: string\n peerUrl: string\n /** When the last copy finished. */\n at: string\n}\n\ninterface AbsorbLedger {\n entries: Record<string, { at: string; cited: boolean }>\n}\n\nexport interface AgentWikiSummary {\n agentId: string\n totalEntries: number\n totalArticles: number\n /** Entries an article cites. */\n cited: number\n /** Entries a successful absorb run read and did not cite. */\n readNotCited: number\n /** Entries absorb has not read yet. */\n unabsorbed: number\n articles: Array<{ title: string; path: string; tags?: string[] }>\n}\n"],"mappings":"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","names":["resolve","existsSync","readdirSync","mkdirSync","readFileSync","writeFileSync","renameSync","WikiHub","baseDir","log","mode","WikiStore","agentId","key","agentDir","store","id","p","d","entries","agents","e","dir","entryIds","citedIds","cited","ledger","at","file","tmp","byAgent","list","all","read","pending","articles","article","s","err","from"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{q as d}from"./chunk-
|
|
2
|
-
//# sourceMappingURL=chunk-
|
|
1
|
+
import{q as d}from"./chunk-2SV4RKRW.js";import{b as i,c as u,d as l,e as c}from"./chunk-HKW56YZK.js";import f from"cronstrue";var p=Intl.DateTimeFormat().resolvedOptions().timeZone,m=600,E='Try: "every morning at 9", "weekdays at 6pm", "every 15 minutes", "every monday at 10am", "1st of every month at noon", "daily at 9:30am", "every hour"',g=/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;function w(e){return g.test(e)}function x(e){try{return new Intl.DateTimeFormat("en-US",{timeZone:e}),!0}catch{return!1}}function $(e){return e?e.split(",").map(r=>r.trim().toLowerCase()).filter(r=>r==="log"||r==="notify"||r==="disable"):["log"]}function S(e){let r=[...e.onError??["log"]];e.notify&&!r.includes("notify")&&r.push("notify");let t={enabled:e.enabled??!0,schedule:e.parsed.cron,timezone:e.timezone||p,agent:e.agent,prompt:e.prompt,timeout:e.timeout??m,onError:r};return e.model&&(t.model=e.model),e.notify&&(t.notify=e.notify),e.notify&&e.deliverResult===!1&&(t.deliverResult=!1),e.createdBy&&(t.createdBy=e.createdBy),e.approval&&(t.approval=e.approval),t}function P(e){try{return f.toString(e,{use24HourTimeFormat:!1})}catch{return e}}function T(e,r,t=new Date){try{return d(e,t,r)}catch{return null}}function A(e,r){if(!e)return"unknown (no match within a year)";try{return`${new Intl.DateTimeFormat("en-GB",{timeZone:r,weekday:"short",day:"2-digit",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1}).format(e)} (${r})`}catch{return e.toISOString()}}function h(e){return e?.approval?.action==="create"}async function D(e,r={}){let t="",o=await i(n=>{let a=l(n,`crons.${e}`);if(!a)throw new Error(`cron "${e}" not found`);let s=a.approval;if(!s)throw new Error(`cron "${e}" has no pending request`);s.action==="create"?(delete a.approval,a.enabled=!0,t=`${e} approved and enabled (requested by ${s.requestedBy})`):(c(n,`crons.${e}`),t=`${e} deletion approved; job removed (requested by ${s.requestedBy})`)},{configPath:r.configPath,reload:r.reload});return o.success?{success:!0,message:t,result:o}:{success:!1,message:o.error||"failed",result:o}}async function I(e,r={}){let t="",o=await i(n=>{let a=l(n,`crons.${e}`);if(!a)throw new Error(`cron "${e}" not found`);let s=a.approval;if(!s)throw new Error(`cron "${e}" has no pending request`);s.action==="create"?(c(n,`crons.${e}`),t=`${e} rejected; pending job removed`):(delete a.approval,t=`${e} deletion rejected; job kept`)},{configPath:r.configPath,reload:r.reload});return o.success?{success:!0,message:t,result:o}:{success:!1,message:o.error||"failed",result:o}}async function O(e,r,t={}){return i(o=>{let n=l(o,`crons.${e}`);if(!n)throw new Error(`cron "${e}" not found`);if(r&&h(n))throw new Error(`cron "${e}" is awaiting approval; run \`agentx schedule approve ${e}\``);u(o,`crons.${e}.enabled`,r)},{configPath:t.configPath,reload:t.reload})}export{p as a,E as b,w as c,x as d,$ as e,S as f,P as g,T as h,A as i,h as j,D as k,I as l,O as m};
|
|
2
|
+
//# sourceMappingURL=chunk-ZLC4TSXF.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{b as o}from"./chunk-JXF54PT7.js";import"./chunk-QIJLFPWE.js";var s=o(process.versions.node);s&&(console.error(s),process.exit(1));var{buildProgram:r}=await import("./program-
|
|
2
|
+
import{b as o}from"./chunk-JXF54PT7.js";import"./chunk-QIJLFPWE.js";var s=o(process.versions.node);s&&(console.error(s),process.exit(1));var{buildProgram:r}=await import("./program-MVD57PKP.js"),{installCliSignalExit:i}=await import("./signal-exit-WL7G3EEZ.js");i();var e=await r();process.argv.slice(2).length===0?e.outputHelp():e.parse();
|
|
3
3
|
//# sourceMappingURL=cli.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a,b,c,d,e,f,g}from"./chunk-
|
|
2
|
-
//# sourceMappingURL=client-
|
|
1
|
+
import{a,b,c,d,e,f,g}from"./chunk-D2WX3BET.js";import"./chunk-MRYA4J5F.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";export{b as fetchAgents,d as fetchCrons,c as fetchProcesses,e as killProcess,a as resolveConn,f as sendTask,g as streamTask};
|
|
2
|
+
//# sourceMappingURL=client-VBV7Q43P.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ca as a,da as b,ea as c,fa as d,ga as e,ha as f,ia as g,ja as h,ka as i,la as j,ma as k,na as l,oa as m,pa as n,qa as o,ra as p,sa as q,ua as r}from"./chunk-MRYA4J5F.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";r();export{a as INTEGRATION_KINDS,o as WIKI_CONTRIBUTE_JOB,p as WIKI_CONTRIBUTE_MERGE_JOB,j as approvalsConfigSchema,d as callsSchema,c as cameraBotSchema,k as daemonConfigSchema,b as eventSubscriptionSchema,l as expandEnvVars,m as loadDaemonConfig,h as membersConfigSchema,g as peopleConfigSchema,f as personSchema,i as requestStatusConfigSchema,e as requestsConfigSchema,n as validateWorkspaces,q as withContributionJobs};
|
|
2
|
+
//# sourceMappingURL=config-52C3DJD2.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a,b}from"./chunk-
|
|
2
|
-
//# sourceMappingURL=config-mutate-
|
|
1
|
+
import{a,b}from"./chunk-TPNTFCSQ.js";import"./chunk-MRYA4J5F.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";export{a as mutateAgentxConfig,b as writeAgentxConfig};
|
|
2
|
+
//# sourceMappingURL=config-mutate-DKQESY6F.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a,b,c,d,e}from"./chunk-HKW56YZK.js";import"./chunk-MRYA4J5F.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";export{b as applyConfigMutation,a as findConfigPath,d as getAtPath,c as setAtPath,e as unsetAtPath};
|
|
2
|
+
//# sourceMappingURL=config-mutator-BF4D4QGN.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import{a as ee}from"./chunk-FXBMFGOV.js";import"./chunk-DN3RLR5Z.js";import{f as Q,k as V}from"./chunk-GLQLCBJS.js";import"./chunk-FSW4FUMW.js";import"./chunk-VD7IO653.js";import"./chunk-LDS4SZBU.js";import"./chunk-WPNRDEHW.js";import{c as O}from"./chunk-KA2UIZXG.js";import"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-YWKLUQDC.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import{b as N,c as H}from"./chunk-QOYAX2FT.js";import{b as X}from"./chunk-4VVHGR7H.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-MRYA4J5F.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";import{createHash as le}from"crypto";import{existsSync as z,mkdirSync as ne,readdirSync as re,readFileSync as ge,renameSync as se,writeFileSync as pe}from"fs";import{resolve as w}from"path";var _={maxPatches:30,maxCostUsd:.5,maxItems:60},he=12,fe=2e3,me=1500,M=8,U=300,be=12,B="## Checked facts";function S(n){return w(n,"_contributions")}function E(n,r){if(!z(n))return r;try{return JSON.parse(ge(n,"utf-8"))}catch(t){throw new Error(`${n} is not valid JSON: ${t.message}`)}}function L(n,r){ne(w(n,".."),{recursive:!0});let t=`${n}.${process.pid}.tmp`;pe(t,`${JSON.stringify(r,null,2)}
|
|
2
|
+
`),se(t,n)}function ie(n){return{agents:E(w(S(n),"state.json"),{agents:{}}).agents??{}}}function ye(n){let r=w(S(n),"pending");return z(r)?re(r).filter(t=>t.endsWith(".json")).sort().map(t=>E(w(r,t),null)).filter(t=>!!t):[]}function G(n){return w(S(n),"held.json")}function K(n,r={}){let t=E(G(n),[]);return r.all?t:t.filter(a=>a.status==="held")}function _e(n){let r=w(S(n),"reports");if(!z(r))return null;let t=re(r).filter(a=>a.endsWith(".json")).sort().pop();return t?E(w(r,t),null):null}function ke(n,r,t,a={}){let o=ie(r).agents[t],c=a.now??Date.now(),e=a.since??o?.lastRunAt??new Date(c-864e5).toISOString(),d=e.slice(0,10),u=new Set(o?.processed??[]),s=[];for(let g of n.getAgentEntries(t))g.date<d||u.has(g.id)||s.push({id:g.id,at:g.date,kind:"chat",title:[g.source,g.sourceContext].filter(Boolean).join(" \xB7 "),text:g.content});if(a.db){let g=Date.parse(e);for(let l of V(a.db,{agentId:t,since:Number.isFinite(g)?g:void 0,limit:500})){if(l.status==="in-flight"||u.has(l.taskId))continue;let k=(Q(a.db,l.taskId)?.steps??[]).filter(b=>b.name==="tool_use"||b.action).slice(0,be).map(b=>`- ${b.action??b.name}${b.inputSummary?` ${x(b.inputSummary,160)}`:""}${b.outputSummary?` \u2192 ${x(b.outputSummary,240)}`:""}${b.error?` \u2717 ${x(b.error,120)}`:""}`),y=[`Request: ${x(l.originalMessage??l.messagePreview??"",600)}`,k.length?`Tool calls:
|
|
3
|
+
${k.join(`
|
|
4
|
+
`)}`:"",l.finalResponse?`Reply: ${x(l.finalResponse,800)}`:""].filter(Boolean).join(`
|
|
5
|
+
`);s.push({id:l.taskId,at:new Date(l.startedAt).toISOString(),kind:"task",title:`task ${l.taskId}${l.channel?` \xB7 ${l.channel}`:""}`,text:y})}}return s.sort((g,l)=>g.at.localeCompare(l.at)||g.id.localeCompare(l.id))}function we(n,r,t,a,o){let c=ie(n),e=c.agents[r],d=a.length?a[0].at:new Date(o).toISOString(),u=[...new Set([...e?.processed??[],...t.map(s=>s.id)])].slice(-5e3);c.agents[r]={lastRunAt:d,processed:u},L(w(S(n),"state.json"),c)}async function Me(n,r,t,a){let o={maxPatches:a.maxPatches??_.maxPatches,maxCostUsd:a.maxCostUsd??_.maxCostUsd,maxItems:a.maxItems??_.maxItems},c=a.now??Date.now(),e=ke(n,r,t,{db:a.db,since:a.since,now:c}),d=e.length?$e(n,t):[],u={id:`${new Date(c).toISOString().replace(/[:.]/g,"-")}-${t.replace(/[^\w-]+/g,"_")}`,agentId:t,runAt:new Date(c).toISOString(),model:a.model,workIds:[],patches:[],costUsd:0,calls:0},s=[],g=new Set;for(;s.length<e.length;){if(u.patches.length>=o.maxPatches){u.stoppedBy="max-patches";break}if(u.costUsd>=o.maxCostUsd){u.stoppedBy="max-cost";break}if(s.length>=o.maxItems){u.stoppedBy="max-items";break}let l=e.slice(s.length,s.length+Math.min(he,o.maxItems-s.length)),m=xe(t,l,ve(d,l),o.maxPatches-u.patches.length),k=await a.call(m,Math.max(.01,o.maxCostUsd-u.costUsd));u.calls++,u.costUsd+=k.costUsd??0,s.push(...l);for(let y of Ae(k.text,t,{now:c})){if(u.patches.length>=o.maxPatches)break;g.has(y.id)||(g.add(y.id),u.patches.push(y))}}return u.workIds=s.map(l=>l.id),u.costUsd=Math.round(u.costUsd*1e4)/1e4,a.dryRun||(u.patches.length&&L(w(S(r),"pending",`${u.id}.json`),u),we(r,t,s,e.slice(s.length),c)),u}function $e(n,r){let t=[],a=(o,c)=>{for(let e of o.listArticles(r))e.path.includes("/_versions/")||c?.(e.path)||t.push({title:e.meta.title,aliases:e.meta.aliases??[],type:e.meta.type,lastUpdated:e.meta.lastUpdated,content:e.content})};a(n.getAgentWiki(r));for(let o of n.sharedScope(r))a(o.store,o.skip);return t}function ve(n,r){if(n.length===0)return[];let t=r.map(d=>`${d.title} ${d.text}`).join(`
|
|
6
|
+
`),a=H(t,N(n.map(d=>[d.title,...d.aliases].join(" ")))),o=H(t,N(n.map(d=>`${d.title} ${d.aliases.join(" ")} ${x(d.content,4e3)}`))),c=[],e=Math.ceil(M/2);for(let d of a.slice(0,e))c.push(d.docIndex);for(let d of o){if(c.length>=M)break;c.includes(d.docIndex)||c.push(d.docIndex)}for(let d of a.slice(e)){if(c.length>=M)break;c.includes(d.docIndex)||c.push(d.docIndex)}return c.map(d=>n[d])}function xe(n,r,t,a){let o=r.map(e=>`### ${e.at.slice(0,16)} \xB7 ${e.kind} \xB7 ${e.title}
|
|
7
|
+
${x(e.text,fe)}`).join(`
|
|
8
|
+
|
|
9
|
+
`),c=t.length?t.map(e=>`### ${e.title}${e.type?` [${e.type}]`:""}${e.lastUpdated?` (updated ${e.lastUpdated})`:""}
|
|
10
|
+
${x(e.content,me)}`).join(`
|
|
11
|
+
|
|
12
|
+
`):"(no matching pages)";return`You are agent "${n}". Below is your own work since your last wiki contribution (chat turns, and tasks with the tool calls you ran and what they returned) and the wiki pages it seems to touch. Propose small, sourced patches to the shared wiki from what you actually used or checked.
|
|
13
|
+
|
|
14
|
+
## Your work
|
|
15
|
+
|
|
16
|
+
${o}
|
|
17
|
+
|
|
18
|
+
## Current wiki pages
|
|
19
|
+
|
|
20
|
+
${c}
|
|
21
|
+
|
|
22
|
+
## Patch kinds
|
|
23
|
+
|
|
24
|
+
- "add": a fact you used or checked that the page lacks.
|
|
25
|
+
- "correct": the page states something your work shows is wrong or out of date. Put the exact wrong text from the page in "previous", and the right value in "value".
|
|
26
|
+
- "create": an entity (person, organization, project, invoice, place\u2026) you dealt with that has no page. Give a one-sentence "summary"; add its facts as separate "add" patches on the same page title.
|
|
27
|
+
|
|
28
|
+
## Rules
|
|
29
|
+
|
|
30
|
+
- Only facts your work shows you checked (a tool result, a system you read) or were told by someone who knows. No guesses, no inferences, nothing from general knowledge.
|
|
31
|
+
- Every patch names its "source": the system, command, URL or person (e.g. "invoice list in the billing app", "owner said in chat"). A patch without a source is dropped.
|
|
32
|
+
- "checkedAt" is the date and time of the work that shows the check (ISO). A patch without it is dropped.
|
|
33
|
+
- One fact per patch: an "attribute" ("phone", "role", "billing status", "due date") and its "value", copied exactly.
|
|
34
|
+
- Never rewrite or summarise a page, and never propose removing a fact.
|
|
35
|
+
- Skip facts a page already states with the same value.
|
|
36
|
+
- Put each fact on the page about its subject. If a page above is about the same thing under another name, use that page (with "correct" when it is out of date) instead of creating a new one. Create a page only when none of the pages above is about the subject.
|
|
37
|
+
- State the fact itself, not the story of how you found it.
|
|
38
|
+
- Do not record facts about the wiki, AgentX, this contribution run or your own tools, unless that is your job.
|
|
39
|
+
- Skip anything you could not verify. "Not checked" or "unknown" is not a fact.
|
|
40
|
+
- At most ${a} patches. Return [] when there is nothing worth adding.
|
|
41
|
+
|
|
42
|
+
Return ONLY a JSON array, no prose, no code fences:
|
|
43
|
+
|
|
44
|
+
[
|
|
45
|
+
{"kind": "add", "page": "Exact Page Title", "attribute": "phone", "value": "+1 555 0100", "source": "contacts app", "checkedAt": "2026-01-31T10:00:00Z"},
|
|
46
|
+
{"kind": "correct", "page": "Exact Page Title", "attribute": "billing status", "previous": "overdue", "value": "paid", "source": "invoice list", "checkedAt": "2026-01-31T10:00:00Z"},
|
|
47
|
+
{"kind": "create", "page": "New Entity Name", "pageType": "person", "summary": "One sentence.", "source": "chat with the owner", "checkedAt": "2026-01-31T10:00:00Z"}
|
|
48
|
+
]`}function Ae(n,r,t={}){let a=n.match(/\[[\s\S]*\]/);if(!a)return[];let o;try{o=JSON.parse(a[0])}catch{return[]}if(!Array.isArray(o))return[];let c=t.now??Date.now(),e=[];for(let d of o){if(!d||typeof d!="object")continue;let u=d,s=u.kind;if(s!=="add"&&s!=="correct"&&s!=="create"&&s!=="remove")continue;let g=I(u.page,120),l=I(u.source,U),m=l.replace(/[\s,;(–—-]*\bchecked\b[^;]*$/i,"").replace(/[\s,;(]+$/,"")||l,k=typeof u.checkedAt=="string"?Date.parse(u.checkedAt):NaN;if(!g||!m||!Number.isFinite(k))continue;let y=I(u.attribute,60),b=I(u.value,U),v=I(u.previous,U),A=I(u.summary,U);if((s==="add"||s==="correct")&&(!y||!b)||s==="remove"&&!y&&!v||s==="create"&&!A)continue;let C=Array.isArray(u.aliases)?u.aliases.map(p=>I(p,120)).filter(Boolean).slice(0,10):[],P=new Date(Math.min(k,c)).toISOString(),i={kind:s,page:g,attribute:y,value:b,previous:v,summary:A,source:m,checkedAt:P,agentId:r};e.push({id:le("sha1").update(JSON.stringify(i)).digest("hex").slice(0,12),kind:s,page:g,source:m,checkedAt:P,agentId:r,...y?{attribute:y}:{},...b?{value:b}:{},...v&&s!=="add"&&s!=="create"?{previous:v}:{},...A&&s==="create"?{summary:A}:{},...s==="create"&&X(u.pageType)?{pageType:u.pageType}:{},...s==="create"&&C.length?{aliases:C}:{}})}return e}function I(n,r){return typeof n=="string"?n.replace(/\s+/g," ").trim().slice(0,r):""}function x(n,r){return n.length>r?`${n.slice(0,r)}\u2026`:n}function W(n){return(n||"").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").trim()}function oe(n){let r=new Map;for(let t of n.listAgents()){if(n.syncedFrom(t))continue;let a=n.getAgentWiki(t);for(let o of a.listAllArticles()){if(o.path.includes("/_versions/"))continue;let c=new Set([o.meta.title,...o.meta.aliases??[]].map(W).filter(Boolean));for(let e of c){let d=r.get(e)??[];d.push({agentId:t,store:a,path:o.path,article:o}),r.set(e,d)}}}return r}function Be(n,r,t={}){let a=t.now??Date.now(),o=new Date(a).toISOString(),c=o.slice(0,10),e=ye(r),d=e.flatMap(i=>i.patches).sort((i,p)=>i.checkedAt.localeCompare(p.checkedAt)),u={at:o,batches:e.map(i=>i.id),agents:[...new Set(e.map(i=>i.agentId))].sort(),patches:d.length,applied:[],pagesUpdated:[],pagesCreated:[],contradictions:[],held:[],duplicates:[],...t.dryRun?{dryRun:!0}:{}},s=[],g=(i,p,h)=>{let f=`h-${i.id}`;s.push({id:f,patch:i,reason:p,heldAt:o,status:"held",...h?.length?{lost:h}:{}}),u.held.push({id:f,page:i.page,attribute:i.attribute,by:i.agentId,reason:p,...h?.length?{lost:h}:{}})},l=oe(n);for(let[,i]of l){let p=[...new Map(i.map(f=>[`${f.agentId}:${f.path}`,f])).values()],h=p[0]?.article.meta.title;p.length>1&&h&&!u.duplicates.some(f=>f.title===h)&&u.duplicates.push({title:h,pages:p.map(f=>`${f.agentId}/${f.path}`)})}let m=new Map;for(let i of d){if(i.kind!=="create")continue;let p=W(i.page);if(l.has(p))continue;let h=m.get(p)??{title:i.page,owner:i.agentId,summaries:[],sources:[],aliases:[],at:i.checkedAt};h.type??=i.pageType,i.summary&&!h.summaries.includes(i.summary)&&h.summaries.push(i.summary),h.sources.includes(i.source)||h.sources.push(i.source);for(let f of i.aliases??[])h.aliases.includes(f)||h.aliases.push(f);m.set(p,h)}for(let i of d){let p=W(i.page);(i.kind==="add"||i.kind==="correct")&&!l.has(p)&&!m.has(p)&&m.set(p,{title:i.page,owner:i.agentId,summaries:[],sources:[i.source],aliases:[],at:i.checkedAt})}let k=[...l.values()].map(i=>i[0]),y=new Map;for(let[i,p]of m){let h=Se(p.title,p.type,k.map(f=>({title:f.article.meta.title,type:f.article.meta.type,ref:`${f.agentId}/${f.path}`})));h&&y.set(i,h)}for(let i of y.keys())m.delete(i);let b=new O(r),v=new Map,A=new Map,C=i=>{let p=l.get(i)?.[0];if(!p)return`new:${i}`;let h=`page:${p.agentId}:${p.path}`;return A.set(h,p),h};for(let i of d){let p=W(i.page),h=y.get(p);if(h&&i.kind!=="remove"){g(i,`possible duplicate of ${h}`);continue}if(i.kind==="create")continue;if(i.kind==="remove"){g(i,"removes a fact");continue}let f=l.get(p)?.[0];if(f&&!f.store.canRead(f.article.meta,i.agentId)){g(i,"the contributing agent cannot read this page");continue}let $=f?.article.meta.title??m.get(p).title,j="planned",R=i.value;if(!t.dryRun){let T=b.write({subject:$,attribute:i.attribute,value:R,source:i.source,verifiedBy:i.agentId,verifiedAt:i.checkedAt},{now:a});if(j=T.status,T.status==="contradiction"){u.contradictions.push({page:$,attribute:i.attribute,value:R,by:i.agentId,questionId:T.questionId});continue}if(T.status==="unchanged")continue;R=T.fact.value}u.applied.push({page:$,attribute:i.attribute,value:R,by:i.agentId,status:j});let Y=v.get(C(p))??[],Z=i.kind==="correct"?i.previous:void 0;Y.push({line:{attribute:i.attribute,value:R,source:i.source,checkedAt:i.checkedAt,by:i.agentId,previous:Z},previous:Z,patch:i}),v.set(C(p),Y)}let P=new Set;for(let[i,p]of v){let h=A.get(i);if(!h)continue;let f=D(h,p,{guard:!0,today:c,dryRun:t.dryRun});if(f.lost)for(let $ of p)g($.patch,"the change would lose facts the page has",f.lost);else if(f.denied)for(let $ of p)g($.patch,`write denied for ${h.agentId}/${h.path}`);else f.changed&&(u.pagesUpdated.push(`${h.agentId}/${h.path}`),t.dryRun||P.add(h.store))}for(let[i,p]of m){let h=v.get(`new:${i}`)??[];if(!p.summaries.length&&!h.length)continue;let f=n.getAgentWiki(p.owner),$=de(f,p.title,p.type);u.pagesCreated.push(`${p.owner}/${$}`),!t.dryRun&&ae(f,$,p,h.map(j=>j.line),c)&&P.add(f)}if(!t.dryRun){for(let p of P)try{p.rebuildIndex()}catch(h){t.log?.(`index rebuild failed: ${h.message}`)}let i=S(r);if(s.length){let p=K(r,{all:!0});L(G(r),[...p,...s.filter(h=>!p.some(f=>f.id===h.id))])}ne(w(i,"merged"),{recursive:!0});for(let p of e)se(w(i,"pending",`${p.id}.json`),w(i,"merged",`${p.id}.json`));L(w(i,"reports",`${o.replace(/[:.]/g,"-")}.json`),u)}return u}function ae(n,r,t,a,o){let c=t.summaries.length?t.summaries.join(" "):`${t.title}.`,{body:e}=ue(`${c}
|
|
49
|
+
|
|
50
|
+
_Sources: ${t.sources.join("; ")}._`,a);return n.writeArticle(r,{title:t.title,...t.type?{type:t.type}:{},...t.aliases.length?{aliases:t.aliases}:{},tags:[],owner:t.owner,access:"public",created:o,lastUpdated:o,sources:[J(t.owner,t.at),...a.map(d=>J(d.by,d.checkedAt))].filter((d,u,s)=>s.indexOf(d)===u)},e,t.owner)}var Ie=new Set(["the","and","for","with","von","des","les","der","die","das","une","pour","page","of","de","la","le","du","et"]);function te(n){return new Set((n.toLowerCase().match(/[\p{L}\p{N}]+/gu)??[]).filter(r=>(r.length>2||/\d/.test(r))&&!Ie.has(r)))}function Se(n,r,t){let a=te(n);if(a.size<2)return;let o;for(let c of t){if(r&&c.type&&r==="person"!=(c.type==="person"))continue;let e=te(c.title);if(e.size<2)continue;let d=m=>[...m].filter(k=>/\d/.test(k)),[u,s]=[d(a),d(e)];if(u.length&&s.length&&!u.some(m=>s.includes(m)))continue;let g=0;for(let m of a)e.has(m)&&g++;let l=g/Math.min(a.size,e.size);g>=2&&l>=.75&&(!o||l>o.score)&&(o={ref:c.ref,title:c.title,score:l})}return o?`"${o.title}" (${o.ref})`:void 0}function D(n,r,t){let a=n.article.content,{body:o,superseded:c}=ue(a,r.map(s=>s.line));for(let s of r){if(!s.previous||s.previous===s.line.value)continue;let g=ce(o,s.previous,s.line.value);g!==o&&(o=g,c.push(s.previous))}if(t.remove&&(o=Pe(o,t.remove)),o===a)return{changed:!1};if(t.guard){let s=ee(a,o,c);if(s.length)return{changed:!1,lost:s}}if(t.dryRun)return{changed:!0};let e=n.article.meta,d=r.map(s=>J(s.line.by,s.line.checkedAt));return n.store.writeArticle(n.path,{...e,lastUpdated:t.today,sources:[...e.sources,...d].filter((s,g,l)=>l.indexOf(s)===g)},o,e.owner)?{changed:!0}:{changed:!1,denied:!0}}function ce(n,r,t){if(!r)return n;let a=n.indexOf(B),o=a===-1?n:n.slice(0,a),c=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),e=[...o.matchAll(new RegExp(`(?<![\\p{L}\\p{N}])${c}(?![\\p{L}\\p{N}])`,"gu"))];if(e.length!==1)return n;let d=e[0].index;return n.slice(0,d)+t+n.slice(d+r.length)}function Pe(n,r){let t=n;if(r.attribute){let a=r.attribute.toLowerCase();t=t.split(`
|
|
51
|
+
`).filter(o=>o.match(q)?.[1].toLowerCase()!==a).join(`
|
|
52
|
+
`)}return r.text&&(t=ce(t,r.text,"")),t}function De(n,r,t,a={}){let o=K(r,{all:!0}),c=o.find(l=>l.id===t);if(!c)return{ok:!1,error:`no held patch "${t}"`};if(c.status!=="held")return{ok:!1,error:`"${t}" is already ${c.status}`};let e=c.patch,d=a.now??Date.now(),u=new Date(d).toISOString().slice(0,10),s=oe(n).get(W(e.page))?.[0];if(!s){if(e.kind==="remove")return{ok:!1,error:`no page "${e.page}" (it may have been renamed)`};let l=[];if(e.attribute&&e.value){let b=new O(r).write({subject:e.page,attribute:e.attribute,value:e.value,source:e.source,verifiedBy:e.agentId,verifiedAt:e.checkedAt},{now:d});if(b.status==="contradiction")return{ok:!1,error:`the wiki has a newer check of ${e.attribute}; answer question ${b.questionId??"(see wiki questions)"} instead`};l.push({attribute:e.attribute,value:b.fact.value,source:e.source,checkedAt:e.checkedAt,by:e.agentId})}let m=n.getAgentWiki(e.agentId),k=de(m,e.page,e.pageType),y={title:e.page,type:e.pageType,owner:e.agentId,summaries:e.summary?[e.summary]:[],sources:[e.source],aliases:e.aliases??[],at:e.checkedAt};if(!ae(m,k,y,l,u))return{ok:!1,error:`write denied for ${e.agentId}/${k}`};try{m.rebuildIndex()}catch{}return F(r,o,c,"approved",a.by,d,`${e.agentId}/${k}`)}let g;if(e.kind==="remove")g=D(s,[],{guard:!1,today:u,remove:{attribute:e.attribute,text:e.previous}});else{if(!e.attribute||!e.value)return{ok:!1,error:`"${t}" carries no fact to apply`};let l=new O(r).write({subject:s.article.meta.title,attribute:e.attribute,value:e.value,source:e.source,verifiedBy:e.agentId,verifiedAt:e.checkedAt},{now:d});if(l.status==="contradiction")return{ok:!1,error:`the wiki has a newer check of ${e.attribute}; answer question ${l.questionId??"(see wiki questions)"} instead`};let m=e.kind==="correct"?e.previous:void 0;g=D(s,[{line:{attribute:e.attribute,value:l.fact.value,source:e.source,checkedAt:e.checkedAt,by:e.agentId,previous:m},previous:m,patch:e}],{guard:!1,today:u})}if(g.denied)return{ok:!1,error:`write denied for ${s.agentId}/${s.path}`};if(g.changed)try{s.store.rebuildIndex()}catch{}return F(r,o,c,"approved",a.by,d,`${s.agentId}/${s.path}`)}function Fe(n,r,t={}){let a=K(n,{all:!0}),o=a.find(c=>c.id===r);return o?o.status!=="held"?{ok:!1,error:`"${r}" is already ${o.status}`}:F(n,a,o,"rejected",t.by,t.now??Date.now()):{ok:!1,error:`no held patch "${r}"`}}function F(n,r,t,a,o,c,e){let d={...t,status:a,decidedBy:o??"operator",decidedAt:new Date(c).toISOString()};return L(G(n),r.map(u=>u.id===t.id?d:u)),{ok:!0,held:d,...e?{page:e}:{}}}var q=/^- \*\*(.+?):\*\* /;function ue(n,r){if(r.length===0)return{body:n,superseded:[]};let t=n.replace(/\s+$/,"").split(`
|
|
53
|
+
`),a=t.findIndex(s=>s.trim()===B),o=t,c=[],e=[];if(a!==-1){o=t.slice(0,a);let s=t.slice(a+1),g=s.findIndex(l=>/^#{1,2} /.test(l));c=(g===-1?s:s.slice(0,g)).filter(l=>l.trim()),e=g===-1?[]:s.slice(g)}let d=[];for(let s of r){let g=c.findIndex(b=>b.match(q)?.[1].toLowerCase()===s.attribute.toLowerCase()),l=g===-1?void 0:Re(c[g]);g!==-1&&d.push(c[g]);let m=l&&l.value===s.value?l.previous:l?`${l.value}, checked ${l.checkedAt}`:s.previous,k=c[g]?.match(q)?.[1]??s.attribute,y=Ce({...s,attribute:k,previous:m});g===-1?c.push(y):c[g]=y}let u=[...o.some(s=>s.trim())?[...o,""]:[],B,"",...c];return e.length&&u.push("",...e),{body:u.join(`
|
|
54
|
+
`).replace(/\n{3,}/g,`
|
|
55
|
+
|
|
56
|
+
`).trim(),superseded:d}}function Ce(n){let r=n.previous?` (previously: ${n.previous})`:"";return`- **${n.attribute}:** ${n.value} \u2014 ${n.source}; checked ${n.checkedAt.slice(0,10)} by ${n.by}${r}`}function Re(n){let r=n.match(/^- \*\*.+?:\*\* (.*?) — .*?; checked (\S+) by \S+(?: \(previously: (.*)\))?$/);return r?{value:r[1],checkedAt:r[2],...r[3]?{previous:r[3]}:{}}:void 0}function J(n,r){return`contribution:${n}@${r.slice(0,10)}`}var Te={person:"people",project:"projects",place:"places",concept:"concepts",event:"events",decision:"decisions",pattern:"patterns"};function de(n,r,t){let a=r.toLowerCase().replace(/[^\p{L}\p{N}]+/gu,"-").replace(/^-+|-+$/g,"").slice(0,60)||"page",o=t?Te[t]:"contributions",c=`${o}/${a}.md`;for(let e=2;n.readArticle(c);e++)c=`${o}/${a}-${e}.md`;return c}export{_ as DEFAULT_CONTRIBUTION_LIMITS,B as FACTS_HEADING,ue as applyFactLines,De as approveHeld,xe as buildContributionPrompt,S as contributionsDir,_e as latestReport,K as listHeld,ye as listPendingBatches,Be as mergeContributions,W as pageKey,Ae as parseContributionPatches,ke as pendingWork,Se as possibleDuplicate,Fe as rejectHeld,ce as replaceOnce,Me as runContribution};
|
|
57
|
+
//# sourceMappingURL=contributions-5OEZWYXI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/wiki/contributions.ts"],"sourcesContent":["import { createHash } from \"crypto\"\nimport { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from \"fs\"\nimport { resolve } from \"path\"\nimport type Database from \"better-sqlite3\"\nimport { buildIndex, scoreAll } from \"@/memory/bm25\"\nimport { getTrace, listTraces } from \"@/storage/traces\"\nimport { FactLedger } from \"./facts/ledger\"\nimport { lostStructuredFacts } from \"./fact-guard\"\nimport type { WikiHub } from \"./hub\"\nimport type { WikiStore } from \"./store\"\nimport { isWikiArticleType, type WikiArticle, type WikiArticleType } from \"./types\"\n\n// --- Daily per-agent wiki contributions (#824) ---\n//\n// Only the central absorb wrote the wiki, and it missed what agents learn\n// while working: a fleet test found money and status facts weeks stale\n// although the owning agent had checked the current values that day.\n//\n// So each opted-in agent reviews its own work once a day (its chat turns\n// and its task traces, with the tool calls it ran) and proposes small,\n// sourced patches:\n//\n// add one fact line for a page\n// correct the page states an old value; give the exact old text and\n// the new value\n// create a short page for an entity that has none\n//\n// Every patch needs a source and a check date; one without is dropped.\n// There is no field for a page body, so an agent cannot rewrite a page:\n// rewrites are what lost facts in the test.\n//\n// One merge a day applies them all. Facts go through the fact ledger\n// (facts/ledger.ts), so the newest check wins and the older value stays\n// in the fact's history; pages keep every earlier body in `_versions/`.\n// A patch that removes a fact, or an edit that would lose a phone number,\n// email, role, contact marker, link or number, is held for a person.\n//\n// Storage, all skipped by the article index (`_` prefix):\n// _contributions/state.json per-agent cursor\n// _contributions/pending/<run>.json one batch per agent run\n// _contributions/merged/<run>.json batches a merge consumed\n// _contributions/reports/<time>.json what each merge did\n// _contributions/held.json patches waiting for a person\n\nexport type ContributionKind = \"add\" | \"correct\" | \"create\" | \"remove\"\n\nexport interface ContributionPatch {\n /** Stable for the same agent, page, attribute, value and check. */\n id: string\n kind: ContributionKind\n /** Title of the page the patch is about. */\n page: string\n /** For `create`: the article type. */\n pageType?: WikiArticleType\n /** For `create`: other names the subject goes by. */\n aliases?: string[]\n /** \"phone\", \"billing status\", \"main contact\"… */\n attribute?: string\n value?: string\n /** For `correct` and `remove`: the exact text on the page that is wrong. */\n previous?: string\n /** For `create`: one sentence saying what the entity is. */\n summary?: string\n /** Where the agent checked it: a system, command, URL or \"owner said\". */\n source: string\n /** When it was checked (ISO). */\n checkedAt: string\n agentId: string\n}\n\nexport interface ContributionBatch {\n id: string\n agentId: string\n runAt: string\n model: string\n /** Chat entries and task traces the run read. */\n workIds: string[]\n patches: ContributionPatch[]\n costUsd: number\n calls: number\n /** Why the run stopped before reading all of the agent's new work. */\n stoppedBy?: \"max-patches\" | \"max-cost\" | \"max-items\"\n}\n\nexport interface ContributionLimits {\n /** Patches one run may submit. */\n maxPatches: number\n /** Model spend one run may reach, in USD. Each call is capped at what\n * is left, and no call starts once it is spent. */\n maxCostUsd: number\n /** Chat entries and task traces one run reads. */\n maxItems: number\n}\n\nexport const DEFAULT_CONTRIBUTION_LIMITS: ContributionLimits = { maxPatches: 30, maxCostUsd: 0.5, maxItems: 60 }\n\n/** Work items sent to the model per call. */\nconst ITEMS_PER_CALL = 12\nconst ITEM_CHARS = 2000\nconst PAGE_CHARS = 1500\nconst PAGES_PER_CALL = 8\nconst FIELD_CHARS = 300\nconst STEPS_PER_TRACE = 12\nexport const FACTS_HEADING = \"## Checked facts\"\n\n// --- Storage -----------------------------------------------------------------\n\nexport function contributionsDir(wikiDir: string): string {\n return resolve(wikiDir, \"_contributions\")\n}\n\ninterface ContributionState {\n agents: Record<string, { lastRunAt: string; processed: string[] }>\n}\n\nfunction readJson<T>(file: string, fallback: T): T {\n if (!existsSync(file)) return fallback\n try {\n return JSON.parse(readFileSync(file, \"utf-8\")) as T\n } catch (err) {\n // A damaged file read as empty would be overwritten on the next save.\n throw new Error(`${file} is not valid JSON: ${(err as Error).message}`)\n }\n}\n\nfunction writeJson(file: string, data: unknown): void {\n mkdirSync(resolve(file, \"..\"), { recursive: true })\n const tmp = `${file}.${process.pid}.tmp`\n writeFileSync(tmp, `${JSON.stringify(data, null, 2)}\\n`)\n renameSync(tmp, file)\n}\n\nfunction readState(wikiDir: string): ContributionState {\n const s = readJson<ContributionState>(resolve(contributionsDir(wikiDir), \"state.json\"), { agents: {} })\n return { agents: s.agents ?? {} }\n}\n\nexport function listPendingBatches(wikiDir: string): ContributionBatch[] {\n const dir = resolve(contributionsDir(wikiDir), \"pending\")\n if (!existsSync(dir)) return []\n return readdirSync(dir).filter((f) => f.endsWith(\".json\")).sort()\n .map((f) => readJson<ContributionBatch | null>(resolve(dir, f), null))\n .filter((b): b is ContributionBatch => !!b)\n}\n\nexport interface HeldPatch {\n id: string\n patch: ContributionPatch\n reason: string\n /** Facts the change would have lost. */\n lost?: string[]\n heldAt: string\n status: \"held\" | \"approved\" | \"rejected\"\n decidedBy?: string\n decidedAt?: string\n}\n\nfunction heldFile(wikiDir: string): string {\n return resolve(contributionsDir(wikiDir), \"held.json\")\n}\n\n/** Held patches; only those still waiting unless `all`. */\nexport function listHeld(wikiDir: string, opts: { all?: boolean } = {}): HeldPatch[] {\n const list = readJson<HeldPatch[]>(heldFile(wikiDir), [])\n return opts.all ? list : list.filter((h) => h.status === \"held\")\n}\n\nexport function latestReport(wikiDir: string): MergeReport | null {\n const dir = resolve(contributionsDir(wikiDir), \"reports\")\n if (!existsSync(dir)) return null\n const last = readdirSync(dir).filter((f) => f.endsWith(\".json\")).sort().pop()\n return last ? readJson<MergeReport | null>(resolve(dir, last), null) : null\n}\n\n// --- What a run reads --------------------------------------------------------\n\n/** One piece of the agent's work: a chat turn or a task it ran. */\nexport interface WorkItem {\n id: string\n /** ISO time (or date) the work happened. */\n at: string\n kind: \"chat\" | \"task\"\n title: string\n text: string\n}\n\n/**\n * The agent's work since its last run, oldest first: its chat entries\n * from the wiki's raw pool and, given the trace database, the tasks it ran\n * with their tool calls and results. On a first run `since` (default:\n * the day before `now`) bounds the window.\n */\nexport function pendingWork(\n hub: WikiHub, wikiDir: string, agentId: string,\n opts: { db?: Database.Database; since?: string; now?: number } = {},\n): WorkItem[] {\n const state = readState(wikiDir).agents[agentId]\n const now = opts.now ?? Date.now()\n const since = opts.since ?? state?.lastRunAt ?? new Date(now - 86_400_000).toISOString()\n const sinceDay = since.slice(0, 10)\n const done = new Set(state?.processed ?? [])\n const items: WorkItem[] = []\n\n for (const e of hub.getAgentEntries(agentId)) {\n if (e.date < sinceDay || done.has(e.id)) continue\n items.push({ id: e.id, at: e.date, kind: \"chat\", title: [e.source, e.sourceContext].filter(Boolean).join(\" · \"), text: e.content })\n }\n\n if (opts.db) {\n const sinceMs = Date.parse(since)\n for (const t of listTraces(opts.db, { agentId, since: Number.isFinite(sinceMs) ? sinceMs : undefined, limit: 500 })) {\n if (t.status === \"in-flight\" || done.has(t.taskId)) continue\n const steps = getTrace(opts.db, t.taskId)?.steps ?? []\n const tools = steps\n .filter((s) => s.name === \"tool_use\" || s.action)\n .slice(0, STEPS_PER_TRACE)\n .map((s) => `- ${s.action ?? s.name}${s.inputSummary ? ` ${clip(s.inputSummary, 160)}` : \"\"}${s.outputSummary ? ` → ${clip(s.outputSummary, 240)}` : \"\"}${s.error ? ` ✗ ${clip(s.error, 120)}` : \"\"}`)\n const text = [\n `Request: ${clip(t.originalMessage ?? t.messagePreview ?? \"\", 600)}`,\n tools.length ? `Tool calls:\\n${tools.join(\"\\n\")}` : \"\",\n t.finalResponse ? `Reply: ${clip(t.finalResponse, 800)}` : \"\",\n ].filter(Boolean).join(\"\\n\")\n items.push({ id: t.taskId, at: new Date(t.startedAt).toISOString(), kind: \"task\", title: `task ${t.taskId}${t.channel ? ` · ${t.channel}` : \"\"}`, text })\n }\n }\n return items.sort((a, b) => a.at.localeCompare(b.at) || a.id.localeCompare(b.id))\n}\n\nfunction saveCursor(wikiDir: string, agentId: string, read: WorkItem[], unread: WorkItem[], now: number): void {\n const state = readState(wikiDir)\n const prev = state.agents[agentId]\n // The cursor stays on the oldest item not read yet, so a run cut short\n // by a cap picks up there tomorrow; ids read at or after it are skipped.\n const lastRunAt = unread.length ? unread[0].at : new Date(now).toISOString()\n const processed = [...new Set([...(prev?.processed ?? []), ...read.map((w) => w.id)])].slice(-5000)\n state.agents[agentId] = { lastRunAt, processed }\n writeJson(resolve(contributionsDir(wikiDir), \"state.json\"), state)\n}\n\n// --- The run -----------------------------------------------------------------\n\n/** One model call: the reply text and what it cost. `maxCostUsd` is what\n * is left of the run's cap; the call must not spend more. */\nexport type ContributionCall = (prompt: string, maxCostUsd: number) => Promise<{ text: string; costUsd?: number }>\n\nexport interface ContributeOptions extends Partial<ContributionLimits> {\n model: string\n call: ContributionCall\n db?: Database.Database\n since?: string\n now?: number\n /** Compute the batch without saving it or moving the cursor. */\n dryRun?: boolean\n}\n\n/**\n * Review an agent's work since its last run and queue sourced patches\n * for the daily merge. Stops at the patch cap, the cost cap or the item\n * cap, whichever comes first.\n */\nexport async function runContribution(hub: WikiHub, wikiDir: string, agentId: string, opts: ContributeOptions): Promise<ContributionBatch> {\n const limits: ContributionLimits = {\n maxPatches: opts.maxPatches ?? DEFAULT_CONTRIBUTION_LIMITS.maxPatches,\n maxCostUsd: opts.maxCostUsd ?? DEFAULT_CONTRIBUTION_LIMITS.maxCostUsd,\n maxItems: opts.maxItems ?? DEFAULT_CONTRIBUTION_LIMITS.maxItems,\n }\n const now = opts.now ?? Date.now()\n const all = pendingWork(hub, wikiDir, agentId, { db: opts.db, since: opts.since, now })\n const pages = all.length ? readablePages(hub, agentId) : []\n const batch: ContributionBatch = {\n id: `${new Date(now).toISOString().replace(/[:.]/g, \"-\")}-${agentId.replace(/[^\\w-]+/g, \"_\")}`,\n agentId, runAt: new Date(now).toISOString(), model: opts.model,\n workIds: [], patches: [], costUsd: 0, calls: 0,\n }\n\n const read: WorkItem[] = []\n const seen = new Set<string>()\n while (read.length < all.length) {\n if (batch.patches.length >= limits.maxPatches) { batch.stoppedBy = \"max-patches\"; break }\n if (batch.costUsd >= limits.maxCostUsd) { batch.stoppedBy = \"max-cost\"; break }\n if (read.length >= limits.maxItems) { batch.stoppedBy = \"max-items\"; break }\n const chunk = all.slice(read.length, read.length + Math.min(ITEMS_PER_CALL, limits.maxItems - read.length))\n const prompt = buildContributionPrompt(agentId, chunk, relevantPages(pages, chunk), limits.maxPatches - batch.patches.length)\n const reply = await opts.call(prompt, Math.max(0.01, limits.maxCostUsd - batch.costUsd))\n batch.calls++\n batch.costUsd += reply.costUsd ?? 0\n read.push(...chunk)\n for (const p of parseContributionPatches(reply.text, agentId, { now })) {\n if (batch.patches.length >= limits.maxPatches) break\n if (seen.has(p.id)) continue\n seen.add(p.id)\n batch.patches.push(p)\n }\n }\n batch.workIds = read.map((w) => w.id)\n batch.costUsd = Math.round(batch.costUsd * 10_000) / 10_000\n\n if (!opts.dryRun) {\n if (batch.patches.length) writeJson(resolve(contributionsDir(wikiDir), \"pending\", `${batch.id}.json`), batch)\n saveCursor(wikiDir, agentId, read, all.slice(read.length), now)\n }\n return batch\n}\n\ninterface PageRef {\n title: string\n aliases: string[]\n type?: WikiArticleType\n lastUpdated?: string\n content: string\n}\n\n/** Every page the agent may read: its own, then the shared wiki's. */\nfunction readablePages(hub: WikiHub, agentId: string): PageRef[] {\n const out: PageRef[] = []\n const add = (store: WikiStore, skip?: (p: string) => boolean) => {\n for (const a of store.listArticles(agentId)) {\n if (a.path.includes(\"/_versions/\") || skip?.(a.path)) continue\n out.push({ title: a.meta.title, aliases: a.meta.aliases ?? [], type: a.meta.type, lastUpdated: a.meta.lastUpdated, content: a.content })\n }\n }\n add(hub.getAgentWiki(agentId))\n for (const s of hub.sharedScope(agentId)) add(s.store, s.skip)\n return out\n}\n\n/**\n * Pages the work most likely touches: half by title and alias, half by\n * body. Titles alone missed a stale page whose title was worded\n * differently from the work, and the model created a duplicate instead\n * of correcting it (#824 review).\n */\nfunction relevantPages(pages: PageRef[], items: WorkItem[]): PageRef[] {\n if (pages.length === 0) return []\n const text = items.map((w) => `${w.title} ${w.text}`).join(\"\\n\")\n const byTitle = scoreAll(text, buildIndex(pages.map((p) => [p.title, ...p.aliases].join(\" \"))))\n const byBody = scoreAll(text, buildIndex(pages.map((p) => `${p.title} ${p.aliases.join(\" \")} ${clip(p.content, 4000)}`)))\n const picked: number[] = []\n const half = Math.ceil(PAGES_PER_CALL / 2)\n for (const r of byTitle.slice(0, half)) picked.push(r.docIndex)\n for (const r of byBody) {\n if (picked.length >= PAGES_PER_CALL) break\n if (!picked.includes(r.docIndex)) picked.push(r.docIndex)\n }\n for (const r of byTitle.slice(half)) {\n if (picked.length >= PAGES_PER_CALL) break\n if (!picked.includes(r.docIndex)) picked.push(r.docIndex)\n }\n return picked.map((i) => pages[i])\n}\n\nexport function buildContributionPrompt(agentId: string, items: WorkItem[], pages: PageRef[], maxPatches: number): string {\n const work = items.map((w) => `### ${w.at.slice(0, 16)} · ${w.kind} · ${w.title}\\n${clip(w.text, ITEM_CHARS)}`).join(\"\\n\\n\")\n const wiki = pages.length\n ? pages.map((p) => `### ${p.title}${p.type ? ` [${p.type}]` : \"\"}${p.lastUpdated ? ` (updated ${p.lastUpdated})` : \"\"}\\n${clip(p.content, PAGE_CHARS)}`).join(\"\\n\\n\")\n : \"(no matching pages)\"\n return `You are agent \"${agentId}\". Below is your own work since your last wiki contribution (chat turns, and tasks with the tool calls you ran and what they returned) and the wiki pages it seems to touch. Propose small, sourced patches to the shared wiki from what you actually used or checked.\n\n## Your work\n\n${work}\n\n## Current wiki pages\n\n${wiki}\n\n## Patch kinds\n\n- \"add\": a fact you used or checked that the page lacks.\n- \"correct\": the page states something your work shows is wrong or out of date. Put the exact wrong text from the page in \"previous\", and the right value in \"value\".\n- \"create\": an entity (person, organization, project, invoice, place…) you dealt with that has no page. Give a one-sentence \"summary\"; add its facts as separate \"add\" patches on the same page title.\n\n## Rules\n\n- Only facts your work shows you checked (a tool result, a system you read) or were told by someone who knows. No guesses, no inferences, nothing from general knowledge.\n- Every patch names its \"source\": the system, command, URL or person (e.g. \"invoice list in the billing app\", \"owner said in chat\"). A patch without a source is dropped.\n- \"checkedAt\" is the date and time of the work that shows the check (ISO). A patch without it is dropped.\n- One fact per patch: an \"attribute\" (\"phone\", \"role\", \"billing status\", \"due date\") and its \"value\", copied exactly.\n- Never rewrite or summarise a page, and never propose removing a fact.\n- Skip facts a page already states with the same value.\n- Put each fact on the page about its subject. If a page above is about the same thing under another name, use that page (with \"correct\" when it is out of date) instead of creating a new one. Create a page only when none of the pages above is about the subject.\n- State the fact itself, not the story of how you found it.\n- Do not record facts about the wiki, AgentX, this contribution run or your own tools, unless that is your job.\n- Skip anything you could not verify. \"Not checked\" or \"unknown\" is not a fact.\n- At most ${maxPatches} patches. Return [] when there is nothing worth adding.\n\nReturn ONLY a JSON array, no prose, no code fences:\n\n[\n {\"kind\": \"add\", \"page\": \"Exact Page Title\", \"attribute\": \"phone\", \"value\": \"+1 555 0100\", \"source\": \"contacts app\", \"checkedAt\": \"2026-01-31T10:00:00Z\"},\n {\"kind\": \"correct\", \"page\": \"Exact Page Title\", \"attribute\": \"billing status\", \"previous\": \"overdue\", \"value\": \"paid\", \"source\": \"invoice list\", \"checkedAt\": \"2026-01-31T10:00:00Z\"},\n {\"kind\": \"create\", \"page\": \"New Entity Name\", \"pageType\": \"person\", \"summary\": \"One sentence.\", \"source\": \"chat with the owner\", \"checkedAt\": \"2026-01-31T10:00:00Z\"}\n]`\n}\n\n/** Valid patches from a model reply; anything malformed is dropped. */\nexport function parseContributionPatches(raw: string, agentId: string, opts: { now?: number } = {}): ContributionPatch[] {\n const match = raw.match(/\\[[\\s\\S]*\\]/)\n if (!match) return []\n let parsed: unknown\n try { parsed = JSON.parse(match[0]) } catch { return [] }\n if (!Array.isArray(parsed)) return []\n const now = opts.now ?? Date.now()\n const out: ContributionPatch[] = []\n for (const x of parsed) {\n if (!x || typeof x !== \"object\") continue\n const r = x as Record<string, unknown>\n const kind = r.kind\n if (kind !== \"add\" && kind !== \"correct\" && kind !== \"create\" && kind !== \"remove\") continue\n const page = clean(r.page, 120)\n // The fact line adds \"checked <date> by <agent>\" itself.\n const rawSource = clean(r.source, FIELD_CHARS)\n const source = rawSource.replace(/[\\s,;(–—-]*\\bchecked\\b[^;]*$/i, \"\").replace(/[\\s,;(]+$/, \"\") || rawSource\n const checked = typeof r.checkedAt === \"string\" ? Date.parse(r.checkedAt) : NaN\n if (!page || !source || !Number.isFinite(checked)) continue\n const attribute = clean(r.attribute, 60)\n const value = clean(r.value, FIELD_CHARS)\n const previous = clean(r.previous, FIELD_CHARS)\n const summary = clean(r.summary, FIELD_CHARS)\n if ((kind === \"add\" || kind === \"correct\") && (!attribute || !value)) continue\n if (kind === \"remove\" && !attribute && !previous) continue\n if (kind === \"create\" && !summary) continue\n const aliases = Array.isArray(r.aliases) ? r.aliases.map((a) => clean(a, 120)).filter(Boolean).slice(0, 10) : []\n // A check can't be dated after the run.\n const checkedAt = new Date(Math.min(checked, now)).toISOString()\n const body = { kind, page, attribute, value, previous, summary, source, checkedAt, agentId }\n out.push({\n id: createHash(\"sha1\").update(JSON.stringify(body)).digest(\"hex\").slice(0, 12),\n kind, page, source, checkedAt, agentId,\n ...(attribute ? { attribute } : {}),\n ...(value ? { value } : {}),\n ...(previous && kind !== \"add\" && kind !== \"create\" ? { previous } : {}),\n ...(summary && kind === \"create\" ? { summary } : {}),\n ...(kind === \"create\" && isWikiArticleType(r.pageType) ? { pageType: r.pageType } : {}),\n ...(kind === \"create\" && aliases.length ? { aliases } : {}),\n })\n }\n return out\n}\n\n/** One line, trimmed, capped; \"\" for anything not a string. */\nfunction clean(v: unknown, max: number): string {\n return typeof v === \"string\" ? v.replace(/\\s+/g, \" \").trim().slice(0, max) : \"\"\n}\n\nfunction clip(s: string, max: number): string {\n return s.length > max ? `${s.slice(0, max)}…` : s\n}\n\n// --- The daily merge -----------------------------------------------------------\n\nexport interface MergeReport {\n at: string\n batches: string[]\n agents: string[]\n patches: number\n /** Facts the ledger took as new, newer or re-checked. */\n applied: Array<{ page: string; attribute: string; value: string; by: string; status: string }>\n /** Pages that got a new or changed fact. */\n pagesUpdated: string[]\n pagesCreated: string[]\n /** Patches with an older check than the wiki's: a question was raised. */\n contradictions: Array<{ page: string; attribute: string; value: string; by: string; questionId?: string }>\n held: Array<{ id: string; page: string; attribute?: string; by: string; reason: string; lost?: string[] }>\n /** Several pages for one subject: listed for a person to merge. */\n duplicates: Array<{ title: string; pages: string[] }>\n dryRun?: boolean\n}\n\ninterface PageTarget {\n agentId: string\n store: WikiStore\n path: string\n article: WikiArticle\n}\n\n/** Title or alias, without case or punctuation. */\nexport function pageKey(title: string): string {\n return (title || \"\").toLowerCase().replace(/[^\\p{L}\\p{N}]+/gu, \" \").trim()\n}\n\n/** Every page by title and alias, across agents. Copied agents are read-only here. */\nfunction pageTargets(hub: WikiHub): Map<string, PageTarget[]> {\n const targets = new Map<string, PageTarget[]>()\n for (const id of hub.listAgents()) {\n if (hub.syncedFrom(id)) continue\n const store = hub.getAgentWiki(id)\n for (const article of store.listAllArticles()) {\n if (article.path.includes(\"/_versions/\")) continue\n const keys = new Set([article.meta.title, ...(article.meta.aliases ?? [])].map(pageKey).filter(Boolean))\n for (const k of keys) {\n const list = targets.get(k) ?? []\n list.push({ agentId: id, store, path: article.path, article })\n targets.set(k, list)\n }\n }\n }\n return targets\n}\n\n/**\n * Apply every pending batch. The newest checked fact wins (the fact\n * ledger keeps the older one in its history), new pages for one subject\n * become one page, and a change that would lose a fact is held.\n */\nexport function mergeContributions(hub: WikiHub, wikiDir: string, opts: { now?: number; dryRun?: boolean; log?: (m: string) => void } = {}): MergeReport {\n const now = opts.now ?? Date.now()\n const nowIso = new Date(now).toISOString()\n const today = nowIso.slice(0, 10)\n const batches = listPendingBatches(wikiDir)\n // Oldest check first, so the ledger takes each newer value over the\n // last and keeps the older one in its history.\n const patches = batches.flatMap((b) => b.patches).sort((a, b) => a.checkedAt.localeCompare(b.checkedAt))\n const report: MergeReport = {\n at: nowIso, batches: batches.map((b) => b.id), agents: [...new Set(batches.map((b) => b.agentId))].sort(),\n patches: patches.length, applied: [], pagesUpdated: [], pagesCreated: [], contradictions: [], held: [], duplicates: [],\n ...(opts.dryRun ? { dryRun: true } : {}),\n }\n const held: HeldPatch[] = []\n const hold = (patch: ContributionPatch, reason: string, lost?: string[]) => {\n const id = `h-${patch.id}`\n held.push({ id, patch, reason, heldAt: nowIso, status: \"held\", ...(lost?.length ? { lost } : {}) })\n report.held.push({ id, page: patch.page, attribute: patch.attribute, by: patch.agentId, reason, ...(lost?.length ? { lost } : {}) })\n }\n\n const targets = pageTargets(hub)\n for (const [, list] of targets) {\n const distinct = [...new Map(list.map((t) => [`${t.agentId}:${t.path}`, t])).values()]\n const title = distinct[0]?.article.meta.title\n if (distinct.length > 1 && title && !report.duplicates.some((d) => d.title === title)) {\n report.duplicates.push({ title, pages: distinct.map((t) => `${t.agentId}/${t.path}`) })\n }\n }\n\n // New pages: one per subject, however many agents proposed it. A page\n // that already exists (by title or alias) takes the facts instead.\n const newPages = new Map<string, NewPage>()\n for (const p of patches) {\n if (p.kind !== \"create\") continue\n const key = pageKey(p.page)\n if (targets.has(key)) continue\n const draft = newPages.get(key) ?? { title: p.page, owner: p.agentId, summaries: [], sources: [], aliases: [], at: p.checkedAt }\n draft.type ??= p.pageType\n if (p.summary && !draft.summaries.includes(p.summary)) draft.summaries.push(p.summary)\n if (!draft.sources.includes(p.source)) draft.sources.push(p.source)\n for (const a of p.aliases ?? []) if (!draft.aliases.includes(a)) draft.aliases.push(a)\n newPages.set(key, draft)\n }\n for (const p of patches) {\n const key = pageKey(p.page)\n if ((p.kind === \"add\" || p.kind === \"correct\") && !targets.has(key) && !newPages.has(key)) {\n // A fact about a subject with no page and no `create`: start one.\n newPages.set(key, { title: p.page, owner: p.agentId, summaries: [], sources: [p.source], aliases: [], at: p.checkedAt })\n }\n }\n\n // A new page whose title is a near match of an existing one is probably\n // that page under a longer or shorter name; creating it is how the\n // first trial duplicated a stale page instead of correcting it.\n const existing = [...targets.values()].map((list) => list[0])\n const duplicateOf = new Map<string, string>()\n for (const [key, draft] of newPages) {\n const match = possibleDuplicate(draft.title, draft.type, existing.map((t) => ({ title: t.article.meta.title, type: t.article.meta.type, ref: `${t.agentId}/${t.path}` })))\n if (match) duplicateOf.set(key, match)\n }\n for (const key of duplicateOf.keys()) newPages.delete(key)\n\n const ledger = new FactLedger(wikiDir)\n // Keyed by the page itself, not by the name a patch used: a title patch\n // and an alias patch to one page each started from the same stored\n // body, and the second write dropped the first one's lines.\n const edits = new Map<string, PageEdit[]>()\n const editTargets = new Map<string, PageTarget>()\n const editKey = (key: string) => {\n const t = targets.get(key)?.[0]\n if (!t) return `new:${key}`\n const k = `page:${t.agentId}:${t.path}`\n editTargets.set(k, t)\n return k\n }\n for (const p of patches) {\n const key = pageKey(p.page)\n const dup = duplicateOf.get(key)\n if (dup && p.kind !== \"remove\") { hold(p, `possible duplicate of ${dup}`); continue }\n if (p.kind === \"create\") continue\n if (p.kind === \"remove\") { hold(p, \"removes a fact\"); continue }\n const target = targets.get(key)?.[0]\n if (target && !target.store.canRead(target.article.meta, p.agentId)) {\n hold(p, \"the contributing agent cannot read this page\")\n continue\n }\n const subject = target?.article.meta.title ?? newPages.get(key)!.title\n let status = \"planned\"\n let value = p.value!\n if (!opts.dryRun) {\n const r = ledger.write({ subject, attribute: p.attribute!, value, source: p.source, verifiedBy: p.agentId, verifiedAt: p.checkedAt }, { now })\n status = r.status\n if (r.status === \"contradiction\") {\n report.contradictions.push({ page: subject, attribute: p.attribute!, value, by: p.agentId, questionId: r.questionId })\n continue\n }\n if (r.status === \"unchanged\") continue\n value = r.fact.value\n }\n report.applied.push({ page: subject, attribute: p.attribute!, value, by: p.agentId, status })\n const list = edits.get(editKey(key)) ?? []\n const previous = p.kind === \"correct\" ? p.previous : undefined\n list.push({ line: { attribute: p.attribute!, value, source: p.source, checkedAt: p.checkedAt, by: p.agentId, previous }, previous, patch: p })\n edits.set(editKey(key), list)\n }\n\n const touched = new Set<WikiStore>()\n for (const [key, list] of edits) {\n const target = editTargets.get(key)\n if (!target) continue\n const r = updatePage(target, list, { guard: true, today, dryRun: opts.dryRun })\n if (r.lost) for (const e of list) hold(e.patch, \"the change would lose facts the page has\", r.lost)\n else if (r.denied) for (const e of list) hold(e.patch, `write denied for ${target.agentId}/${target.path}`)\n else if (r.changed) {\n report.pagesUpdated.push(`${target.agentId}/${target.path}`)\n if (!opts.dryRun) touched.add(target.store)\n }\n }\n\n for (const [key, draft] of newPages) {\n const list = edits.get(`new:${key}`) ?? []\n if (!draft.summaries.length && !list.length) continue\n const store = hub.getAgentWiki(draft.owner)\n const path = newPagePath(store, draft.title, draft.type)\n report.pagesCreated.push(`${draft.owner}/${path}`)\n if (opts.dryRun) continue\n if (createPage(store, path, draft, list.map((e) => e.line), today)) touched.add(store)\n }\n\n if (!opts.dryRun) {\n for (const store of touched) {\n try { store.rebuildIndex() } catch (err) { opts.log?.(`index rebuild failed: ${(err as Error).message}`) }\n }\n const dir = contributionsDir(wikiDir)\n if (held.length) {\n const known = listHeld(wikiDir, { all: true })\n writeJson(heldFile(wikiDir), [...known, ...held.filter((h) => !known.some((k) => k.id === h.id))])\n }\n mkdirSync(resolve(dir, \"merged\"), { recursive: true })\n for (const b of batches) renameSync(resolve(dir, \"pending\", `${b.id}.json`), resolve(dir, \"merged\", `${b.id}.json`))\n writeJson(resolve(dir, \"reports\", `${nowIso.replace(/[:.]/g, \"-\")}.json`), report)\n }\n return report\n}\n\nfunction createPage(store: WikiStore, path: string, draft: NewPage, lines: FactLine[], today: string): boolean {\n const intro = draft.summaries.length ? draft.summaries.join(\" \") : `${draft.title}.`\n const { body } = applyFactLines(`${intro}\\n\\n_Sources: ${draft.sources.join(\"; \")}._`, lines)\n return store.writeArticle(path, {\n title: draft.title,\n ...(draft.type ? { type: draft.type } : {}),\n ...(draft.aliases.length ? { aliases: draft.aliases } : {}),\n tags: [],\n owner: draft.owner,\n access: \"public\",\n created: today,\n lastUpdated: today,\n sources: [contributionStamp(draft.owner, draft.at), ...lines.map((l) => contributionStamp(l.by, l.checkedAt))]\n .filter((s, i, a) => a.indexOf(s) === i),\n }, body, draft.owner)\n}\n\nconst TITLE_STOPWORDS = new Set([\"the\", \"and\", \"for\", \"with\", \"von\", \"des\", \"les\", \"der\", \"die\", \"das\", \"une\", \"pour\", \"page\", \"of\", \"de\", \"la\", \"le\", \"du\", \"et\"])\n\nfunction titleTokens(title: string): Set<string> {\n return new Set((title.toLowerCase().match(/[\\p{L}\\p{N}]+/gu) ?? []).filter((t) => (t.length > 2 || /\\d/.test(t)) && !TITLE_STOPWORDS.has(t)))\n}\n\n/**\n * The existing page a new title most likely means, or undefined. A match\n * shares at least two significant words and most of the shorter title's\n * words (\"Tax Payment Plan\" and \"Tax Payment Plan Engagement 4471\"). A\n * person page never matches a page of another type, and titles carrying\n * different numbers never match.\n */\nexport function possibleDuplicate(\n title: string, type: WikiArticleType | undefined,\n pages: Array<{ title: string; type?: WikiArticleType; ref: string }>,\n): string | undefined {\n const mine = titleTokens(title)\n if (mine.size < 2) return undefined\n let best: { ref: string; title: string; score: number } | undefined\n for (const p of pages) {\n if (type && p.type && (type === \"person\") !== (p.type === \"person\")) continue\n const theirs = titleTokens(p.title)\n if (theirs.size < 2) continue\n // Two numbered things (invoices, issues) with different numbers are\n // different things, however alike the rest of the title.\n const nums = (set: Set<string>) => [...set].filter((t) => /\\d/.test(t))\n const [a, b] = [nums(mine), nums(theirs)]\n if (a.length && b.length && !a.some((n) => b.includes(n))) continue\n let shared = 0\n for (const t of mine) if (theirs.has(t)) shared++\n const score = shared / Math.min(mine.size, theirs.size)\n if (shared >= 2 && score >= 0.75 && (!best || score > best.score)) best = { ref: p.ref, title: p.title, score }\n }\n return best ? `\"${best.title}\" (${best.ref})` : undefined\n}\n\ninterface NewPage {\n title: string\n type?: WikiArticleType\n owner: string\n summaries: string[]\n sources: string[]\n aliases: string[]\n /** Earliest check behind it. */\n at: string\n}\n\ninterface PageEdit {\n line: FactLine\n /** For a correction the ledger accepted: the exact wrong text to replace in place. */\n previous?: string\n patch: ContributionPatch\n}\n\n/**\n * Write a page's fact lines and in-place corrections. With `guard`, an\n * edit that would lose a structured fact is not written and the lost\n * facts are returned.\n */\nfunction updatePage(\n target: PageTarget, list: PageEdit[],\n opts: { guard: boolean; today: string; dryRun?: boolean; remove?: { attribute?: string; text?: string } },\n): { changed: boolean; lost?: string[]; denied?: boolean } {\n const before = target.article.content\n let { body, superseded } = applyFactLines(before, list.map((e) => e.line))\n for (const e of list) {\n if (!e.previous || e.previous === e.line.value) continue\n const fixed = replaceOnce(body, e.previous, e.line.value)\n if (fixed !== body) { body = fixed; superseded.push(e.previous) }\n }\n if (opts.remove) body = removeFact(body, opts.remove)\n if (body === before) return { changed: false }\n if (opts.guard) {\n const lost = lostStructuredFacts(before, body, superseded)\n if (lost.length) return { changed: false, lost }\n }\n if (opts.dryRun) return { changed: true }\n const meta = target.article.meta\n const stamps = list.map((e) => contributionStamp(e.line.by, e.line.checkedAt))\n const ok = target.store.writeArticle(target.path, {\n ...meta,\n lastUpdated: opts.today,\n sources: [...meta.sources, ...stamps].filter((s, i, a) => a.indexOf(s) === i),\n }, body, meta.owner)\n return ok ? { changed: true } : { changed: false, denied: true }\n}\n\n/** Replace `old` with `next` when it occurs exactly once, as whole words,\n * outside the \"Checked facts\" section; anything else is ambiguous and\n * left alone. Whole words, so \"paid\" is not rewritten inside \"unpaid\". */\nexport function replaceOnce(body: string, old: string, next: string): string {\n if (!old) return body\n const at = body.indexOf(FACTS_HEADING)\n const prose = at === -1 ? body : body.slice(0, at)\n const escaped = old.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n const hits = [...prose.matchAll(new RegExp(`(?<![\\\\p{L}\\\\p{N}])${escaped}(?![\\\\p{L}\\\\p{N}])`, \"gu\"))]\n if (hits.length !== 1) return body\n const first = hits[0].index!\n return body.slice(0, first) + next + body.slice(first + old.length)\n}\n\nfunction removeFact(body: string, remove: { attribute?: string; text?: string }): string {\n let out = body\n if (remove.attribute) {\n const attr = remove.attribute.toLowerCase()\n out = out.split(\"\\n\").filter((l) => l.match(LINE_RE)?.[1].toLowerCase() !== attr).join(\"\\n\")\n }\n if (remove.text) out = replaceOnce(out, remove.text, \"\")\n return out\n}\n\n// --- Held patches: a person decides ----------------------------------------\n\nexport type HeldDecision = { ok: true; held: HeldPatch; page?: string } | { ok: false; error: string }\n\n/**\n * Apply a held patch as it is, without the fact-loss guard: a person\n * looked at it. A removal deletes the attribute's fact line and the\n * exact text it names; the page's previous body stays in `_versions/`.\n */\nexport function approveHeld(hub: WikiHub, wikiDir: string, id: string, opts: { by?: string; now?: number } = {}): HeldDecision {\n const all = listHeld(wikiDir, { all: true })\n const h = all.find((x) => x.id === id)\n if (!h) return { ok: false, error: `no held patch \"${id}\"` }\n if (h.status !== \"held\") return { ok: false, error: `\"${id}\" is already ${h.status}` }\n const p = h.patch\n const now = opts.now ?? Date.now()\n const today = new Date(now).toISOString().slice(0, 10)\n const target = pageTargets(hub).get(pageKey(p.page))?.[0]\n if (!target) {\n // A held `create` (a possible duplicate), or a fact for the page it\n // would have made: a person said it is a new subject after all.\n if (p.kind === \"remove\") return { ok: false, error: `no page \"${p.page}\" (it may have been renamed)` }\n const lines: FactLine[] = []\n if (p.attribute && p.value) {\n const w = new FactLedger(wikiDir).write({ subject: p.page, attribute: p.attribute, value: p.value, source: p.source, verifiedBy: p.agentId, verifiedAt: p.checkedAt }, { now })\n if (w.status === \"contradiction\") return { ok: false, error: `the wiki has a newer check of ${p.attribute}; answer question ${w.questionId ?? \"(see wiki questions)\"} instead` }\n lines.push({ attribute: p.attribute, value: w.fact.value, source: p.source, checkedAt: p.checkedAt, by: p.agentId })\n }\n const store = hub.getAgentWiki(p.agentId)\n const path = newPagePath(store, p.page, p.pageType)\n const draft: NewPage = { title: p.page, type: p.pageType, owner: p.agentId, summaries: p.summary ? [p.summary] : [], sources: [p.source], aliases: p.aliases ?? [], at: p.checkedAt }\n if (!createPage(store, path, draft, lines, today)) return { ok: false, error: `write denied for ${p.agentId}/${path}` }\n try { store.rebuildIndex() } catch { /* the page is written; the next rebuild indexes it */ }\n return decide(wikiDir, all, h, \"approved\", opts.by, now, `${p.agentId}/${path}`)\n }\n\n let r: { changed: boolean; denied?: boolean }\n if (p.kind === \"remove\") {\n r = updatePage(target, [], { guard: false, today, remove: { attribute: p.attribute, text: p.previous } })\n } else {\n if (!p.attribute || !p.value) return { ok: false, error: `\"${id}\" carries no fact to apply` }\n const w = new FactLedger(wikiDir).write({ subject: target.article.meta.title, attribute: p.attribute, value: p.value, source: p.source, verifiedBy: p.agentId, verifiedAt: p.checkedAt }, { now })\n if (w.status === \"contradiction\") return { ok: false, error: `the wiki has a newer check of ${p.attribute}; answer question ${w.questionId ?? \"(see wiki questions)\"} instead` }\n const previous = p.kind === \"correct\" ? p.previous : undefined\n r = updatePage(target, [{ line: { attribute: p.attribute, value: w.fact.value, source: p.source, checkedAt: p.checkedAt, by: p.agentId, previous }, previous, patch: p }], { guard: false, today })\n }\n if (r.denied) return { ok: false, error: `write denied for ${target.agentId}/${target.path}` }\n if (r.changed) {\n try { target.store.rebuildIndex() } catch { /* the page is written; the next rebuild indexes it */ }\n }\n return decide(wikiDir, all, h, \"approved\", opts.by, now, `${target.agentId}/${target.path}`)\n}\n\nexport function rejectHeld(wikiDir: string, id: string, opts: { by?: string; now?: number } = {}): HeldDecision {\n const all = listHeld(wikiDir, { all: true })\n const h = all.find((x) => x.id === id)\n if (!h) return { ok: false, error: `no held patch \"${id}\"` }\n if (h.status !== \"held\") return { ok: false, error: `\"${id}\" is already ${h.status}` }\n return decide(wikiDir, all, h, \"rejected\", opts.by, opts.now ?? Date.now())\n}\n\nfunction decide(wikiDir: string, all: HeldPatch[], h: HeldPatch, status: \"approved\" | \"rejected\", by: string | undefined, now: number, page?: string): HeldDecision {\n const decided: HeldPatch = { ...h, status, decidedBy: by ?? \"operator\", decidedAt: new Date(now).toISOString() }\n writeJson(heldFile(wikiDir), all.map((x) => (x.id === h.id ? decided : x)))\n return { ok: true, held: decided, ...(page ? { page } : {}) }\n}\n\n// --- Page text -----------------------------------------------------------------\n\nexport interface FactLine {\n attribute: string\n value: string\n source: string\n checkedAt: string\n by: string\n previous?: string\n}\n\nconst LINE_RE = /^- \\*\\*(.+?):\\*\\* /\n\n/**\n * Add or update one line per attribute in the page's \"Checked facts\"\n * section. Nothing outside that section changes. A changed value keeps\n * the old one on its line as \"previously\", so a correction never drops a\n * fact from the page.\n *\n * `superseded` holds the replaced lines: their older parts live on in the\n * ledger's history and the page's versions, so the guard lets them go.\n */\nexport function applyFactLines(body: string, lines: FactLine[]): { body: string; superseded: string[] } {\n if (lines.length === 0) return { body, superseded: [] }\n const all = body.replace(/\\s+$/, \"\").split(\"\\n\")\n const start = all.findIndex((l) => l.trim() === FACTS_HEADING)\n let head = all\n let section: string[] = []\n let tail: string[] = []\n if (start !== -1) {\n head = all.slice(0, start)\n const rest = all.slice(start + 1)\n const end = rest.findIndex((l) => /^#{1,2} /.test(l))\n section = (end === -1 ? rest : rest.slice(0, end)).filter((l) => l.trim())\n tail = end === -1 ? [] : rest.slice(end)\n }\n\n const superseded: string[] = []\n for (const l of lines) {\n const at = section.findIndex((s) => s.match(LINE_RE)?.[1].toLowerCase() === l.attribute.toLowerCase())\n const old = at === -1 ? undefined : parseFactLine(section[at])\n if (at !== -1) superseded.push(section[at])\n // A re-check of the same value refreshes the line and keeps its history.\n const previous = old && old.value === l.value ? old.previous : old ? `${old.value}, checked ${old.checkedAt}` : l.previous\n // An existing line keeps its spelling of the attribute.\n const attribute = section[at]?.match(LINE_RE)?.[1] ?? l.attribute\n const line = renderFactLine({ ...l, attribute, previous })\n if (at === -1) section.push(line)\n else section[at] = line\n }\n\n const out = [...(head.some((l) => l.trim()) ? [...head, \"\"] : []), FACTS_HEADING, \"\", ...section]\n if (tail.length) out.push(\"\", ...tail)\n return { body: out.join(\"\\n\").replace(/\\n{3,}/g, \"\\n\\n\").trim(), superseded }\n}\n\nfunction renderFactLine(l: FactLine): string {\n const prev = l.previous ? ` (previously: ${l.previous})` : \"\"\n return `- **${l.attribute}:** ${l.value} — ${l.source}; checked ${l.checkedAt.slice(0, 10)} by ${l.by}${prev}`\n}\n\nfunction parseFactLine(line: string): { value: string; checkedAt: string; previous?: string } | undefined {\n const m = line.match(/^- \\*\\*.+?:\\*\\* (.*?) — .*?; checked (\\S+) by \\S+(?: \\(previously: (.*)\\))?$/)\n return m ? { value: m[1], checkedAt: m[2], ...(m[3] ? { previous: m[3] } : {}) } : undefined\n}\n\nfunction contributionStamp(agentId: string, at: string): string {\n return `contribution:${agentId}@${at.slice(0, 10)}`\n}\n\nconst TYPE_FOLDER: Record<WikiArticleType, string> = {\n person: \"people\", project: \"projects\", place: \"places\", concept: \"concepts\",\n event: \"events\", decision: \"decisions\", pattern: \"patterns\",\n}\n\nfunction newPagePath(store: WikiStore, title: string, type?: WikiArticleType): string {\n const slug = title.toLowerCase().replace(/[^\\p{L}\\p{N}]+/gu, \"-\").replace(/^-+|-+$/g, \"\").slice(0, 60) || \"page\"\n const folder = type ? TYPE_FOLDER[type] : \"contributions\"\n let path = `${folder}/${slug}.md`\n for (let n = 2; store.readArticle(path); n++) path = `${folder}/${slug}-${n}.md`\n return path\n}\n"],"mappings":"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","names":["createHash","existsSync","mkdirSync","readdirSync","readFileSync","renameSync","writeFileSync","resolve","DEFAULT_CONTRIBUTION_LIMITS","ITEMS_PER_CALL","ITEM_CHARS","PAGE_CHARS","PAGES_PER_CALL","FIELD_CHARS","STEPS_PER_TRACE","FACTS_HEADING","contributionsDir","wikiDir","resolve","readJson","file","fallback","existsSync","readFileSync","err","writeJson","data","mkdirSync","tmp","writeFileSync","renameSync","readState","listPendingBatches","dir","readdirSync","f","b","heldFile","listHeld","opts","list","h","latestReport","last","pendingWork","hub","agentId","state","now","since","sinceDay","done","items","e","sinceMs","t","listTraces","tools","getTrace","s","clip","text","a","saveCursor","read","unread","prev","lastRunAt","processed","w","runContribution","limits","all","pages","readablePages","batch","seen","chunk","prompt","buildContributionPrompt","relevantPages","reply","p","parseContributionPatches","out","add","store","skip","byTitle","scoreAll","buildIndex","byBody","picked","half","r","i","maxPatches","work","wiki","raw","match","parsed","x","kind","page","clean","rawSource","source","checked","attribute","value","previous","summary","aliases","checkedAt","body","createHash","isWikiArticleType","v","max","pageKey","title","pageTargets","targets","id","article","keys","k","mergeContributions","nowIso","today","batches","patches","report","held","hold","patch","reason","lost","distinct","d","newPages","key","draft","existing","duplicateOf","possibleDuplicate","ledger","FactLedger","edits","editTargets","editKey","dup","target","subject","status","touched","updatePage","path","newPagePath","createPage","known","lines","intro","applyFactLines","contributionStamp","l","TITLE_STOPWORDS","titleTokens","type","mine","best","theirs","nums","set","n","shared","score","before","superseded","fixed","replaceOnce","removeFact","lostStructuredFacts","meta","stamps","old","next","at","prose","escaped","hits","first","remove","attr","LINE_RE","approveHeld","decide","rejectHeld","by","decided","start","head","section","tail","rest","end","parseFactLine","line","renderFactLine","m","TYPE_FOLDER","slug","folder"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{b as a,c as b,d as c,e as d,f as e}from"./chunk-
|
|
2
|
-
//# sourceMappingURL=doctor-
|
|
1
|
+
import{b as a,c as b,d as c,e as d,f as e}from"./chunk-QFZU5CEO.js";import"./chunk-S2GAEH2F.js";import"./chunk-JXF54PT7.js";import"./chunk-MRYA4J5F.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";export{e as daemonVoiceCheck,b as doctor,a as runDoctorChecks,c as runNotificationChecks,d as runReminderChecks};
|
|
2
|
+
//# sourceMappingURL=doctor-VLRC4HW2.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{b as h}from"./chunk-
|
|
1
|
+
import{b as h}from"./chunk-TG6CT54D.js";import"./chunk-RKPAVWXF.js";import{b as m}from"./chunk-LLNPKE7H.js";import"./chunk-SHEUCITK.js";import"./chunk-ZLC4TSXF.js";import"./chunk-2SV4RKRW.js";import"./chunk-HKW56YZK.js";import"./chunk-52SIHG45.js";import"./chunk-FCPTN6NF.js";import"./chunk-7I7IEX4S.js";import"./chunk-MRYA4J5F.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";var p=t=>typeof t=="string"?t.trim():"";function k(t){return[`Run ${t.runId} "${t.title}" [${t.status}] on step ${t.step}: waiting on ${t.waitingOn}.`,t.tags?.length?`Tags: ${t.tags.join(", ")}`:"",...(t.steps??[]).slice(-8).map(r=>`- ${String(r.at).slice(0,16).replace("T"," ")} ${r.step} ${r.status}${r.note?`: ${r.note}`:""}`)].filter(Boolean).join(`
|
|
2
2
|
`)}async function T(t,u){let r=u.fetch??fetch,$=u.daemonUrl.replace(/\/$/,""),a=(p(t.action)||"list").toLowerCase(),f=u.env??process.env,w=async i=>{let l=await r(`${$}${i}`,{signal:AbortSignal.timeout(1e4)}),n=await l.json().catch(()=>({}));return{ok:l.ok,status:l.status,data:n}};try{if(a==="list"){let e=await w("/follow-up");if(!e.ok)return`Error: ${e.data?.error||`HTTP ${e.status}`}`;let o=e.data.groups??[];return o.length?o.map(c=>[`${c.tag}:`,...c.rows.map(s=>`- ${s.runId} "${s.title}" on ${s.step}: waiting on ${s.waitingOn} (since ${String(s.since).slice(0,16).replace("T"," ")} UTC)`)].join(`
|
|
3
3
|
`)).join(`
|
|
4
4
|
`):"No follow-up workflows are running."}if(a==="match"){let e=p(t.request)||p(t.title);if(!e)return"Error: match needs `request`: the owner's request in their words.";let o=h(t,f),c=await w(`/follow-up/match?q=${encodeURIComponent(e)}${o?`&agentId=${encodeURIComponent(o.agentId)}`:""}`);if(!c.ok)return`Error: ${c.data?.error||`HTTP ${c.status}`}`;let s=c.data.matches??[];return s.length?["Saved workflows, best fit first (confidence 0-1):",...s.map(d=>`- ${d.workflowId} "${d.title}" (${d.confidence}${d.autoStart?", starts without asking":""}): ${d.steps.map(I=>I.id).join(" \u2192 ")}`),'Start one with {action:"start", workflowId:"<id>", title:"\u2026", tags:["client:<name>"]}. Run its steps through the workflow, not by hand.'].join(`
|
|
5
5
|
`):"No saved workflow fits. If the request has several steps, build one: start with title and steps."}if(a==="status"){let e=p(t.runId);if(!e)return"Error: status needs runId.";let o=await w(`/follow-up/${encodeURIComponent(e)}`);return o.ok?k(o.data.run):`Error: ${o.data?.error||`HTTP ${o.status}`}`}let i=h(t,f);if(!i)return"Error: couldn't tell which agent you are. Pass callerAgentId.";let l=await r(`${$}/follow-up`,{method:"POST",headers:{"Content-Type":"application/json",...m(f)},body:JSON.stringify({action:a,agentId:i.agentId,workflowId:t.workflowId,title:t.title,description:t.description,tags:t.tags,inputs:t.inputs,steps:t.steps,edges:t.edges,approval:t.approval,autoStart:t.autoStart,requestId:t.requestId,runId:t.runId,step:t.step,evidence:t.evidence,note:t.note,reason:t.reason,fromRun:t.fromRun}),signal:AbortSignal.timeout(2e4)}),n=await l.json().catch(()=>({}));if(!l.ok)return`Error: ${n?.error||`HTTP ${l.status}`}`;if(a==="start"){let e=n.run;return[`Started run ${e.runId} "${e.title}"${n.built?" (built from the steps you gave; propose it with fromRun to keep it)":""}.`,n.awaitingApproval?"It waits for the owner's approval before the first step.":`It is on step ${e.step}: ${e.waitingOn}.`,"AgentX follows it from here: it starts each step, reminds whoever is slow, and tells the owner when it ends. Do not run its steps by hand.",...n.warning?[`Note: ${n.warning}`]:[]].join(" ")}return a==="done"?`Step recorded as done. ${n.run?k(n.run):""}`.trim():a==="blocked"?"The step is marked blocked and the owner is told. Nothing more happens on it until it is sorted.":`Saved ${n.workflowId} switched off, and asked the owner (card ${n.cardId}) whether to keep it as a reusable workflow.`}catch(i){return`Error: couldn't reach the daemon (${i?.message??i}).`}}export{T as runWorkflowTool};
|
|
6
|
-
//# sourceMappingURL=follow-up-tool-
|
|
6
|
+
//# sourceMappingURL=follow-up-tool-235LDEMP.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a}from"./chunk-
|
|
2
|
-
//# sourceMappingURL=hub-
|
|
1
|
+
import{a}from"./chunk-Z3W7D5RR.js";import"./chunk-P4XGM7ZM.js";import"./chunk-3PGPN323.js";import"./chunk-LDS4SZBU.js";import"./chunk-WPNRDEHW.js";import"./chunk-YWKLUQDC.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-QOYAX2FT.js";import"./chunk-4VVHGR7H.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-MRYA4J5F.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{a as WikiHub};
|
|
2
|
+
//# sourceMappingURL=hub-5QK7KYTZ.js.map
|