@asermax/tachikoma 2.0.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.
Files changed (345) hide show
  1. package/README.md +64 -0
  2. package/dist/agent/adapter.d.ts +8 -0
  3. package/dist/agent/adapter.js +86 -0
  4. package/dist/agent/adapter.js.map +1 -0
  5. package/dist/agent/manager.d.ts +35 -0
  6. package/dist/agent/manager.js +76 -0
  7. package/dist/agent/manager.js.map +1 -0
  8. package/dist/agent/models.d.ts +46 -0
  9. package/dist/agent/models.js +96 -0
  10. package/dist/agent/models.js.map +1 -0
  11. package/dist/agent/side-run.d.ts +42 -0
  12. package/dist/agent/side-run.js +83 -0
  13. package/dist/agent/side-run.js.map +1 -0
  14. package/dist/app.d.ts +5 -0
  15. package/dist/app.js +79 -0
  16. package/dist/app.js.map +1 -0
  17. package/dist/channels/types.d.ts +37 -0
  18. package/dist/channels/types.js +5 -0
  19. package/dist/channels/types.js.map +1 -0
  20. package/dist/config/default-template.d.ts +1 -0
  21. package/dist/config/default-template.js +49 -0
  22. package/dist/config/default-template.js.map +1 -0
  23. package/dist/config/load.d.ts +8 -0
  24. package/dist/config/load.js +28 -0
  25. package/dist/config/load.js.map +1 -0
  26. package/dist/config/parse.d.ts +5 -0
  27. package/dist/config/parse.js +18 -0
  28. package/dist/config/parse.js.map +1 -0
  29. package/dist/config/schema.d.ts +29 -0
  30. package/dist/config/schema.js +35 -0
  31. package/dist/config/schema.js.map +1 -0
  32. package/dist/coordinator.d.ts +54 -0
  33. package/dist/coordinator.js +344 -0
  34. package/dist/coordinator.js.map +1 -0
  35. package/dist/db/core-schema.d.ts +250 -0
  36. package/dist/db/core-schema.js +19 -0
  37. package/dist/db/core-schema.js.map +1 -0
  38. package/dist/db/index.d.ts +8 -0
  39. package/dist/db/index.js +16 -0
  40. package/dist/db/index.js.map +1 -0
  41. package/dist/db/schema.d.ts +4 -0
  42. package/dist/db/schema.js +7 -0
  43. package/dist/db/schema.js.map +1 -0
  44. package/dist/db/state.d.ts +10 -0
  45. package/dist/db/state.js +36 -0
  46. package/dist/db/state.js.map +1 -0
  47. package/dist/domain/agent-events.d.ts +26 -0
  48. package/dist/domain/agent-events.js +2 -0
  49. package/dist/domain/agent-events.js.map +1 -0
  50. package/dist/domain/message.d.ts +25 -0
  51. package/dist/domain/message.js +17 -0
  52. package/dist/domain/message.js.map +1 -0
  53. package/dist/events.d.ts +9 -0
  54. package/dist/events.js +27 -0
  55. package/dist/events.js.map +1 -0
  56. package/dist/extensions/api.d.ts +118 -0
  57. package/dist/extensions/api.js +7 -0
  58. package/dist/extensions/api.js.map +1 -0
  59. package/dist/extensions/boundary/detector.d.ts +20 -0
  60. package/dist/extensions/boundary/detector.js +57 -0
  61. package/dist/extensions/boundary/detector.js.map +1 -0
  62. package/dist/extensions/boundary/idle.d.ts +10 -0
  63. package/dist/extensions/boundary/idle.js +28 -0
  64. package/dist/extensions/boundary/idle.js.map +1 -0
  65. package/dist/extensions/boundary/index.d.ts +12 -0
  66. package/dist/extensions/boundary/index.js +65 -0
  67. package/dist/extensions/boundary/index.js.map +1 -0
  68. package/dist/extensions/boundary/summary.d.ts +5 -0
  69. package/dist/extensions/boundary/summary.js +33 -0
  70. package/dist/extensions/boundary/summary.js.map +1 -0
  71. package/dist/extensions/commands/index.d.ts +7 -0
  72. package/dist/extensions/commands/index.js +21 -0
  73. package/dist/extensions/commands/index.js.map +1 -0
  74. package/dist/extensions/context/index.d.ts +7 -0
  75. package/dist/extensions/context/index.js +65 -0
  76. package/dist/extensions/context/index.js.map +1 -0
  77. package/dist/extensions/context/processor.d.ts +27 -0
  78. package/dist/extensions/context/processor.js +228 -0
  79. package/dist/extensions/context/processor.js.map +1 -0
  80. package/dist/extensions/detached-processes/index.d.ts +12 -0
  81. package/dist/extensions/detached-processes/index.js +51 -0
  82. package/dist/extensions/detached-processes/index.js.map +1 -0
  83. package/dist/extensions/detached-processes/limits.d.ts +27 -0
  84. package/dist/extensions/detached-processes/limits.js +55 -0
  85. package/dist/extensions/detached-processes/limits.js.map +1 -0
  86. package/dist/extensions/detached-processes/output.d.ts +2 -0
  87. package/dist/extensions/detached-processes/output.js +26 -0
  88. package/dist/extensions/detached-processes/output.js.map +1 -0
  89. package/dist/extensions/detached-processes/reconcile.d.ts +31 -0
  90. package/dist/extensions/detached-processes/reconcile.js +71 -0
  91. package/dist/extensions/detached-processes/reconcile.js.map +1 -0
  92. package/dist/extensions/detached-processes/repository.d.ts +33 -0
  93. package/dist/extensions/detached-processes/repository.js +62 -0
  94. package/dist/extensions/detached-processes/repository.js.map +1 -0
  95. package/dist/extensions/detached-processes/schema.d.ts +252 -0
  96. package/dist/extensions/detached-processes/schema.js +23 -0
  97. package/dist/extensions/detached-processes/schema.js.map +1 -0
  98. package/dist/extensions/detached-processes/spawn.d.ts +40 -0
  99. package/dist/extensions/detached-processes/spawn.js +137 -0
  100. package/dist/extensions/detached-processes/spawn.js.map +1 -0
  101. package/dist/extensions/detached-processes/tools.d.ts +41 -0
  102. package/dist/extensions/detached-processes/tools.js +243 -0
  103. package/dist/extensions/detached-processes/tools.js.map +1 -0
  104. package/dist/extensions/detached-processes/watcher.d.ts +7 -0
  105. package/dist/extensions/detached-processes/watcher.js +19 -0
  106. package/dist/extensions/detached-processes/watcher.js.map +1 -0
  107. package/dist/extensions/external/index.d.ts +11 -0
  108. package/dist/extensions/external/index.js +40 -0
  109. package/dist/extensions/external/index.js.map +1 -0
  110. package/dist/extensions/external/installs.d.ts +39 -0
  111. package/dist/extensions/external/installs.js +98 -0
  112. package/dist/extensions/external/installs.js.map +1 -0
  113. package/dist/extensions/external/loader.d.ts +19 -0
  114. package/dist/extensions/external/loader.js +70 -0
  115. package/dist/extensions/external/loader.js.map +1 -0
  116. package/dist/extensions/external/tools.d.ts +17 -0
  117. package/dist/extensions/external/tools.js +112 -0
  118. package/dist/extensions/external/tools.js.map +1 -0
  119. package/dist/extensions/git/commit.d.ts +19 -0
  120. package/dist/extensions/git/commit.js +44 -0
  121. package/dist/extensions/git/commit.js.map +1 -0
  122. package/dist/extensions/git/git.d.ts +11 -0
  123. package/dist/extensions/git/git.js +29 -0
  124. package/dist/extensions/git/git.js.map +1 -0
  125. package/dist/extensions/git/hooks.d.ts +10 -0
  126. package/dist/extensions/git/hooks.js +88 -0
  127. package/dist/extensions/git/hooks.js.map +1 -0
  128. package/dist/extensions/git/index.d.ts +11 -0
  129. package/dist/extensions/git/index.js +28 -0
  130. package/dist/extensions/git/index.js.map +1 -0
  131. package/dist/extensions/git/processor.d.ts +13 -0
  132. package/dist/extensions/git/processor.js +52 -0
  133. package/dist/extensions/git/processor.js.map +1 -0
  134. package/dist/extensions/git/sync.d.ts +44 -0
  135. package/dist/extensions/git/sync.js +189 -0
  136. package/dist/extensions/git/sync.js.map +1 -0
  137. package/dist/extensions/git/tools.d.ts +21 -0
  138. package/dist/extensions/git/tools.js +101 -0
  139. package/dist/extensions/git/tools.js.map +1 -0
  140. package/dist/extensions/host.d.ts +31 -0
  141. package/dist/extensions/host.js +75 -0
  142. package/dist/extensions/host.js.map +1 -0
  143. package/dist/extensions/index.d.ts +3 -0
  144. package/dist/extensions/index.js +32 -0
  145. package/dist/extensions/index.js.map +1 -0
  146. package/dist/extensions/memory/archive.d.ts +8 -0
  147. package/dist/extensions/memory/archive.js +46 -0
  148. package/dist/extensions/memory/archive.js.map +1 -0
  149. package/dist/extensions/memory/dates.d.ts +2 -0
  150. package/dist/extensions/memory/dates.js +7 -0
  151. package/dist/extensions/memory/dates.js.map +1 -0
  152. package/dist/extensions/memory/extraction.d.ts +17 -0
  153. package/dist/extensions/memory/extraction.js +218 -0
  154. package/dist/extensions/memory/extraction.js.map +1 -0
  155. package/dist/extensions/memory/index.d.ts +20 -0
  156. package/dist/extensions/memory/index.js +67 -0
  157. package/dist/extensions/memory/index.js.map +1 -0
  158. package/dist/extensions/memory/indexes.d.ts +14 -0
  159. package/dist/extensions/memory/indexes.js +64 -0
  160. package/dist/extensions/memory/indexes.js.map +1 -0
  161. package/dist/extensions/memory/layout.d.ts +20 -0
  162. package/dist/extensions/memory/layout.js +79 -0
  163. package/dist/extensions/memory/layout.js.map +1 -0
  164. package/dist/extensions/memory/maintenance.d.ts +21 -0
  165. package/dist/extensions/memory/maintenance.js +357 -0
  166. package/dist/extensions/memory/maintenance.js.map +1 -0
  167. package/dist/extensions/memory/prompts.d.ts +8 -0
  168. package/dist/extensions/memory/prompts.js +125 -0
  169. package/dist/extensions/memory/prompts.js.map +1 -0
  170. package/dist/extensions/memory/transcript.d.ts +18 -0
  171. package/dist/extensions/memory/transcript.js +79 -0
  172. package/dist/extensions/memory/transcript.js.map +1 -0
  173. package/dist/extensions/notifications/format.d.ts +5 -0
  174. package/dist/extensions/notifications/format.js +17 -0
  175. package/dist/extensions/notifications/format.js.map +1 -0
  176. package/dist/extensions/notifications/index.d.ts +13 -0
  177. package/dist/extensions/notifications/index.js +29 -0
  178. package/dist/extensions/notifications/index.js.map +1 -0
  179. package/dist/extensions/notifications/payload.d.ts +22 -0
  180. package/dist/extensions/notifications/payload.js +29 -0
  181. package/dist/extensions/notifications/payload.js.map +1 -0
  182. package/dist/extensions/notifications/router.d.ts +29 -0
  183. package/dist/extensions/notifications/router.js +55 -0
  184. package/dist/extensions/notifications/router.js.map +1 -0
  185. package/dist/extensions/notifications/tools.d.ts +12 -0
  186. package/dist/extensions/notifications/tools.js +41 -0
  187. package/dist/extensions/notifications/tools.js.map +1 -0
  188. package/dist/extensions/projects/context-provider.d.ts +9 -0
  189. package/dist/extensions/projects/context-provider.js +37 -0
  190. package/dist/extensions/projects/context-provider.js.map +1 -0
  191. package/dist/extensions/projects/git.d.ts +28 -0
  192. package/dist/extensions/projects/git.js +91 -0
  193. package/dist/extensions/projects/git.js.map +1 -0
  194. package/dist/extensions/projects/hooks.d.ts +7 -0
  195. package/dist/extensions/projects/hooks.js +42 -0
  196. package/dist/extensions/projects/hooks.js.map +1 -0
  197. package/dist/extensions/projects/index.d.ts +11 -0
  198. package/dist/extensions/projects/index.js +30 -0
  199. package/dist/extensions/projects/index.js.map +1 -0
  200. package/dist/extensions/projects/processor.d.ts +13 -0
  201. package/dist/extensions/projects/processor.js +63 -0
  202. package/dist/extensions/projects/processor.js.map +1 -0
  203. package/dist/extensions/projects/tools.d.ts +21 -0
  204. package/dist/extensions/projects/tools.js +118 -0
  205. package/dist/extensions/projects/tools.js.map +1 -0
  206. package/dist/extensions/registrations.d.ts +21 -0
  207. package/dist/extensions/registrations.js +12 -0
  208. package/dist/extensions/registrations.js.map +1 -0
  209. package/dist/extensions/repl/index.d.ts +2 -0
  210. package/dist/extensions/repl/index.js +85 -0
  211. package/dist/extensions/repl/index.js.map +1 -0
  212. package/dist/extensions/skills/agents.d.ts +17 -0
  213. package/dist/extensions/skills/agents.js +77 -0
  214. package/dist/extensions/skills/agents.js.map +1 -0
  215. package/dist/extensions/skills/delegate.d.ts +22 -0
  216. package/dist/extensions/skills/delegate.js +54 -0
  217. package/dist/extensions/skills/delegate.js.map +1 -0
  218. package/dist/extensions/skills/index.d.ts +11 -0
  219. package/dist/extensions/skills/index.js +43 -0
  220. package/dist/extensions/skills/index.js.map +1 -0
  221. package/dist/extensions/skills/reload.d.ts +8 -0
  222. package/dist/extensions/skills/reload.js +38 -0
  223. package/dist/extensions/skills/reload.js.map +1 -0
  224. package/dist/extensions/tasks/executor.d.ts +43 -0
  225. package/dist/extensions/tasks/executor.js +179 -0
  226. package/dist/extensions/tasks/executor.js.map +1 -0
  227. package/dist/extensions/tasks/expiration.d.ts +12 -0
  228. package/dist/extensions/tasks/expiration.js +17 -0
  229. package/dist/extensions/tasks/expiration.js.map +1 -0
  230. package/dist/extensions/tasks/generation.d.ts +14 -0
  231. package/dist/extensions/tasks/generation.js +70 -0
  232. package/dist/extensions/tasks/generation.js.map +1 -0
  233. package/dist/extensions/tasks/index.d.ts +14 -0
  234. package/dist/extensions/tasks/index.js +75 -0
  235. package/dist/extensions/tasks/index.js.map +1 -0
  236. package/dist/extensions/tasks/repository.d.ts +53 -0
  237. package/dist/extensions/tasks/repository.js +147 -0
  238. package/dist/extensions/tasks/repository.js.map +1 -0
  239. package/dist/extensions/tasks/schedule.d.ts +13 -0
  240. package/dist/extensions/tasks/schedule.js +32 -0
  241. package/dist/extensions/tasks/schedule.js.map +1 -0
  242. package/dist/extensions/tasks/schema.d.ts +423 -0
  243. package/dist/extensions/tasks/schema.js +45 -0
  244. package/dist/extensions/tasks/schema.js.map +1 -0
  245. package/dist/extensions/tasks/session-delivery.d.ts +18 -0
  246. package/dist/extensions/tasks/session-delivery.js +39 -0
  247. package/dist/extensions/tasks/session-delivery.js.map +1 -0
  248. package/dist/extensions/tasks/tools.d.ts +38 -0
  249. package/dist/extensions/tasks/tools.js +181 -0
  250. package/dist/extensions/tasks/tools.js.map +1 -0
  251. package/dist/extensions/telegram/buttons.d.ts +14 -0
  252. package/dist/extensions/telegram/buttons.js +49 -0
  253. package/dist/extensions/telegram/buttons.js.map +1 -0
  254. package/dist/extensions/telegram/channel.d.ts +39 -0
  255. package/dist/extensions/telegram/channel.js +201 -0
  256. package/dist/extensions/telegram/channel.js.map +1 -0
  257. package/dist/extensions/telegram/chunking.d.ts +7 -0
  258. package/dist/extensions/telegram/chunking.js +67 -0
  259. package/dist/extensions/telegram/chunking.js.map +1 -0
  260. package/dist/extensions/telegram/inbound.d.ts +7 -0
  261. package/dist/extensions/telegram/inbound.js +29 -0
  262. package/dist/extensions/telegram/inbound.js.map +1 -0
  263. package/dist/extensions/telegram/index.d.ts +13 -0
  264. package/dist/extensions/telegram/index.js +67 -0
  265. package/dist/extensions/telegram/index.js.map +1 -0
  266. package/dist/extensions/telegram/media.d.ts +39 -0
  267. package/dist/extensions/telegram/media.js +223 -0
  268. package/dist/extensions/telegram/media.js.map +1 -0
  269. package/dist/extensions/telegram/mutex.d.ts +9 -0
  270. package/dist/extensions/telegram/mutex.js +14 -0
  271. package/dist/extensions/telegram/mutex.js.map +1 -0
  272. package/dist/extensions/telegram/sending.d.ts +48 -0
  273. package/dist/extensions/telegram/sending.js +119 -0
  274. package/dist/extensions/telegram/sending.js.map +1 -0
  275. package/dist/extensions/telegram/streaming.d.ts +46 -0
  276. package/dist/extensions/telegram/streaming.js +140 -0
  277. package/dist/extensions/telegram/streaming.js.map +1 -0
  278. package/dist/extensions/telegram/tools.d.ts +80 -0
  279. package/dist/extensions/telegram/tools.js +232 -0
  280. package/dist/extensions/telegram/tools.js.map +1 -0
  281. package/dist/extensions/workflows/cleanup.d.ts +10 -0
  282. package/dist/extensions/workflows/cleanup.js +38 -0
  283. package/dist/extensions/workflows/cleanup.js.map +1 -0
  284. package/dist/extensions/workflows/index.d.ts +11 -0
  285. package/dist/extensions/workflows/index.js +42 -0
  286. package/dist/extensions/workflows/index.js.map +1 -0
  287. package/dist/extensions/workflows/loader.d.ts +27 -0
  288. package/dist/extensions/workflows/loader.js +90 -0
  289. package/dist/extensions/workflows/loader.js.map +1 -0
  290. package/dist/extensions/workflows/model.d.ts +19 -0
  291. package/dist/extensions/workflows/model.js +7 -0
  292. package/dist/extensions/workflows/model.js.map +1 -0
  293. package/dist/extensions/workflows/repository.d.ts +24 -0
  294. package/dist/extensions/workflows/repository.js +61 -0
  295. package/dist/extensions/workflows/repository.js.map +1 -0
  296. package/dist/extensions/workflows/schema.d.ts +193 -0
  297. package/dist/extensions/workflows/schema.js +20 -0
  298. package/dist/extensions/workflows/schema.js.map +1 -0
  299. package/dist/extensions/workflows/tools.d.ts +27 -0
  300. package/dist/extensions/workflows/tools.js +285 -0
  301. package/dist/extensions/workflows/tools.js.map +1 -0
  302. package/dist/log.d.ts +8 -0
  303. package/dist/log.js +15 -0
  304. package/dist/log.js.map +1 -0
  305. package/dist/main.d.ts +2 -0
  306. package/dist/main.js +27 -0
  307. package/dist/main.js.map +1 -0
  308. package/dist/migration/ask.d.ts +8 -0
  309. package/dist/migration/ask.js +24 -0
  310. package/dist/migration/ask.js.map +1 -0
  311. package/dist/migration/config.d.ts +10 -0
  312. package/dist/migration/config.js +122 -0
  313. package/dist/migration/config.js.map +1 -0
  314. package/dist/migration/context.d.ts +3 -0
  315. package/dist/migration/context.js +24 -0
  316. package/dist/migration/context.js.map +1 -0
  317. package/dist/migration/database.d.ts +8 -0
  318. package/dist/migration/database.js +51 -0
  319. package/dist/migration/database.js.map +1 -0
  320. package/dist/migration/fs.d.ts +1 -0
  321. package/dist/migration/fs.js +11 -0
  322. package/dist/migration/fs.js.map +1 -0
  323. package/dist/migration/index.d.ts +11 -0
  324. package/dist/migration/index.js +28 -0
  325. package/dist/migration/index.js.map +1 -0
  326. package/dist/migration/skills.d.ts +19 -0
  327. package/dist/migration/skills.js +77 -0
  328. package/dist/migration/skills.js.map +1 -0
  329. package/dist/scheduler.d.ts +17 -0
  330. package/dist/scheduler.js +53 -0
  331. package/dist/scheduler.js.map +1 -0
  332. package/dist/sessions/registry.d.ts +15 -0
  333. package/dist/sessions/registry.js +42 -0
  334. package/dist/sessions/registry.js.map +1 -0
  335. package/dist/workspace.d.ts +13 -0
  336. package/dist/workspace.js +32 -0
  337. package/dist/workspace.js.map +1 -0
  338. package/drizzle/0000_init.sql +19 -0
  339. package/drizzle/0001_extensions.sql +63 -0
  340. package/drizzle/meta/0000_snapshot.json +134 -0
  341. package/drizzle/meta/0001_snapshot.json +526 -0
  342. package/drizzle/meta/_journal.json +20 -0
  343. package/package.json +63 -0
  344. package/skills/skill-authoring/SKILL.md +168 -0
  345. package/skills/workflow-authoring/SKILL.md +251 -0
@@ -0,0 +1,243 @@
1
+ import { constants } from "node:os";
2
+ import { StringEnum } from "@earendil-works/pi-ai";
3
+ import { truncateTail } from "@earendil-works/pi-coding-agent";
4
+ import { Type } from "typebox";
5
+ import { readOutputTail } from "./output.js";
6
+ import { reconcileExit } from "./reconcile.js";
7
+ import { isAlive, spawnProcess, terminate } from "./spawn.js";
8
+ const reconcileDeps = (deps) => ({
9
+ repository: deps.repository,
10
+ processesDir: deps.processesDir,
11
+ notify: deps.notify,
12
+ log: deps.log,
13
+ now: deps.now,
14
+ });
15
+ export const DispatchProcessParams = Type.Object({
16
+ name: Type.String({ description: "Display label for the process (non-unique)" }),
17
+ command: Type.String({ description: "Shell command to run (supports pipes, &&, etc.)" }),
18
+ cwd: Type.Optional(Type.String({ description: "Working directory (defaults to Tachikoma's)" })),
19
+ env: Type.Optional(Type.Record(Type.String(), Type.String(), {
20
+ description: "Environment variable overrides merged onto the OS environment",
21
+ })),
22
+ memory_limit_mb: Type.Optional(Type.Number({ description: "Memory limit in MB (overrides the configured default)" })),
23
+ });
24
+ export const QueryProcessParams = Type.Object({
25
+ process_id: Type.Optional(Type.String({ description: "ID of a specific process to inspect; omit to list" })),
26
+ archived: Type.Optional(Type.Boolean({ description: "When listing, set true to show exited processes" })),
27
+ });
28
+ export const ReadProcessOutputParams = Type.Object({
29
+ process_id: Type.String({ description: "ID of the process" }),
30
+ stream: Type.Optional(StringEnum(["stdout", "stderr"], {
31
+ description: "Which output stream to read (default stdout)",
32
+ })),
33
+ });
34
+ export const TerminateProcessParams = Type.Object({
35
+ process_id: Type.String({ description: "ID of the process to terminate" }),
36
+ signal: Type.Optional(Type.String({ description: "Signal name (default SIGTERM), e.g. SIGTERM, SIGINT, SIGKILL" })),
37
+ grace_seconds: Type.Optional(Type.Number({
38
+ description: "Seconds before escalating to SIGKILL (default 10); 0 = signal and return",
39
+ })),
40
+ });
41
+ const notFound = (processId) => new Error(`Process '${processId}' not found.`);
42
+ const describeProcess = (record) => {
43
+ const lines = [
44
+ `- [${record.id}] **${record.name}** (pid ${record.pid}) ${record.status}`,
45
+ ` Command: ${record.command}`,
46
+ ` Started: ${record.startedAt.toISOString()}`,
47
+ ];
48
+ if (record.exitedAt != null) {
49
+ lines.push(` Exited: ${record.exitedAt.toISOString()} (code: ${record.exitCode ?? "unknown"})`);
50
+ }
51
+ lines.push("");
52
+ return lines;
53
+ };
54
+ export const handleDispatchProcess = async (deps, args) => {
55
+ if (args.memory_limit_mb != null && args.memory_limit_mb < 1) {
56
+ throw new Error(`Invalid memory_limit_mb: ${args.memory_limit_mb}. Minimum value is 1.`);
57
+ }
58
+ const record = await spawnProcess(deps, {
59
+ name: args.name,
60
+ command: args.command,
61
+ cwd: args.cwd,
62
+ env: args.env,
63
+ memoryLimitMb: args.memory_limit_mb ?? deps.defaultMemoryLimitMb,
64
+ });
65
+ return [
66
+ `Process '${record.name}' started.`,
67
+ `- ID: ${record.id}`,
68
+ `- PID: ${record.pid}`,
69
+ `- Stdout: ${record.stdoutPath}`,
70
+ `- Stderr: ${record.stderrPath}`,
71
+ ].join("\n");
72
+ };
73
+ export const handleQueryProcess = async (deps, args) => {
74
+ const { repository } = deps;
75
+ if (args.process_id != null) {
76
+ let record = repository.get(args.process_id);
77
+ if (record == null)
78
+ throw notFound(args.process_id);
79
+ if (record.status === "running" && !isAlive(record.pid)) {
80
+ await reconcileExit(reconcileDeps(deps), record.id);
81
+ record = repository.get(args.process_id);
82
+ if (record == null)
83
+ throw notFound(args.process_id);
84
+ }
85
+ const lines = [
86
+ `# ${record.name}`,
87
+ "",
88
+ `- ID: ${record.id}`,
89
+ `- Status: ${record.status}`,
90
+ `- PID: ${record.pid}`,
91
+ `- Command: ${record.command}`,
92
+ `- CWD: ${record.cwd}`,
93
+ `- Stdout: ${record.stdoutPath}`,
94
+ `- Stderr: ${record.stderrPath}`,
95
+ `- Started: ${record.startedAt.toISOString()}`,
96
+ ];
97
+ if (record.exitedAt != null) {
98
+ lines.push(`- Exited: ${record.exitedAt.toISOString()}`);
99
+ lines.push(`- Exit code: ${record.exitCode ?? "unknown"}`);
100
+ }
101
+ if (record.memoryLimitMb != null)
102
+ lines.push(`- Memory limit: ${record.memoryLimitMb}MB`);
103
+ return lines.join("\n");
104
+ }
105
+ let records;
106
+ if (args.archived === true) {
107
+ records = repository.listExited();
108
+ }
109
+ else {
110
+ records = [];
111
+ for (const record of repository.listRunning()) {
112
+ if (isAlive(record.pid)) {
113
+ records.push(record);
114
+ }
115
+ else {
116
+ await reconcileExit(reconcileDeps(deps), record.id);
117
+ }
118
+ }
119
+ }
120
+ if (records.length === 0) {
121
+ return `No ${args.archived === true ? "exited" : "running"} processes found.`;
122
+ }
123
+ return ["# Detached Processes", "", ...records.flatMap(describeProcess)].join("\n");
124
+ };
125
+ export const handleReadProcessOutput = async (deps, args) => {
126
+ const record = deps.repository.get(args.process_id);
127
+ if (record == null)
128
+ throw notFound(args.process_id);
129
+ const path = args.stream === "stderr" ? record.stderrPath : record.stdoutPath;
130
+ const raw = await readOutputTail(path);
131
+ if (raw == null || raw === "")
132
+ return "No output yet.";
133
+ const { content, truncated } = truncateTail(raw);
134
+ return truncated ? `[earlier output truncated]\n${content}` : content;
135
+ };
136
+ export const handleTerminateProcess = async (deps, args) => {
137
+ const { repository, log } = deps;
138
+ const graceSeconds = args.grace_seconds ?? 10;
139
+ let record = repository.get(args.process_id);
140
+ if (record == null)
141
+ throw notFound(args.process_id);
142
+ if (record.status === "running" && !isAlive(record.pid)) {
143
+ // Lazy reconcile — stop-initiated exits don't notify the user.
144
+ await reconcileExit(reconcileDeps(deps), record.id, { dispatchNotification: false });
145
+ record = repository.get(args.process_id);
146
+ if (record == null)
147
+ throw notFound(args.process_id);
148
+ return `Process '${record.name}' already stopped (exit code: ${record.exitCode ?? "unknown"}).`;
149
+ }
150
+ if (record.status === "exited") {
151
+ return `Process '${record.name}' already stopped (exit code: ${record.exitCode ?? "unknown"}).`;
152
+ }
153
+ const signal = (args.signal ?? "SIGTERM");
154
+ if (constants.signals[signal] == null)
155
+ throw new Error(`Unknown signal: ${args.signal}`);
156
+ try {
157
+ repository.markStopInitiated(record.id);
158
+ }
159
+ catch (error) {
160
+ log.error({ id: record.id, err: error }, "failed to mark stop initiated — signalling anyway");
161
+ }
162
+ try {
163
+ await terminate(record, log, { signal, graceSeconds });
164
+ }
165
+ catch (error) {
166
+ if (error.code === "EPERM") {
167
+ try {
168
+ repository.clearStopReason(record.id);
169
+ }
170
+ catch {
171
+ // Best effort — a stale stop reason only suppresses one notification.
172
+ }
173
+ throw new Error(`Permission denied: cannot signal process ${record.pid}.`);
174
+ }
175
+ throw error;
176
+ }
177
+ // grace 0 is fire-and-forget — the watcher will observe the exit.
178
+ if (graceSeconds === 0)
179
+ return `Signal sent to process '${record.name}'.`;
180
+ await reconcileExit(reconcileDeps(deps), record.id, { dispatchNotification: false });
181
+ const updated = repository.get(args.process_id);
182
+ return `Process '${record.name}' stopped (exit code: ${updated?.exitCode ?? "unknown"}).`;
183
+ };
184
+ const textResult = (text) => ({
185
+ content: [{ type: "text", text }],
186
+ details: undefined,
187
+ });
188
+ /** pi extension factory exposing the detached process management tools to the agent. */
189
+ export const createProcessToolsFactory = (deps) => (pi) => {
190
+ pi.registerTool({
191
+ name: "dispatch_detached_process",
192
+ label: "Dispatch Detached Process",
193
+ description: "Start a detached shell command that runs independently of Tachikoma and survives restarts. Output is captured to per-process stdout/stderr log files. Returns the record ID, PID, and log paths.",
194
+ promptSnippet: "Run long-lived shell commands detached from the conversation",
195
+ promptGuidelines: [
196
+ "Use dispatch_detached_process for long-running work (servers, builds, downloads) instead of blocking on bash.",
197
+ ],
198
+ parameters: DispatchProcessParams,
199
+ async execute(_toolCallId, params) {
200
+ return textResult(await handleDispatchProcess(deps, params));
201
+ },
202
+ });
203
+ pi.registerTool({
204
+ name: "query_process",
205
+ label: "Query Process",
206
+ description: "Inspect detached processes. With process_id, returns full details for that process; without it, lists running processes (archived=true lists exited ones). Each entry includes the ID needed by the other process tools.",
207
+ promptSnippet: "List or inspect detached processes",
208
+ promptGuidelines: [
209
+ "Check query_process before dispatch_detached_process to avoid starting duplicate work.",
210
+ ],
211
+ parameters: QueryProcessParams,
212
+ async execute(_toolCallId, params) {
213
+ return textResult(await handleQueryProcess(deps, params));
214
+ },
215
+ });
216
+ pi.registerTool({
217
+ name: "read_process_output",
218
+ label: "Read Process Output",
219
+ description: "Read the tail of a detached process's captured output. Defaults to stdout; pass stream='stderr' for the error stream. Large logs are truncated to the most recent output.",
220
+ promptSnippet: "Read captured output of a detached process",
221
+ promptGuidelines: [
222
+ "Use read_process_output to check on a detached process's progress or failures.",
223
+ ],
224
+ parameters: ReadProcessOutputParams,
225
+ async execute(_toolCallId, params) {
226
+ return textResult(await handleReadProcessOutput(deps, params));
227
+ },
228
+ });
229
+ pi.registerTool({
230
+ name: "terminate_process",
231
+ label: "Terminate Process",
232
+ description: "Stop a running detached process: sends the signal (default SIGTERM) to its process group and escalates to SIGKILL after grace_seconds. Reports 'already stopped' without error when the process has exited.",
233
+ promptSnippet: "Stop a running detached process",
234
+ promptGuidelines: [
235
+ "Use terminate_process when the user asks to stop, cancel, or kill a detached process.",
236
+ ],
237
+ parameters: TerminateProcessParams,
238
+ async execute(_toolCallId, params) {
239
+ return textResult(await handleTerminateProcess(deps, params));
240
+ },
241
+ });
242
+ };
243
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/extensions/detached-processes/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type ReconcileDeps } from "./reconcile.ts";
2
+ /**
3
+ * Polling watcher tick: check every running record for liveness and reconcile
4
+ * the dead ones. Per-record error isolation keeps one bad record from
5
+ * stopping the sweep.
6
+ */
7
+ export declare const createWatcherTick: (deps: ReconcileDeps) => () => Promise<void>;
@@ -0,0 +1,19 @@
1
+ import { reconcileExit } from "./reconcile.js";
2
+ import { isAlive } from "./spawn.js";
3
+ /**
4
+ * Polling watcher tick: check every running record for liveness and reconcile
5
+ * the dead ones. Per-record error isolation keeps one bad record from
6
+ * stopping the sweep.
7
+ */
8
+ export const createWatcherTick = (deps) => async () => {
9
+ for (const record of deps.repository.listRunning()) {
10
+ try {
11
+ if (!isAlive(record.pid))
12
+ await reconcileExit(deps, record.id);
13
+ }
14
+ catch (error) {
15
+ deps.log.error({ id: record.id, err: error }, "watcher: error checking record");
16
+ }
17
+ }
18
+ };
19
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../../src/extensions/detached-processes/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAmB,EAAE,EAAE,CAAC,KAAK,IAAmB,EAAE;IAClF,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC;QACnD,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;gBAAE,MAAM,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,gCAAgC,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ interface ExternalConfig {
2
+ sources: string[];
3
+ }
4
+ /**
5
+ * External extensions: loads Tachikoma extensions (defineExtension contract) from
6
+ * configured local sources and agent-installed records, registering each with the
7
+ * host. Install management tools clone git sources into `{dataDir}/extensions/<alias>`;
8
+ * installs, updates, and removals take effect on restart.
9
+ */
10
+ declare const _default: import("../api.ts").TachikomaExtension<ExternalConfig>;
11
+ export default _default;
@@ -0,0 +1,40 @@
1
+ import { isAbsolute, join } from "node:path";
2
+ import { Type } from "typebox";
3
+ import { expandHome } from "../../workspace.js";
4
+ import { defineExtension } from "../api.js";
5
+ import { InstallManager } from "./installs.js";
6
+ import { loadExtensionModule } from "./loader.js";
7
+ import { createExternalToolsFactory } from "./tools.js";
8
+ /**
9
+ * External extensions: loads Tachikoma extensions (defineExtension contract) from
10
+ * configured local sources and agent-installed records, registering each with the
11
+ * host. Install management tools clone git sources into `{dataDir}/extensions/<alias>`;
12
+ * installs, updates, and removals take effect on restart.
13
+ */
14
+ export default defineExtension({
15
+ name: "external",
16
+ configSchema: Type.Object({
17
+ sources: Type.Array(Type.String(), { default: [] }),
18
+ }),
19
+ async setup(app) {
20
+ const manager = new InstallManager({
21
+ state: app.state,
22
+ extensionsDir: join(app.workspace.dataDir, "extensions"),
23
+ log: app.log,
24
+ });
25
+ const configured = app.extensionConfig.sources.map((source) => {
26
+ const expanded = expandHome(source);
27
+ return isAbsolute(expanded) ? expanded : app.workspace.resolve(expanded);
28
+ });
29
+ const installed = Object.values(manager.list()).map((record) => record.path);
30
+ for (const source of new Set([...configured, ...installed])) {
31
+ const extension = await loadExtensionModule(source, app.log);
32
+ if (extension != null) {
33
+ app.registerExtension(extension);
34
+ app.log.info({ source, extension: extension.name }, "external extension registered");
35
+ }
36
+ }
37
+ app.agent.use(createExternalToolsFactory(manager));
38
+ },
39
+ });
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/external/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAMxD;;;;;GAKG;AACH,eAAe,eAAe,CAAiB;IAC7C,IAAI,EAAE,UAAU;IAEhB,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC;QACxB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;KACpD,CAAC;IAEF,KAAK,CAAC,KAAK,CAAC,GAAG;QACb,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC;YACjC,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC;YACxD,GAAG,EAAE,GAAG,CAAC,GAAG;SACb,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC5D,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;YAEpC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAE7E,KAAK,MAAM,MAAM,IAAI,IAAI,GAAG,CAAC,CAAC,GAAG,UAAU,EAAE,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC;YAC5D,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;YAE7D,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;gBACtB,GAAG,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;gBACjC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,+BAA+B,CAAC,CAAC;YACvF,CAAC;QACH,CAAC;QAED,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { KeyValueState } from "../../db/state.ts";
2
+ import type { Logger } from "../../log.ts";
3
+ export declare const ALIAS_PATTERN: RegExp;
4
+ /** Git sources are cloned and updatable; anything else is a local path loaded in place. */
5
+ export declare const isGitSource: (source: string) => boolean;
6
+ export interface InstallRecord {
7
+ source: string;
8
+ installedAt: string;
9
+ path: string;
10
+ }
11
+ export interface UpdateResult {
12
+ status: "updated" | "skipped";
13
+ detail: string;
14
+ }
15
+ export type InstallsState = Pick<KeyValueState, "get" | "set">;
16
+ export interface InstallManagerDeps {
17
+ state: InstallsState;
18
+ /** Where git sources are cloned: `{dataDir}/extensions/<alias>`. */
19
+ extensionsDir: string;
20
+ log: Logger;
21
+ now?: () => Date;
22
+ }
23
+ /**
24
+ * Agent-driven external extension installs. Git sources are cloned under the data dir and
25
+ * updated with `git pull`; local paths are recorded as-is (always current).
26
+ * Records live in the extension's KV state; loading happens on the next startup.
27
+ */
28
+ export declare class InstallManager {
29
+ private readonly state;
30
+ private readonly extensionsDir;
31
+ private readonly log;
32
+ private readonly now;
33
+ constructor({ state, extensionsDir, log, now }: InstallManagerDeps);
34
+ list(): Record<string, InstallRecord>;
35
+ install(source: string, alias: string): Promise<InstallRecord>;
36
+ private cloneGitSource;
37
+ update(alias: string): Promise<UpdateResult>;
38
+ uninstall(alias: string): Promise<InstallRecord>;
39
+ }
@@ -0,0 +1,98 @@
1
+ import { execFile } from "node:child_process";
2
+ import { mkdir, rm } from "node:fs/promises";
3
+ import { join, resolve } from "node:path";
4
+ import { promisify } from "node:util";
5
+ import { expandHome } from "../../workspace.js";
6
+ import { loadExtensionModule } from "./loader.js";
7
+ const execFileAsync = promisify(execFile);
8
+ export const ALIAS_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
9
+ const GIT_SOURCE_PATTERN = /^(https?:\/\/|git@|ssh:\/\/|file:\/\/)|\.git$/;
10
+ /** Git sources are cloned and updatable; anything else is a local path loaded in place. */
11
+ export const isGitSource = (source) => GIT_SOURCE_PATTERN.test(source);
12
+ const INSTALLS_KEY = "installs";
13
+ /**
14
+ * Agent-driven external extension installs. Git sources are cloned under the data dir and
15
+ * updated with `git pull`; local paths are recorded as-is (always current).
16
+ * Records live in the extension's KV state; loading happens on the next startup.
17
+ */
18
+ export class InstallManager {
19
+ state;
20
+ extensionsDir;
21
+ log;
22
+ now;
23
+ constructor({ state, extensionsDir, log, now }) {
24
+ this.state = state;
25
+ this.extensionsDir = extensionsDir;
26
+ this.log = log;
27
+ this.now = now ?? (() => new Date());
28
+ }
29
+ list() {
30
+ return this.state.get(INSTALLS_KEY) ?? {};
31
+ }
32
+ async install(source, alias) {
33
+ if (!ALIAS_PATTERN.test(alias)) {
34
+ throw new Error(`Invalid alias '${alias}': must match [a-z0-9][a-z0-9-]*`);
35
+ }
36
+ const records = this.list();
37
+ if (records[alias] != null) {
38
+ throw new Error(`ExternalExtension '${alias}' is already installed. Uninstall it or pick another alias.`);
39
+ }
40
+ const fromGit = isGitSource(source);
41
+ const path = fromGit ? await this.cloneGitSource(source, alias) : resolve(expandHome(source));
42
+ if ((await loadExtensionModule(path, this.log)) == null) {
43
+ if (fromGit)
44
+ await rm(path, { recursive: true, force: true });
45
+ throw new Error(`Source '${source}' does not contain a valid Tachikoma extension module ` +
46
+ "(expected a .ts/.js file or an index.ts/index.js whose default export has 'name' and 'setup').");
47
+ }
48
+ const record = { source, installedAt: this.now().toISOString(), path };
49
+ this.state.set(INSTALLS_KEY, { ...records, [alias]: record });
50
+ this.log.info({ alias, source, path }, "external extension installed");
51
+ return record;
52
+ }
53
+ async cloneGitSource(source, alias) {
54
+ const target = join(this.extensionsDir, alias);
55
+ await mkdir(this.extensionsDir, { recursive: true });
56
+ await rm(target, { recursive: true, force: true });
57
+ try {
58
+ await execFileAsync("git", ["clone", source, target]);
59
+ }
60
+ catch (error) {
61
+ throw new Error(`git clone failed for '${source}': ${error}`);
62
+ }
63
+ return target;
64
+ }
65
+ async update(alias) {
66
+ const record = this.list()[alias];
67
+ if (record == null)
68
+ throw new Error(`ExternalExtension '${alias}' is not installed.`);
69
+ if (!isGitSource(record.source)) {
70
+ return {
71
+ status: "skipped",
72
+ detail: "Local external extensions load directly from their source path and are always current.",
73
+ };
74
+ }
75
+ try {
76
+ const { stdout } = await execFileAsync("git", ["pull", "--ff-only"], { cwd: record.path });
77
+ this.log.info({ alias }, "external extension updated");
78
+ return { status: "updated", detail: stdout.trim() };
79
+ }
80
+ catch (error) {
81
+ throw new Error(`git pull failed for '${alias}': ${error}`);
82
+ }
83
+ }
84
+ async uninstall(alias) {
85
+ const records = this.list();
86
+ const record = records[alias];
87
+ if (record == null)
88
+ throw new Error(`ExternalExtension '${alias}' is not installed.`);
89
+ // Only remove directories we cloned ourselves; local sources stay untouched.
90
+ if (isGitSource(record.source)) {
91
+ await rm(record.path, { recursive: true, force: true });
92
+ }
93
+ this.state.set(INSTALLS_KEY, Object.fromEntries(Object.entries(records).filter(([key]) => key !== alias)));
94
+ this.log.info({ alias }, "external extension uninstalled");
95
+ return record;
96
+ }
97
+ }
98
+ //# sourceMappingURL=installs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installs.js","sourceRoot":"","sources":["../../../src/extensions/external/installs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { Logger } from "../../log.ts";
2
+ import type { TachikomaExtension } from "../api.ts";
3
+ /** Resolve a source (file or directory) to its extension module file, or null. */
4
+ export declare const resolveExtensionModule: (source: string) => string | null;
5
+ export type ExtensionValidation = {
6
+ ok: true;
7
+ extension: TachikomaExtension<never>;
8
+ } | {
9
+ ok: false;
10
+ reason: string;
11
+ };
12
+ /** Check that a module's default export satisfies the defineExtension contract. */
13
+ export declare const validateExtensionShape: (value: unknown) => ExtensionValidation;
14
+ /**
15
+ * Load a Tachikoma extension from a source path: resolve the module file,
16
+ * import it natively, and validate its default export. Invalid sources are
17
+ * logged and skipped (null) so one bad external extension never aborts startup.
18
+ */
19
+ export declare const loadExtensionModule: (source: string, log: Logger) => Promise<TachikomaExtension<never> | null>;
@@ -0,0 +1,70 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { existsSync, statSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { pathToFileURL } from "node:url";
12
+ const INDEX_CANDIDATES = ["index.ts", "index.js"];
13
+ /** Resolve a source (file or directory) to its extension module file, or null. */
14
+ export const resolveExtensionModule = (source) => {
15
+ if (!existsSync(source))
16
+ return null;
17
+ if (statSync(source).isFile()) {
18
+ return source.endsWith(".ts") || source.endsWith(".js") ? source : null;
19
+ }
20
+ for (const candidate of INDEX_CANDIDATES) {
21
+ const path = join(source, candidate);
22
+ if (existsSync(path))
23
+ return path;
24
+ }
25
+ return null;
26
+ };
27
+ /** Check that a module's default export satisfies the defineExtension contract. */
28
+ export const validateExtensionShape = (value) => {
29
+ if (value == null || typeof value !== "object") {
30
+ return { ok: false, reason: "default export is not an object" };
31
+ }
32
+ const candidate = value;
33
+ if (typeof candidate.name !== "string" || candidate.name.trim() === "") {
34
+ return { ok: false, reason: "missing a non-empty 'name' string" };
35
+ }
36
+ if (typeof candidate.setup !== "function") {
37
+ return { ok: false, reason: "missing a 'setup' function" };
38
+ }
39
+ if (candidate.configSchema != null && typeof candidate.configSchema !== "object") {
40
+ return { ok: false, reason: "'configSchema' must be a TypeBox schema object" };
41
+ }
42
+ return { ok: true, extension: candidate };
43
+ };
44
+ /**
45
+ * Load a Tachikoma extension from a source path: resolve the module file,
46
+ * import it natively, and validate its default export. Invalid sources are
47
+ * logged and skipped (null) so one bad external extension never aborts startup.
48
+ */
49
+ export const loadExtensionModule = async (source, log) => {
50
+ const modulePath = resolveExtensionModule(source);
51
+ if (modulePath == null) {
52
+ log.warn({ source }, "external extension source has no loadable extension module (.ts/.js) — skipping");
53
+ return null;
54
+ }
55
+ let module;
56
+ try {
57
+ module = await import(__rewriteRelativeImportExtension(pathToFileURL(modulePath).href));
58
+ }
59
+ catch (error) {
60
+ log.warn({ source: modulePath, err: error }, "external extension module failed to import — skipping");
61
+ return null;
62
+ }
63
+ const validation = validateExtensionShape(module.default);
64
+ if (!validation.ok) {
65
+ log.warn({ source: modulePath, reason: validation.reason }, "invalid external extension — skipping");
66
+ return null;
67
+ }
68
+ return validation.extension;
69
+ };
70
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/extensions/external/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { ExtensionFactory } from "@earendil-works/pi-coding-agent";
2
+ import { type Static, Type } from "typebox";
3
+ import { type InstallManager } from "./installs.ts";
4
+ export declare const InstallPluginParams: Type.TObject<{
5
+ source: Type.TString;
6
+ alias: Type.TString;
7
+ }>;
8
+ export declare const PluginAliasParams: Type.TObject<{
9
+ alias: Type.TString;
10
+ }>;
11
+ export declare const ListInstalledPluginsParams: Type.TObject<{}>;
12
+ export declare const handleInstallExternalExtension: (manager: InstallManager, args: Static<typeof InstallPluginParams>) => Promise<string>;
13
+ export declare const handleUpdateExternalExtension: (manager: InstallManager, args: Static<typeof PluginAliasParams>) => Promise<string>;
14
+ export declare const handleListInstalledPlugins: (manager: InstallManager) => string;
15
+ export declare const handleUninstallExtension: (manager: InstallManager, args: Static<typeof PluginAliasParams>) => Promise<string>;
16
+ /** pi extension factory exposing the extension install management tools to the agent. */
17
+ export declare const createExternalToolsFactory: (manager: InstallManager) => ExtensionFactory;