arisa 5.1.24 → 5.1.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/package.json +2 -3
  2. package/src/core/agent/agent-manager.js +132 -70
  3. package/src/core/agent/pi-runtime.js +0 -8
  4. package/src/core/agent/system-shell-tool.js +13 -2
  5. package/src/core/artifacts/artifact-store.js +17 -18
  6. package/src/core/config/config-defaults.js +2 -2
  7. package/src/core/conversation/session-seed-store.js +85 -0
  8. package/src/core/tools/ipc-client.js +0 -2
  9. package/src/core/tools/tool-output-materializer.js +41 -0
  10. package/src/core/tools/tool-registry.js +96 -23
  11. package/src/official-tools.lock.json +145 -93
  12. package/src/runtime/doctor.js +1 -4
  13. package/src/runtime/headless-tool-executor.js +2 -32
  14. package/src/runtime/paths.js +7 -1
  15. package/src/runtime/restart-receipt.js +90 -0
  16. package/src/transport/telegram/bot.js +390 -1034
  17. package/src/transport/telegram/chat-queue.js +132 -0
  18. package/src/transport/telegram/media.js +2 -2
  19. package/src/transport/telegram/model-callback.js +211 -0
  20. package/src/transport/telegram/model-controls.js +164 -0
  21. package/src/transport/telegram/prompt-builders.js +372 -0
  22. package/src/transport/telegram/task-dispatcher.js +94 -0
  23. package/src/transport/telegram/update-command.js +1 -1
  24. package/src/transport/telegram/workspace-group.js +83 -0
  25. package/test/agent-tool-policy.test.js +7 -1
  26. package/test/context-and-task-bounds.test.js +9 -7
  27. package/test/doctor.test.js +2 -4
  28. package/test/model-selection.test.js +47 -1
  29. package/test/official-tool-dependencies.test.js +2 -0
  30. package/test/paths.test.js +4 -4
  31. package/test/restart-receipt.test.js +39 -0
  32. package/test/session-start-operational-notes.test.js +47 -0
  33. package/test/telegram-prompt-builders.test.js +33 -0
  34. package/test/telegram-task-dispatcher.test.js +102 -0
  35. package/test/telegram-workspace-group.test.js +76 -0
  36. package/test/tool-registry-run.test.js +62 -0
  37. package/test/topic-initialization.test.js +66 -0
  38. package/src/core/conversation/conversation-history-store.js +0 -142
@@ -16,17 +16,53 @@ function toolEnv() {
16
16
  return { ...process.env, ARISA_PACKAGE_DIR: arisaPackageDir, ARISA_IPC_SOCKET: arisaIpcSocketFile };
17
17
  }
18
18
 
19
- function runProcess(command, args, options = {}) {
20
- return new Promise((resolve) => {
21
- const child = spawn(command, args, { ...options, stdio: ["ignore", "pipe", "pipe"] });
22
- let stdout = "";
23
- let stderr = "";
24
- child.stdout.on("data", (d) => { stdout += d.toString(); });
25
- child.stderr.on("data", (d) => { stderr += d.toString(); });
26
- child.on("close", (code) => resolve({ code, stdout, stderr }));
19
+ const defaultToolHelpTimeoutMs = 10_000;
20
+ const defaultToolRunTimeoutMs = 30 * 60_000;
21
+ const defaultToolKillGraceMs = 2_000;
22
+
23
+ function positiveDuration(value, fallback) {
24
+ return Number.isFinite(value) && value > 0 ? value : fallback;
25
+ }
26
+
27
+ function waitForToolProcess(child, { timeoutMs, killGraceMs, label }) {
28
+ return new Promise((resolve, reject) => {
29
+ let timedOut = false;
30
+ let forceTimer = null;
31
+ const timeout = setTimeout(() => {
32
+ timedOut = true;
33
+ child.kill("SIGTERM");
34
+ forceTimer = setTimeout(() => child.kill("SIGKILL"), killGraceMs);
35
+ }, timeoutMs);
36
+
37
+ const finish = (callback, value) => {
38
+ clearTimeout(timeout);
39
+ clearTimeout(forceTimer);
40
+ callback(value);
41
+ };
42
+
43
+ child.once("error", (error) => finish(reject, error));
44
+ child.once("close", (code) => {
45
+ if (!timedOut) {
46
+ finish(resolve, code);
47
+ return;
48
+ }
49
+ const error = new Error(`${label} timed out after ${timeoutMs}ms`);
50
+ error.code = "TOOL_PROCESS_TIMEOUT";
51
+ finish(reject, error);
52
+ });
27
53
  });
28
54
  }
29
55
 
56
+ async function runProcess(command, args, { timeoutMs, killGraceMs, label, ...options } = {}) {
57
+ const child = spawn(command, args, { ...options, stdio: ["ignore", "pipe", "pipe"] });
58
+ let stdout = "";
59
+ let stderr = "";
60
+ child.stdout.on("data", (d) => { stdout += d.toString(); });
61
+ child.stderr.on("data", (d) => { stderr += d.toString(); });
62
+ const code = await waitForToolProcess(child, { timeoutMs, killGraceMs, label });
63
+ return { code, stdout, stderr };
64
+ }
65
+
30
66
  function requirementNames(requirements) {
31
67
  if (Array.isArray(requirements)) {
32
68
  return requirements.map((item) => typeof item === "string" ? item : item?.name).filter(Boolean);
@@ -121,7 +157,7 @@ export function createToolOutputParser(name, { onEvent, maxFrameBytes = 1_048_57
121
157
  };
122
158
  }
123
159
 
124
- async function runToolProcess(command, args, { onEvent, maxFrameBytes, ...options } = {}) {
160
+ async function runToolProcess(command, args, { onEvent, maxFrameBytes, timeoutMs, killGraceMs, label, ...options } = {}) {
125
161
  const child = spawn(command, args, { ...options, stdio: ["ignore", "pipe", "pipe"] });
126
162
  const parser = createToolOutputParser(path.basename(args[0] || command), { onEvent, maxFrameBytes });
127
163
  const stderrChunks = [];
@@ -139,13 +175,15 @@ async function runToolProcess(command, args, { onEvent, maxFrameBytes, ...option
139
175
  }
140
176
  return Buffer.concat(stderrChunks).toString("utf8");
141
177
  })();
142
- const exitPromise = new Promise((resolve, reject) => {
143
- child.once("error", reject);
144
- child.once("close", resolve);
145
- });
146
178
  child.stdout.resume();
147
179
  child.stderr.resume();
148
- const code = await exitPromise;
180
+ let code;
181
+ try {
182
+ code = await waitForToolProcess(child, { timeoutMs, killGraceMs, label });
183
+ } catch (error) {
184
+ await Promise.allSettled([stdoutTask, stderrTask]);
185
+ throw error;
186
+ }
149
187
  const [parsed, stderr] = await Promise.all([stdoutTask, stderrTask]);
150
188
  return { code, parsed, stderr };
151
189
  }
@@ -228,17 +266,26 @@ async function readOfficialToolNames() {
228
266
  }
229
267
 
230
268
  export class ToolRegistry {
231
- constructor({ logger, usageStore = new ToolUsageStore(), resolveOfficialToolNames = readOfficialToolNames } = {}) {
269
+ constructor({
270
+ logger,
271
+ usageStore = new ToolUsageStore(),
272
+ resolveOfficialToolNames = readOfficialToolNames,
273
+ helpTimeoutMs = defaultToolHelpTimeoutMs,
274
+ runTimeoutMs = defaultToolRunTimeoutMs,
275
+ killGraceMs = defaultToolKillGraceMs
276
+ } = {}) {
232
277
  this.logger = logger;
278
+ this.helpTimeoutMs = positiveDuration(helpTimeoutMs, defaultToolHelpTimeoutMs);
279
+ this.runTimeoutMs = positiveDuration(runTimeoutMs, defaultToolRunTimeoutMs);
280
+ this.killGraceMs = positiveDuration(killGraceMs, defaultToolKillGraceMs);
233
281
  this.tools = new Map();
234
282
  this.skillRegistry = new SkillRegistry();
235
283
  this.usageStore = usageStore;
236
284
  this.resolveOfficialToolNames = resolveOfficialToolNames;
237
285
  }
238
286
 
239
- async load() {
240
- this.tools.clear();
241
-
287
+ async buildSnapshot() {
288
+ const snapshot = new Map();
242
289
  let entries = [];
243
290
  try {
244
291
  entries = await readdir(userToolsRoot, { withFileTypes: true });
@@ -253,12 +300,12 @@ export class ToolRegistry {
253
300
  const configPath = path.join(toolDir, "config.js");
254
301
  try {
255
302
  const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
256
- if (this.tools.has(manifest.name)) continue;
303
+ if (snapshot.has(manifest.name)) continue;
257
304
  const configSource = await readFile(configPath, "utf8");
258
305
  const defaults = parseConfigModule(configSource);
259
306
  const config = await loadToolConfig(manifest.name, defaults);
260
307
  const skillHints = this.skillRegistry.normalizeHints(manifest);
261
- this.tools.set(manifest.name, {
308
+ snapshot.set(manifest.name, {
262
309
  ...manifest,
263
310
  toolDependencies: normalizeToolDependencies(manifest.toolDependencies),
264
311
  category: normalizeCategory(manifest.category),
@@ -275,8 +322,13 @@ export class ToolRegistry {
275
322
  // ignore invalid tool dirs in v1
276
323
  }
277
324
  }
325
+ return snapshot;
326
+ }
278
327
 
279
- this.logger?.log("tools", `loaded ${this.tools.size} tool(s)`);
328
+ async load() {
329
+ const snapshot = await this.buildSnapshot();
330
+ this.tools = snapshot;
331
+ this.logger?.log("tools", `loaded ${snapshot.size} tool(s)`);
280
332
  }
281
333
 
282
334
  list() {
@@ -333,7 +385,13 @@ export class ToolRegistry {
333
385
  async help(name) {
334
386
  const tool = this.get(name);
335
387
  if (!tool) throw new Error(`Tool not found: ${name}`);
336
- const result = await runProcess("node", [tool.entry, "--help"], { cwd: tool.dir, env: toolEnv() });
388
+ const result = await runProcess("node", [tool.entry, "--help"], {
389
+ cwd: tool.dir,
390
+ env: toolEnv(),
391
+ timeoutMs: this.helpTimeoutMs,
392
+ killGraceMs: this.killGraceMs,
393
+ label: `Tool help for ${name}`
394
+ });
337
395
  const help = result.stdout || result.stderr;
338
396
  const skills = await this.resolveSkills(name);
339
397
  const sections = [
@@ -443,7 +501,10 @@ export class ToolRegistry {
443
501
  cwd: tool.dir,
444
502
  env: toolEnv(),
445
503
  onEvent,
446
- maxFrameBytes: daemonConfigDefaults.ipcFrameBytes
504
+ maxFrameBytes: daemonConfigDefaults.ipcFrameBytes,
505
+ timeoutMs: this.runTimeoutMs,
506
+ killGraceMs: this.killGraceMs,
507
+ label: `Tool run for ${name}`
447
508
  });
448
509
  if (processResult.stderr.trim()) {
449
510
  this.logger?.log("tools", `${name} stderr: ${processResult.stderr.trim()}`);
@@ -460,6 +521,18 @@ export class ToolRegistry {
460
521
  }
461
522
  return normalized;
462
523
  } catch (error) {
524
+ if (error?.code === "TOOL_PROCESS_TIMEOUT") {
525
+ return normalizeToolResult(name, {
526
+ ok: false,
527
+ status: "outcome_uncertain",
528
+ error: error.message,
529
+ resolution: {
530
+ type: "status_check_required",
531
+ retry: false,
532
+ message: "The tool process was terminated after timing out. Check external state before retrying."
533
+ }
534
+ });
535
+ }
463
536
  return normalizeToolResult(name, {
464
537
  ok: false,
465
538
  error: error?.message || `Invalid tool response for ${name}`
@@ -1,8 +1,100 @@
1
1
  {
2
2
  "version": 1,
3
3
  "repository": "https://github.com/clasen/Arisa.git",
4
- "commit": "eff37798c546e33cc4386c878ee01baa5dbd701c",
4
+ "commit": "aaec12e4f63f4959462b26380e7d4c1a60562586",
5
5
  "tools": {
6
+ "browser-session-bridge": {
7
+ "version": "0.1.0",
8
+ "files": {
9
+ "bridge-server.js": "87f5a392bc99fd97899836c0731b4694402b04d5dfbe88e66bb4f496bfef351d",
10
+ "chrome-web-store.js": "a6bd9553f1490d5ccda3fe3044c30ee6fe243f422e69a5000bc844884e6d1e95",
11
+ "config.js": "45c8e9e9a159b9125d6ea3458c616926c2ba2b5327fdfd750aa05316d3ce5af8",
12
+ "extension/icons/icon-128.png": "a55af49bb570bd5471fc0a2e15a6bcaf3f76a2c5e7439f16bb1829682b343380",
13
+ "extension/icons/icon-16.png": "a4aedb49e2227222a68dc56455812a9e17938fd197b1f30268f02d6c9f7bf95e",
14
+ "extension/icons/icon-32.png": "2dfc9e6e7ec6b4e9feb9c1326d65116cda8e53306c65c84074c818c9e7f6a2a2",
15
+ "extension/icons/icon-48.png": "2f316f1f2fbc72227e7e1f14cf1ff1553a12fc9aab139799f1ee2970c0303deb",
16
+ "extension/manifest.json": "3e19d7b1c2a9521745b585fbbb3a6f4639d3056703fdbca17e8cd6dd80fc4c91",
17
+ "extension/popup.css": "138811e3e96e9c7741f064f8cf017be75973cd0942efa9668e96a584b7b52c1c",
18
+ "extension/popup.html": "9d7798efd04c57c534840a7966dd3818f9264022c52390f0fd1d462236a01d60",
19
+ "extension/popup.js": "60ea83f17e5d87f072d27c6540b903361f70e03925c3727983cca6beba9696d3",
20
+ "index.js": "4c92afffaec61910e3522f483535c760e8c660604158a23628d2807daa024934",
21
+ "package-lock.json": "e1081b8b48c2eaaeca73c63e64902519b33e8822ce351a45afe8509224776c12",
22
+ "package.json": "b54fad02442d9d09fb42d6c1fa01bb2e441e946babdf73dbc7e5767002a07b28",
23
+ "README.md": "fc2848472b48627838b757bf1a7be9564f31e483e8b673bd4ae95a11016f3309",
24
+ "session-browser.js": "d5544db5c6712327e76b8436cfabe02e34d8e043ff2d251c2c5ff3f00f1a9dd7",
25
+ "session-store.js": "56b33e1a342ba148cb4443e03435e5c728db60903ecd0ae87c05fbff3ca881ab",
26
+ "test/device-enrollment.test.js": "3dd36d37044eaf1043bd8b2e9f10ead9dc87479152a07237ab87d50146782f4c",
27
+ "test/session-refresh.test.js": "8f5facb81444f0d09928d48f22e82112d47bde21927afcd7fd830ce6832b9f79",
28
+ "tool.manifest.json": "40326de8bc08f2fd51ce51d4a20637b9af37de588d6cb97d27bc0b0d16304095",
29
+ "web-store/listing.md": "914e7c38bc67e19f3afbea86288c0cbc49afcb8941f4734fd3f786c5533861e7",
30
+ "web-store/privacy-policy.md": "c96e84f1a112e5949a3e7bd952fcf5ec794eaa5c4bee14a1dbe0c8e0f5888fb7"
31
+ }
32
+ },
33
+ "campaign-draft-runner": {
34
+ "version": "0.3.3",
35
+ "toolDependencies": {
36
+ "pr-campaign": "^0.1.0",
37
+ "gmail-workspace": "^0.1.0"
38
+ },
39
+ "files": {
40
+ "README.md": "fb73d47f6825a1c9b419f6667a319c2cbd959dc7b56c488321db72a6e2210a41",
41
+ "config.js": "23b95ad1851e498310eb400b1d53c648c280ddcc73cf91f6fa0ae5dc470ae6d2",
42
+ "index.js": "28d58096adb76e00d74b23ef10816199a5af57e13866ed6ab829da2535d73890",
43
+ "operation-timeout.js": "9b1ced30ec9ed710bb9118b91f6f3feded5111a08e1e21abf163e4cfb91d7ad2",
44
+ "package.json": "a25b7ed1dd2c30cd68c3c10feb8ee1752cac8cd55cd4344690ffad649e231ec1",
45
+ "product-facts.js": "69339e20e7b70a6b9833878d72b10b70ea4ede4aa448097975d0961b6aaced59",
46
+ "search-quality.js": "ab5412d45d5144e976cccef52992e634c11aca0e21b73fd53f9dc2d489c56dd7",
47
+ "source-exhaustion.js": "407f940f5205eb01715a797672d0dad8bd0b0b897024b5fcb87052a062ecd054",
48
+ "telemetry.js": "bab44341ae2176c8a29eed19b89db4e7e251c9938af163ecd85293917d94bfb5",
49
+ "test/selection-policy.test.js": "27dacdc6ac3b1c570229ef624267c5bf7e4b9606dbb71214c2a451a30ac3762b",
50
+ "test/telemetry.test.js": "e297727e382163f18ab0ec4a21f55bf7e47790939510b615fd8e38c4dfc1998f",
51
+ "tool.manifest.json": "1eacb9ccdf0b37bba9745ba20ce3462548bac28c7abb15214e5502e7e53d3e0d"
52
+ }
53
+ },
54
+ "creator-scout": {
55
+ "version": "1.0.1",
56
+ "files": {
57
+ "README.md": "4f50850317c0875ad7ddea767c7dda112669112bec107a98e67a31a42787b82c",
58
+ "config.js": "bab728665650b986c0eaef8e1be1c259ec42b1f83df4217c9780f5468d3c7666",
59
+ "index.js": "d1266d622b6abaf77ce1fe93823d4f2faedb8a5991371997c364082a198dc728",
60
+ "package-lock.json": "ed479120b59c2d9b083991dea60eb7750ba36bc7b2c7defb01cfb598889b8d90",
61
+ "package.json": "ad463eeddea6a958ef291d58f216c0b42c5ff3b398b62ed9512b857ea5e4b672",
62
+ "reference-match.js": "762d822ad31f89c06cb5a40f84ba3f864436db486375ed30e48bde94de282c7c",
63
+ "test/reference-match.test.js": "701ce83396126b1e42bd3a54e331ff011a1fc27646a0f3aa99ce1c3e576aff6d",
64
+ "tool.manifest.json": "0617b0488035fd7f8a83a8e5a698558b3d0e956e7ea1e043e2e80bb224d4974f"
65
+ }
66
+ },
67
+ "gmail-workspace": {
68
+ "version": "0.1.1",
69
+ "files": {
70
+ "config.js": "6ad295ec4cedbc936835d8f86c7528e0939ef09d5792c003308d2ee85dc5eea4",
71
+ "index.js": "c4b1c27a3c5d2309501b695058da73f6287e2a6239f6e2384c05daae8ee25d43",
72
+ "package.json": "ba87edd5a148da9e99af6b3ab71a0024b86e1a469d56f548c7eeb253bb431f5d",
73
+ "secretary-state.js": "afc27732670420bccf1ce56ce715676dd2266de9f2d36a92015a93842755094a",
74
+ "test/secretary-state.test.mjs": "3aea05524a4ad5ebcb79c6aa1db94fcd009ac8ae69414c8f950b32a32af94370",
75
+ "tool.manifest.json": "2860c5684b9b9532ab4675f5cc5b96238320209086b132a5eda74ba99b6c294a"
76
+ }
77
+ },
78
+ "magnific-mcp": {
79
+ "version": "0.1.1",
80
+ "toolDependencies": {
81
+ "mcp-client": "^0.1.0"
82
+ },
83
+ "files": {
84
+ "README.md": "519b68d10c80112f475ab173394e937b0fc5930758415c1fc65ea2f5536b6371",
85
+ "config.js": "98a629781a1b2541806050952aa78a1e6e1b1671a6f1df7ba36c70dd116936a7",
86
+ "delivery-claims.js": "52f05a5bd1ece1ab21f7d9a49f362f9c55f101ef5723efd642dbecf0236921cd",
87
+ "generation-watch-close.js": "0dd780280eef870d2f11cb1800e6e9de19e5ead7b9d02b9983852cc8ddbdc79b",
88
+ "generation-watch-plan.js": "eb60660341f254adc224181ca19dbbb969ef1d676aeaab60b71a8567f52648fe",
89
+ "index.js": "0dcbd84ad03ab59919df57081d34a45c3a8d59b3c37ac31249409210ae7107e6",
90
+ "magnific-api.js": "39fa9a122577029111965c3e8487565c88ce46b61dec5ca685acf1c76cd3b636",
91
+ "network.js": "b45e43b49eea98ca7d80921ebfa6daf8b0a85d2079d4653f9eda682bc82101ae",
92
+ "package.json": "9c44eb43a3555cf79bd327318f9a30d3060f22dd2fd534923e303cca1eed7de9",
93
+ "state-store.js": "c3ee744509f7a6be251cd895406bd1c70827f53cbdc1ac9d1c2a6e48479bfe1e",
94
+ "test/magnific-mcp.test.js": "7a61dd19a2f6f9f48213cabf0de6e87e0b6fb73a94f0ea9dbfe9c8568c2cc32d",
95
+ "tool.manifest.json": "ff886d95250d279eff097430e6f89405a2bdd488d5f0949277cbc3f57f918950"
96
+ }
97
+ },
6
98
  "master-slave": {
7
99
  "files": {
8
100
  "README.md": "84d2841d8df31c07065d4fee6e434dc43cad241f3abf63e95efafad51ed69fcb",
@@ -53,38 +145,19 @@
53
145
  "tool.manifest.json": "5659c398922c914c5bf893404519a30071ee685ab49f34a650ecafd585b4d6ec"
54
146
  }
55
147
  },
56
- "magnific-mcp": {
57
- "version": "0.1.0",
58
- "toolDependencies": {
59
- "mcp-client": "^0.1.0"
60
- },
61
- "files": {
62
- "README.md": "00342fc9ae98f38716aeb332941524336c0e9ee4a5020104e52e7ed7b61882f9",
63
- "config.js": "98a629781a1b2541806050952aa78a1e6e1b1671a6f1df7ba36c70dd116936a7",
64
- "delivery-claims.js": "52f05a5bd1ece1ab21f7d9a49f362f9c55f101ef5723efd642dbecf0236921cd",
65
- "generation-watch-plan.js": "eb60660341f254adc224181ca19dbbb969ef1d676aeaab60b71a8567f52648fe",
66
- "index.js": "da7d35f2685fa0d5e716073f20725d7a5a4a0c477a1982b106a314662641b989",
67
- "magnific-api.js": "39fa9a122577029111965c3e8487565c88ce46b61dec5ca685acf1c76cd3b636",
68
- "network.js": "b45e43b49eea98ca7d80921ebfa6daf8b0a85d2079d4653f9eda682bc82101ae",
69
- "package.json": "10ded9e89c13b500208717610984fd837e67e82ac3b31b21fe0058bd53c22a96",
70
- "state-store.js": "c3ee744509f7a6be251cd895406bd1c70827f53cbdc1ac9d1c2a6e48479bfe1e",
71
- "test/magnific-mcp.test.js": "c6345e70a7834a22df49abaf648c781f4da2e4d0790cbc13035c8af433c814c5",
72
- "tool.manifest.json": "bbb24f54814c67f1ca1e119e6767e59d48f8e0cbc7f92444cf8e22fcc2fe06ed"
73
- }
74
- },
75
- "campaign-draft-runner": {
76
- "version": "0.1.0",
148
+ "official-tool-sync": {
149
+ "version": "1.0.0",
77
150
  "toolDependencies": {
78
- "pr-campaign": "^0.1.0",
79
- "gmail-workspace": "^0.1.0"
151
+ "trash": "^1.0.0"
80
152
  },
81
153
  "files": {
82
- "README.md": "4e97db605c55c31c5fdb3ad83973f7733cef7a689b71b6d014fe07df631a4f99",
83
- "config.js": "3c0c252baa7170e0bf0a9d1a7ecdb4febcf19f7baf0fcd320c0b852008f41b63",
84
- "index.js": "0fd4574c70e7d008714f17eb54ccc34bc703a1fee7ab7eae768d79f86d2e747c",
85
- "package.json": "a25b7ed1dd2c30cd68c3c10feb8ee1752cac8cd55cd4344690ffad649e231ec1",
86
- "test/selection-policy.test.js": "b1bc804ba2be210230e78d7e4cfa5469e07e75c6ee944f58d77e6d00e88561cd",
87
- "tool.manifest.json": "2609869985fd78000c999a9ae03f4b251c0aa945d19eed97e630f70da97c72ce"
154
+ ".gitignore": "4d56952b0fb13bf8f9b6c13a6d4c34a075bac3af447636a1df4335d7576e2f97",
155
+ "config.js": "744c445b1d2ff65b77f38a5473c24e50a32f4288c4a08c25a874a478086c08c8",
156
+ "index.js": "fdd4167c63cd33c8e7640cb7ce09fd618dbd416030aa920407392e4591543e94",
157
+ "package.json": "4447cb5d4e0a04526604dfb9820c44af88349c27e208f27baa148686846559da",
158
+ "sync-lib.js": "c9f2cd7e19370088ab5fd10f6b2ada52c07d2e405674a356d0989f9a0f4984f6",
159
+ "sync-lib.test.js": "c97cf850d9f42f6b121a458863b048bdcaa6d7d0475642f20742c5862ebf7cc4",
160
+ "tool.manifest.json": "8e0f94ad786bdaf9edb1a65cd03438e26c1e9927e8db9a5a39e349e7ef3c6cd3"
88
161
  }
89
162
  },
90
163
  "pr-campaign": {
@@ -99,15 +172,44 @@
99
172
  "tool.manifest.json": "9c68d89276996039b055c43b4b4f82499ea684edbb36d9bfedcc909a3a23a80f"
100
173
  }
101
174
  },
102
- "gmail-workspace": {
175
+ "process-retrospective": {
176
+ "version": "1.1.0",
177
+ "files": {
178
+ "README.md": "798c5c34893dccabe2101be91581b1845359fb57744efcc56a2b5beb83712c15",
179
+ "config.js": "30703e809f0a2c4b85ffb1e1f9cd7ee599224e9bc62c3bc19e71e271cbc72b5d",
180
+ "index.js": "9bd1ae078293211387ee3035b4c4dc7cc5852d08503cd55cf5fb3187cf1ace34",
181
+ "package.json": "491b490a8c7f5db0fef1202f5d3059f1cc2dd75a84c6668f9fd2f5c81c1a4240",
182
+ "reflection-plan.js": "6c7e088385d39d2e3ba4f74c2d6dd94194e6a506f4ac263e552d34d9c2335488",
183
+ "state-store.js": "6d0d39bff7e5e16558123c088eb8946bf3758596ae974598936b94424618c7cf",
184
+ "test/reflection-plan.test.js": "d7c5953b5c5ba6fed4c403d64affce3f2b70b7975c1f28edcd1b902651fbe727",
185
+ "tool.manifest.json": "33440c26660f74dc381c4b4cc5f8487f4764693a352d37ae7ae2ef67e669754f"
186
+ }
187
+ },
188
+ "telemetry-ledger": {
103
189
  "version": "0.1.0",
104
190
  "files": {
105
- "config.js": "6ad295ec4cedbc936835d8f86c7528e0939ef09d5792c003308d2ee85dc5eea4",
106
- "index.js": "495b5cec129a71638ab9b2682cf575eb8659e9a100b2e70deb0c523e60b69886",
107
- "package.json": "1e88d42180a8dacd08c7ad1aa84d783991f901bb3bca7f0dddc4efd919470bdc",
108
- "secretary-state.js": "0c4ef04db0d990a92b4b49ef62135baea76b7e4d5c232dfbf2087c61d1ce1948",
109
- "test/secretary-state.test.mjs": "d8e866400853b39dc26e4b4ec09880c3cb1dd0b0091b2d25097388adf38559e7",
110
- "tool.manifest.json": "93583b8c3a5f417435e3b3e88b129d2c610f2f168788e510f4cb2c03d4aef3a4"
191
+ "README.md": "4cf1b8c7addaa0f6a2d802a7ae261293822c2662efac9c10afa844f9fbcf4e1d",
192
+ "analysis.js": "c0effbff3af519b018e59c0460d2c277b4f7e1422ca2680de217bcb5e8a13136",
193
+ "config.js": "ddc8543cde5aeda634b8df60628d0024bb03e65b8710cf4878b4c6a7d953a641",
194
+ "index.js": "7df14d142a70b725b32ee40741ce1007fd96a080f96a9b2e3e34d917d88621b5",
195
+ "package.json": "e662652038c1c5a6a2a4502b308ae89e1acbd3cb6d3fc494512a730ebe9ccb8a",
196
+ "stats.js": "fc41b065d1f280dc278c53dc4c4baaa385a5bf25416c3e4ff8a153ea624967fb",
197
+ "storage.js": "099187e270ccc2bd6d7300b78a2ee31a837f98694a23a3b40b20a646cdb1db1e",
198
+ "test/telemetry.test.js": "312eef22ad960b19a6fe777aecd520952ae20ed03168edbbef8a0f747bee01c0",
199
+ "tool.manifest.json": "e4b321a56db9030e5b39b764547769c76bcf282ed019ebba0323bf16a73dbe05",
200
+ "validation.js": "1a50c75a5ca1bb7249bb8bfc3f2927b31ff4accd0efb56a48c36df5adae78f61"
201
+ }
202
+ },
203
+ "trash": {
204
+ "version": "1.0.0",
205
+ "files": {
206
+ ".gitignore": "4d56952b0fb13bf8f9b6c13a6d4c34a075bac3af447636a1df4335d7576e2f97",
207
+ "config.js": "ad76578e9dcc05c2e45854de9fa2cd41285fd8dcdb9a7d9ee2056e0f8b2d68d6",
208
+ "index.js": "d562d2466bddc93dd9a3bc5455962a3457c50368ee5dde0607cae3ff5a88578a",
209
+ "package.json": "18ec594d43b6595c587b16125b9ce0c9426fdf00a28d7e342834e31e360575f8",
210
+ "tool.manifest.json": "4f236d274c891b55e4445d459cff6a3337a5d13adc5e8aca7fb965ff6aba4e4d",
211
+ "trash-store.js": "1318e0f9539292684c0c2ec2f1b7189f066fdba42f78e07821b067792f40e8c9",
212
+ "trash-store.test.js": "5647edba4ab5e5492764ccf8ba3e674e42b63942623d779b0bf69465c5adb53f"
111
213
  }
112
214
  },
113
215
  "x-campaign-runner": {
@@ -126,66 +228,16 @@
126
228
  },
127
229
  "x-dm": {
128
230
  "version": "0.2.0",
231
+ "toolDependencies": {
232
+ "browser-session-bridge": "^0.1.0"
233
+ },
129
234
  "files": {
130
- "README.md": "f02835c10d822ce906df121441761de8c6d61c3a4aac3f9aa9a6d9211b73a6ea",
131
235
  "config.js": "69a2dcccd10aa2f1ddcc24d52f4ce8fe4a6f5f5a85be64abbdf9dc9e19de0cd4",
132
- "index.js": "cf4f92e94b9f21f6fcfed7d8d2926105a11b4ad621e2121c762d9c1e67a91456",
236
+ "index.js": "83e3eb7fbeea8a5183303e0e56b1d6854ca7ccb800e4cd2ad689a5f13637380f",
133
237
  "package.json": "3a76a921b1e78e91b1d2a5ae1926b298dfd6b4ee3f716d5382159b474ee400f4",
238
+ "README.md": "503b0ed25ef9a8df3079523ea653178e6e029854b4d199cb8d20be82cc837f9e",
134
239
  "test/x-dm.test.mjs": "06352996e14777358eb62ad5e5d757b0dab5c0696927ed54ff40a5b7cdefcfd0",
135
- "tool.manifest.json": "f3b2e613562e4dd0f88d196c4e3caf525a425483133a54351300ce284a5836a9"
136
- }
137
- },
138
- "official-tool-sync": {
139
- "version": "1.0.0",
140
- "toolDependencies": {
141
- "trash": "^1.0.0"
142
- },
143
- "files": {
144
- ".gitignore": "4d56952b0fb13bf8f9b6c13a6d4c34a075bac3af447636a1df4335d7576e2f97",
145
- "config.js": "744c445b1d2ff65b77f38a5473c24e50a32f4288c4a08c25a874a478086c08c8",
146
- "index.js": "fdd4167c63cd33c8e7640cb7ce09fd618dbd416030aa920407392e4591543e94",
147
- "package.json": "4447cb5d4e0a04526604dfb9820c44af88349c27e208f27baa148686846559da",
148
- "sync-lib.js": "c9f2cd7e19370088ab5fd10f6b2ada52c07d2e405674a356d0989f9a0f4984f6",
149
- "sync-lib.test.js": "c97cf850d9f42f6b121a458863b048bdcaa6d7d0475642f20742c5862ebf7cc4",
150
- "tool.manifest.json": "8e0f94ad786bdaf9edb1a65cd03438e26c1e9927e8db9a5a39e349e7ef3c6cd3"
151
- }
152
- },
153
- "trash": {
154
- "version": "1.0.0",
155
- "files": {
156
- ".gitignore": "4d56952b0fb13bf8f9b6c13a6d4c34a075bac3af447636a1df4335d7576e2f97",
157
- "config.js": "ad76578e9dcc05c2e45854de9fa2cd41285fd8dcdb9a7d9ee2056e0f8b2d68d6",
158
- "index.js": "d562d2466bddc93dd9a3bc5455962a3457c50368ee5dde0607cae3ff5a88578a",
159
- "package.json": "18ec594d43b6595c587b16125b9ce0c9426fdf00a28d7e342834e31e360575f8",
160
- "tool.manifest.json": "4f236d274c891b55e4445d459cff6a3337a5d13adc5e8aca7fb965ff6aba4e4d",
161
- "trash-store.js": "1318e0f9539292684c0c2ec2f1b7189f066fdba42f78e07821b067792f40e8c9",
162
- "trash-store.test.js": "5647edba4ab5e5492764ccf8ba3e674e42b63942623d779b0bf69465c5adb53f"
163
- }
164
- },
165
- "process-retrospective": {
166
- "version": "1.0.0",
167
- "files": {
168
- "README.md": "7fa901adf532dbd1bb337a8019b0bd73978eef3b1ded51ffb24a3279d107056d",
169
- "config.js": "30703e809f0a2c4b85ffb1e1f9cd7ee599224e9bc62c3bc19e71e271cbc72b5d",
170
- "index.js": "9bd1ae078293211387ee3035b4c4dc7cc5852d08503cd55cf5fb3187cf1ace34",
171
- "package.json": "e3978089354004e495b7c7f4b4edd9c0984b34f68229d0dfdafbb2e606d48c8d",
172
- "reflection-plan.js": "ae78b47f5108993395fe9a6f1ff2eea0663a07ae1100780f9a63107fd6402314",
173
- "state-store.js": "6d0d39bff7e5e16558123c088eb8946bf3758596ae974598936b94424618c7cf",
174
- "test/reflection-plan.test.js": "d4e960948fc76aaed03651652a592ee4b3109abbb91693d415945cbb79642237",
175
- "tool.manifest.json": "4304208986be075c95c6d71aa97d301fd266af18fef1b6ddac4cf004e38427e7"
176
- }
177
- },
178
- "creator-scout": {
179
- "version": "1.0.1",
180
- "files": {
181
- "README.md": "4f50850317c0875ad7ddea767c7dda112669112bec107a98e67a31a42787b82c",
182
- "config.js": "bab728665650b986c0eaef8e1be1c259ec42b1f83df4217c9780f5468d3c7666",
183
- "index.js": "d1266d622b6abaf77ce1fe93823d4f2faedb8a5991371997c364082a198dc728",
184
- "package-lock.json": "ed479120b59c2d9b083991dea60eb7750ba36bc7b2c7defb01cfb598889b8d90",
185
- "package.json": "ad463eeddea6a958ef291d58f216c0b42c5ff3b398b62ed9512b857ea5e4b672",
186
- "reference-match.js": "762d822ad31f89c06cb5a40f84ba3f864436db486375ed30e48bde94de282c7c",
187
- "test/reference-match.test.js": "701ce83396126b1e42bd3a54e331ff011a1fc27646a0f3aa99ce1c3e576aff6d",
188
- "tool.manifest.json": "0617b0488035fd7f8a83a8e5a698558b3d0e956e7ea1e043e2e80bb224d4974f"
240
+ "tool.manifest.json": "177e0abac770f89a0f06aa445363393fa38e7f05ad7cd773ea907fa56faed505"
189
241
  }
190
242
  }
191
243
  }
@@ -193,7 +193,6 @@ export async function inspectSystemResources({ diskPath = arisaHomeDir } = {}) {
193
193
 
194
194
  function assertDoctorPolicy(policy) {
195
195
  const positiveValues = [
196
- "contextInspectionTimeoutMs",
197
196
  "contextWarningPercent",
198
197
  "contextCriticalPercent",
199
198
  "contextInefficientMinTokens",
@@ -318,9 +317,7 @@ export async function runDoctor({
318
317
  inspectToolDependencies = null
319
318
  }) {
320
319
  assertDoctorPolicy(doctorPolicy);
321
- const runtime = await agentManager.getRuntimeDiagnostic({
322
- contextInspectionTimeoutMs: doctorPolicy.contextInspectionTimeoutMs
323
- });
320
+ const runtime = await agentManager.getRuntimeDiagnostic();
324
321
  const report = {
325
322
  runtime,
326
323
  contexts: runtime.contexts.map((context) => evaluateContext(context, doctorPolicy)),
@@ -1,5 +1,4 @@
1
- import path from "node:path";
2
- import { unlink } from "node:fs/promises";
1
+ import { materializeToolOutput } from "../core/tools/tool-output-materializer.js";
3
2
 
4
3
  export function createHeadlessToolExecutor({ artifactStore, taskStore, toolRegistry } = {}) {
5
4
  if (!artifactStore || !taskStore || !toolRegistry) {
@@ -10,36 +9,7 @@ export function createHeadlessToolExecutor({ artifactStore, taskStore, toolRegis
10
9
  async runTool({ name, request, chatId }) {
11
10
  await toolRegistry.load();
12
11
  const result = await toolRegistry.run({ name, request, chatId });
13
- const chatArtifacts = artifactStore.forChat(chatId);
14
-
15
- if (result.output?.text) {
16
- const artifact = await chatArtifacts.createText({
17
- text: result.output.text,
18
- source: { type: "tool", toolName: name },
19
- metadata: { tool: name }
20
- });
21
- result.output.artifactId = artifact.id;
22
- }
23
- if (result.output?.filePath) {
24
- const generated = await chatArtifacts.createFromFile({
25
- originalPath: result.output.filePath,
26
- fileName: result.output.fileName || path.basename(result.output.filePath),
27
- kind: result.output.kind || "file",
28
- mimeType: result.output.mimeType || "application/octet-stream",
29
- source: { type: "tool", toolName: name },
30
- metadata: { tool: name, delivery: result.output.delivery }
31
- });
32
- result.output.artifactId = generated.id;
33
- await unlink(result.output.filePath).catch(() => {});
34
- }
35
- if (result.asyncTask || result.asyncTasks?.length) {
36
- result.asyncTasks = await taskStore.addMany(result.asyncTasks || [result.asyncTask], {
37
- payload: { chatId },
38
- source: { type: "tool", toolName: name, chatId }
39
- });
40
- delete result.asyncTask;
41
- }
42
- return result;
12
+ return materializeToolOutput({ result, name, chatId, artifactStore, taskStore });
43
13
  }
44
14
  };
45
15
  }
@@ -13,6 +13,8 @@ export const configFile = path.join(stateDir, "config.json");
13
13
  export const piAuthFile = path.join(stateDir, "pi-auth.json");
14
14
  export const servicePidFile = path.join(stateDir, "arisa.pid");
15
15
  export const serviceLogFile = path.join(stateDir, "arisa.log");
16
+ export const restartReceiptFile = path.join(stateDir, "restart-receipt.json");
17
+ export const sessionStartOperationalNotesFile = path.join(stateDir, "session-start-operational-notes.json");
16
18
  export function createIpcSocketPath({ homeDir = arisaHomeDir, platform = process.platform } = {}) {
17
19
  if (platform === "win32") {
18
20
  const suffix = crypto.createHash("sha256").update(homeDir).digest("hex").slice(0, 16);
@@ -47,7 +49,11 @@ export function getChatArtifactsIndexFile(chatId) {
47
49
  return path.join(getChatDir(chatId), "state", "artifacts.json");
48
50
  }
49
51
 
50
- export function getChatConversationHistoryFile(chatId) {
52
+ export function getChatSessionSeedFile(chatId) {
53
+ return path.join(getChatDir(chatId), "state", "session-seed.jsonl");
54
+ }
55
+
56
+ export function getChatLegacyConversationHistoryFile(chatId) {
51
57
  return path.join(getChatDir(chatId), "state", "conversation.jsonl");
52
58
  }
53
59
 
@@ -0,0 +1,90 @@
1
+ import crypto from "node:crypto";
2
+ import { execFile } from "node:child_process";
3
+ import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { promisify } from "node:util";
6
+ import { arisaPackageDir, restartReceiptFile } from "./paths.js";
7
+
8
+ const execFileAsync = promisify(execFile);
9
+
10
+ function normalizeDestination({ transportChatId, threadId = null }) {
11
+ const chatId = Number(transportChatId);
12
+ if (!Number.isSafeInteger(chatId)) throw new Error("Restart receipt requires a valid Telegram chat id");
13
+ const topic = threadId == null ? null : Number(threadId);
14
+ if (topic != null && (!Number.isSafeInteger(topic) || topic <= 0)) {
15
+ throw new Error("Restart receipt requires a valid Telegram topic id");
16
+ }
17
+ return { transportChatId: chatId, threadId: topic };
18
+ }
19
+
20
+ async function runtimeIdentity() {
21
+ const packageJson = JSON.parse(await readFile(path.join(arisaPackageDir, "package.json"), "utf8"));
22
+ let commit = null;
23
+ try {
24
+ const result = await execFileAsync("git", ["rev-parse", "--short=12", "HEAD"], { cwd: arisaPackageDir });
25
+ commit = String(result.stdout || "").trim() || null;
26
+ } catch {}
27
+ return { version: String(packageJson.version || "unknown"), commit };
28
+ }
29
+
30
+ export async function prepareRestartReceipt(destination, { reason = "requested restart" } = {}, {
31
+ receiptFile = restartReceiptFile,
32
+ getIdentity = runtimeIdentity
33
+ } = {}) {
34
+ const target = normalizeDestination(destination);
35
+ const identity = await getIdentity();
36
+ const receipt = {
37
+ id: crypto.randomUUID(),
38
+ ...target,
39
+ reason: String(reason || "requested restart").slice(0, 500),
40
+ expectedVersion: identity.version,
41
+ expectedCommit: identity.commit,
42
+ requestedAt: new Date().toISOString()
43
+ };
44
+ await mkdir(path.dirname(receiptFile), { recursive: true, mode: 0o700 });
45
+ const temporaryFile = `${receiptFile}.${process.pid}.tmp`;
46
+ await writeFile(temporaryFile, `${JSON.stringify(receipt, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
47
+ await rename(temporaryFile, receiptFile);
48
+ return receipt;
49
+ }
50
+
51
+ export async function cancelRestartReceipt(receiptId, { receiptFile = restartReceiptFile } = {}) {
52
+ try {
53
+ const receipt = JSON.parse(await readFile(receiptFile, "utf8"));
54
+ if (receipt.id !== receiptId) return false;
55
+ await rm(receiptFile, { force: true });
56
+ return true;
57
+ } catch (error) {
58
+ if (error?.code === "ENOENT") return false;
59
+ throw error;
60
+ }
61
+ }
62
+
63
+ export async function deliverRestartReceipt(sendMessage, {
64
+ receiptFile = restartReceiptFile,
65
+ getIdentity = runtimeIdentity
66
+ } = {}) {
67
+ let receipt;
68
+ try {
69
+ receipt = JSON.parse(await readFile(receiptFile, "utf8"));
70
+ } catch (error) {
71
+ if (error?.code === "ENOENT") return null;
72
+ throw error;
73
+ }
74
+
75
+ const actual = await getIdentity();
76
+ const versionMatches = receipt.expectedVersion === actual.version;
77
+ const commitMatches = !receipt.expectedCommit || receipt.expectedCommit === actual.commit;
78
+ const genericReasons = new Set(["requested restart", "Agent-requested restart", "Telegram restart", "Telegram /restart", "Telegram update restart"]);
79
+ const resultSummary = String(receipt.reason || "").trim();
80
+ const lines = [
81
+ versionMatches && commitMatches ? "Restart completed." : "Restart completed with an unexpected runtime identity.",
82
+ resultSummary && !genericReasons.has(resultSummary) ? resultSummary : null,
83
+ `Arisa ${actual.version} is running${actual.commit ? ` at commit ${actual.commit}` : ""}.`,
84
+ versionMatches && commitMatches ? null : `Expected: ${receipt.expectedVersion}${receipt.expectedCommit ? ` at ${receipt.expectedCommit}` : ""}.`
85
+ ].filter(Boolean);
86
+ const options = receipt.threadId ? { message_thread_id: receipt.threadId } : {};
87
+ await sendMessage(receipt.transportChatId, lines.join("\n"), options);
88
+ await rm(receiptFile, { force: true });
89
+ return { receipt, actual, verified: versionMatches && commitMatches };
90
+ }