@asterxsk/kiln 0.1.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 (263) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +170 -0
  3. package/agent/AGENTS.md +67 -0
  4. package/agent/README.md +5 -0
  5. package/agent/extensions/AGENTS.md +68 -0
  6. package/agent/extensions/ask-user/index.ts +418 -0
  7. package/agent/extensions/ask-user/install.ps1 +23 -0
  8. package/agent/extensions/ask-user/install.sh +21 -0
  9. package/agent/extensions/ask-user/package-lock.json +769 -0
  10. package/agent/extensions/ask-user/package.json +19 -0
  11. package/agent/extensions/ask-user/prompt.ts +45 -0
  12. package/agent/extensions/ask-user/tsconfig.json +7 -0
  13. package/agent/extensions/background-terminals/docs/implementation-guide.md +942 -0
  14. package/agent/extensions/background-terminals/index.ts +627 -0
  15. package/agent/extensions/background-terminals/install.ps1 +23 -0
  16. package/agent/extensions/background-terminals/install.sh +21 -0
  17. package/agent/extensions/background-terminals/manager.test.ts +735 -0
  18. package/agent/extensions/background-terminals/output.test.ts +109 -0
  19. package/agent/extensions/background-terminals/package-lock.json +769 -0
  20. package/agent/extensions/background-terminals/package.json +17 -0
  21. package/agent/extensions/background-terminals/prompt.test.ts +125 -0
  22. package/agent/extensions/background-terminals/ps.test.ts +82 -0
  23. package/agent/extensions/background-terminals/result-delivery.test.ts +44 -0
  24. package/agent/extensions/background-terminals/src/domain.ts +87 -0
  25. package/agent/extensions/background-terminals/src/manager.ts +907 -0
  26. package/agent/extensions/background-terminals/src/output.ts +84 -0
  27. package/agent/extensions/background-terminals/src/prompt.ts +142 -0
  28. package/agent/extensions/background-terminals/src/result-delivery.ts +27 -0
  29. package/agent/extensions/background-terminals/src/runtime.ts +36 -0
  30. package/agent/extensions/background-terminals/src/ui/output-view.ts +79 -0
  31. package/agent/extensions/background-terminals/src/ui/ps.ts +621 -0
  32. package/agent/extensions/background-terminals/tsconfig.json +7 -0
  33. package/agent/extensions/destructive/README.md +31 -0
  34. package/agent/extensions/destructive/index.ts +88 -0
  35. package/agent/extensions/destructive/install.ps1 +23 -0
  36. package/agent/extensions/destructive/install.sh +21 -0
  37. package/agent/extensions/file-search/index.spec.ts +443 -0
  38. package/agent/extensions/file-search/index.ts +459 -0
  39. package/agent/extensions/file-search/install.ps1 +23 -0
  40. package/agent/extensions/file-search/install.sh +21 -0
  41. package/agent/extensions/file-search/package-lock.json +2253 -0
  42. package/agent/extensions/file-search/package.json +23 -0
  43. package/agent/extensions/file-search/src/args.ts +122 -0
  44. package/agent/extensions/file-search/src/binaries.ts +422 -0
  45. package/agent/extensions/file-search/src/output.ts +126 -0
  46. package/agent/extensions/file-search/src/process.ts +146 -0
  47. package/agent/extensions/file-search/src/prompt.ts +52 -0
  48. package/agent/extensions/file-search/tsconfig.json +7 -0
  49. package/agent/extensions/goal/README.md +50 -0
  50. package/agent/extensions/goal/index.ts +155 -0
  51. package/agent/extensions/goal/install.ps1 +23 -0
  52. package/agent/extensions/goal/install.sh +21 -0
  53. package/agent/extensions/modelconf/PLAN.md +915 -0
  54. package/agent/extensions/modelconf/README.md +66 -0
  55. package/agent/extensions/modelconf/index.ts +296 -0
  56. package/agent/extensions/modelconf/install.ps1 +23 -0
  57. package/agent/extensions/modelconf/install.sh +21 -0
  58. package/agent/extensions/modelconf/package-lock.json +1809 -0
  59. package/agent/extensions/modelconf/package.json +13 -0
  60. package/agent/extensions/modelconf/src/fuzzy.ts +26 -0
  61. package/agent/extensions/modelconf/src/glob.ts +13 -0
  62. package/agent/extensions/modelconf/src/persistence.test.ts +46 -0
  63. package/agent/extensions/modelconf/src/persistence.ts +164 -0
  64. package/agent/extensions/modelconf/src/ui/ModelConfView.test.ts +75 -0
  65. package/agent/extensions/modelconf/src/ui/ModelConfView.ts +1101 -0
  66. package/agent/extensions/modelconf/tsconfig.json +15 -0
  67. package/agent/extensions/pi-web-access/CHANGELOG.md +690 -0
  68. package/agent/extensions/pi-web-access/LICENSE +21 -0
  69. package/agent/extensions/pi-web-access/README.md +470 -0
  70. package/agent/extensions/pi-web-access/SECURITY.md +5 -0
  71. package/agent/extensions/pi-web-access/activity.ts +101 -0
  72. package/agent/extensions/pi-web-access/auth-fetch.ts +148 -0
  73. package/agent/extensions/pi-web-access/banner.png +0 -0
  74. package/agent/extensions/pi-web-access/brightdata-unlocker.ts +272 -0
  75. package/agent/extensions/pi-web-access/chrome-cookies.ts +669 -0
  76. package/agent/extensions/pi-web-access/content-find.ts +139 -0
  77. package/agent/extensions/pi-web-access/credential-source.ts +191 -0
  78. package/agent/extensions/pi-web-access/data-uri-sanitize.ts +406 -0
  79. package/agent/extensions/pi-web-access/datalab-pdf-extract.ts +568 -0
  80. package/agent/extensions/pi-web-access/declared-web-links.ts +173 -0
  81. package/agent/extensions/pi-web-access/evidence/CONTRACT-EVIDENCE.md +496 -0
  82. package/agent/extensions/pi-web-access/evidence/contract-probe.mjs +140 -0
  83. package/agent/extensions/pi-web-access/exa.ts +526 -0
  84. package/agent/extensions/pi-web-access/extract.ts +1196 -0
  85. package/agent/extensions/pi-web-access/feature-config.ts +29 -0
  86. package/agent/extensions/pi-web-access/fetch-params.ts +111 -0
  87. package/agent/extensions/pi-web-access/gemini-adc.ts +298 -0
  88. package/agent/extensions/pi-web-access/gemini-api.ts +353 -0
  89. package/agent/extensions/pi-web-access/gemini-pdf-extract.ts +108 -0
  90. package/agent/extensions/pi-web-access/gemini-search.ts +21 -0
  91. package/agent/extensions/pi-web-access/gemini-url-context.ts +128 -0
  92. package/agent/extensions/pi-web-access/gemini-web-config.ts +101 -0
  93. package/agent/extensions/pi-web-access/gemini-web.ts +487 -0
  94. package/agent/extensions/pi-web-access/github-api.ts +197 -0
  95. package/agent/extensions/pi-web-access/github-extract.ts +746 -0
  96. package/agent/extensions/pi-web-access/github-issue-pr.ts +700 -0
  97. package/agent/extensions/pi-web-access/index.ts +1737 -0
  98. package/agent/extensions/pi-web-access/package-lock.json +5808 -0
  99. package/agent/extensions/pi-web-access/package.json +64 -0
  100. package/agent/extensions/pi-web-access/page-query.ts +96 -0
  101. package/agent/extensions/pi-web-access/pdf-extract.ts +409 -0
  102. package/agent/extensions/pi-web-access/pi-web-fetch-demo.mp4 +0 -0
  103. package/agent/extensions/pi-web-access/promise-try.d.ts +7 -0
  104. package/agent/extensions/pi-web-access/query-rewrite.ts +51 -0
  105. package/agent/extensions/pi-web-access/render-search-error.ts +170 -0
  106. package/agent/extensions/pi-web-access/rsc-extract.ts +338 -0
  107. package/agent/extensions/pi-web-access/search-types.ts +20 -0
  108. package/agent/extensions/pi-web-access/source-check.ts +282 -0
  109. package/agent/extensions/pi-web-access/ssrf-protection.ts +526 -0
  110. package/agent/extensions/pi-web-access/storage.ts +521 -0
  111. package/agent/extensions/pi-web-access/summary-model-scope.ts +125 -0
  112. package/agent/extensions/pi-web-access/test/auth-fetch.test.mjs +208 -0
  113. package/agent/extensions/pi-web-access/test/brightdata-unlocker.test.mjs +840 -0
  114. package/agent/extensions/pi-web-access/test/chrome-cookie-extraction.test.mjs +441 -0
  115. package/agent/extensions/pi-web-access/test/config-path.test.mjs +283 -0
  116. package/agent/extensions/pi-web-access/test/content-find.test.mjs +25 -0
  117. package/agent/extensions/pi-web-access/test/credential-source.test.mjs +118 -0
  118. package/agent/extensions/pi-web-access/test/data-uri-sanitize.test.mjs +210 -0
  119. package/agent/extensions/pi-web-access/test/datalab-pdf-extract.test.mjs +552 -0
  120. package/agent/extensions/pi-web-access/test/declared-web-links.test.mjs +212 -0
  121. package/agent/extensions/pi-web-access/test/fetch-answer-storage.test.mjs +40 -0
  122. package/agent/extensions/pi-web-access/test/fetch-cache-storage.test.mjs +334 -0
  123. package/agent/extensions/pi-web-access/test/fetch-content-domain-policy.test.mjs +95 -0
  124. package/agent/extensions/pi-web-access/test/fetch-modes.test.mjs +53 -0
  125. package/agent/extensions/pi-web-access/test/fetch-not-found-guidance.test.mjs +92 -0
  126. package/agent/extensions/pi-web-access/test/fetch-params.test.mjs +86 -0
  127. package/agent/extensions/pi-web-access/test/fetch-render-call.test.mjs +34 -0
  128. package/agent/extensions/pi-web-access/test/fetch-routing.test.mjs +173 -0
  129. package/agent/extensions/pi-web-access/test/gemini-adc-auth.test.mjs +257 -0
  130. package/agent/extensions/pi-web-access/test/gemini-api-transport.test.mjs +170 -0
  131. package/agent/extensions/pi-web-access/test/gemini-pdf-extract.test.mjs +133 -0
  132. package/agent/extensions/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +178 -0
  133. package/agent/extensions/pi-web-access/test/gemini-web-header-overflow.test.mjs +148 -0
  134. package/agent/extensions/pi-web-access/test/get-search-content.test.mjs +223 -0
  135. package/agent/extensions/pi-web-access/test/github-extract.test.mjs +378 -0
  136. package/agent/extensions/pi-web-access/test/github-issue-pr.test.mjs +565 -0
  137. package/agent/extensions/pi-web-access/test/inline-content-config.test.mjs +99 -0
  138. package/agent/extensions/pi-web-access/test/lazy-extract-load.test.mjs +118 -0
  139. package/agent/extensions/pi-web-access/test/local-video-oversize.test.mjs +52 -0
  140. package/agent/extensions/pi-web-access/test/package-typebox-dependency.test.mjs +50 -0
  141. package/agent/extensions/pi-web-access/test/page-query.test.mjs +51 -0
  142. package/agent/extensions/pi-web-access/test/pdf-config.test.mjs +140 -0
  143. package/agent/extensions/pi-web-access/test/pdf-extract.test.mjs +500 -0
  144. package/agent/extensions/pi-web-access/test/proxy-transport.test.mjs +286 -0
  145. package/agent/extensions/pi-web-access/test/query-rewrite.test.mjs +52 -0
  146. package/agent/extensions/pi-web-access/test/rsc-fallback.test.mjs +102 -0
  147. package/agent/extensions/pi-web-access/test/search-error-render.test.mjs +152 -0
  148. package/agent/extensions/pi-web-access/test/search-providers.test.mjs +274 -0
  149. package/agent/extensions/pi-web-access/test/source-check.test.mjs +179 -0
  150. package/agent/extensions/pi-web-access/test/ssrf-allow-ranges-config.test.mjs +205 -0
  151. package/agent/extensions/pi-web-access/test/ssrf-protection.test.mjs +456 -0
  152. package/agent/extensions/pi-web-access/test/summary-model-scope.test.mjs +106 -0
  153. package/agent/extensions/pi-web-access/test/tool-registration-config.test.mjs +182 -0
  154. package/agent/extensions/pi-web-access/test/web-search-answer-render.test.mjs +66 -0
  155. package/agent/extensions/pi-web-access/test/youtube-extract-errors.test.mjs +64 -0
  156. package/agent/extensions/pi-web-access/tsconfig.json +11 -0
  157. package/agent/extensions/pi-web-access/utils.ts +451 -0
  158. package/agent/extensions/pi-web-access/video-extract.ts +392 -0
  159. package/agent/extensions/pi-web-access/youtube-extract.ts +328 -0
  160. package/agent/extensions/shared/activity-status.ts +31 -0
  161. package/agent/extensions/shared/child-session.test.ts +270 -0
  162. package/agent/extensions/shared/child-session.ts +148 -0
  163. package/agent/extensions/shared/context-utilization.test.ts +48 -0
  164. package/agent/extensions/shared/context-utilization.ts +47 -0
  165. package/agent/extensions/shared/dashboard-state.ts +99 -0
  166. package/agent/extensions/shared/install.ps1 +23 -0
  167. package/agent/extensions/shared/install.sh +21 -0
  168. package/agent/extensions/shared/tool-call-timeout.test.ts +117 -0
  169. package/agent/extensions/shared/tool-call-timeout.ts +104 -0
  170. package/agent/extensions/skillsconf/README.md +74 -0
  171. package/agent/extensions/skillsconf/index.ts +92 -0
  172. package/agent/extensions/skillsconf/install.ps1 +23 -0
  173. package/agent/extensions/skillsconf/install.sh +21 -0
  174. package/agent/extensions/skillsconf/package-lock.json +1809 -0
  175. package/agent/extensions/skillsconf/package.json +18 -0
  176. package/agent/extensions/skillsconf/src/delete-skill.test.ts +64 -0
  177. package/agent/extensions/skillsconf/src/delete-skill.ts +45 -0
  178. package/agent/extensions/skillsconf/src/filter.test.ts +80 -0
  179. package/agent/extensions/skillsconf/src/filter.ts +74 -0
  180. package/agent/extensions/skillsconf/src/fuzzy.ts +26 -0
  181. package/agent/extensions/skillsconf/src/persistence.test.ts +72 -0
  182. package/agent/extensions/skillsconf/src/persistence.ts +169 -0
  183. package/agent/extensions/skillsconf/src/ui/SkillConfView.test.ts +337 -0
  184. package/agent/extensions/skillsconf/src/ui/SkillConfView.ts +758 -0
  185. package/agent/extensions/skillsconf/src/ui/text-input.ts +91 -0
  186. package/agent/extensions/skillsconf/src/ui/tui-helpers.ts +144 -0
  187. package/agent/extensions/skillsconf/tsconfig.json +15 -0
  188. package/agent/extensions/status line/index.ts +282 -0
  189. package/agent/extensions/status line/install.ps1 +23 -0
  190. package/agent/extensions/status line/install.sh +21 -0
  191. package/agent/extensions/subagents/by-the-way.test.ts +29 -0
  192. package/agent/extensions/subagents/claude.test.ts +119 -0
  193. package/agent/extensions/subagents/codex.test.ts +102 -0
  194. package/agent/extensions/subagents/context-usage.test.ts +107 -0
  195. package/agent/extensions/subagents/docs/design-plan.md +568 -0
  196. package/agent/extensions/subagents/docs/effect-v4-extension-guide.md +354 -0
  197. package/agent/extensions/subagents/docs/effect-v4-notes.md +571 -0
  198. package/agent/extensions/subagents/index.ts +779 -0
  199. package/agent/extensions/subagents/install.ps1 +23 -0
  200. package/agent/extensions/subagents/install.sh +21 -0
  201. package/agent/extensions/subagents/manager.test.ts +276 -0
  202. package/agent/extensions/subagents/package-lock.json +2244 -0
  203. package/agent/extensions/subagents/package.json +19 -0
  204. package/agent/extensions/subagents/result-delivery.test.ts +27 -0
  205. package/agent/extensions/subagents/src/backend.ts +73 -0
  206. package/agent/extensions/subagents/src/backends/claude.ts +701 -0
  207. package/agent/extensions/subagents/src/backends/codex.ts +1060 -0
  208. package/agent/extensions/subagents/src/backends/pi.ts +575 -0
  209. package/agent/extensions/subagents/src/backends/stub.ts +300 -0
  210. package/agent/extensions/subagents/src/by-the-way.ts +21 -0
  211. package/agent/extensions/subagents/src/domain.ts +253 -0
  212. package/agent/extensions/subagents/src/format.ts +74 -0
  213. package/agent/extensions/subagents/src/manager.ts +736 -0
  214. package/agent/extensions/subagents/src/prompt.ts +92 -0
  215. package/agent/extensions/subagents/src/result-delivery.ts +20 -0
  216. package/agent/extensions/subagents/src/runtime.ts +53 -0
  217. package/agent/extensions/subagents/src/ui/takeover.ts +583 -0
  218. package/agent/extensions/subagents/src/ui/transcript.ts +201 -0
  219. package/agent/extensions/subagents/takeover.test.ts +29 -0
  220. package/agent/extensions/subagents/tsconfig.json +7 -0
  221. package/agent/extensions/taste/index.ts +443 -0
  222. package/agent/extensions/taste/install.ps1 +23 -0
  223. package/agent/extensions/taste/install.sh +21 -0
  224. package/agent/extensions/todo/AGENTS.md +38 -0
  225. package/agent/extensions/todo/LICENSE +21 -0
  226. package/agent/extensions/todo/config.ts +55 -0
  227. package/agent/extensions/todo/index.ts +151 -0
  228. package/agent/extensions/todo/install.ps1 +23 -0
  229. package/agent/extensions/todo/install.sh +21 -0
  230. package/agent/extensions/todo/locales/de.json +17 -0
  231. package/agent/extensions/todo/locales/en.json +15 -0
  232. package/agent/extensions/todo/locales/es.json +17 -0
  233. package/agent/extensions/todo/locales/fr.json +17 -0
  234. package/agent/extensions/todo/locales/pt-BR.json +17 -0
  235. package/agent/extensions/todo/locales/pt.json +17 -0
  236. package/agent/extensions/todo/locales/ru.json +17 -0
  237. package/agent/extensions/todo/locales/uk.json +17 -0
  238. package/agent/extensions/todo/locales/zh.json +17 -0
  239. package/agent/extensions/todo/package-lock.json +3358 -0
  240. package/agent/extensions/todo/package.json +67 -0
  241. package/agent/extensions/todo/state/i18n-bridge.ts +64 -0
  242. package/agent/extensions/todo/state/invariants.ts +20 -0
  243. package/agent/extensions/todo/state/replay.ts +38 -0
  244. package/agent/extensions/todo/state/selectors.ts +107 -0
  245. package/agent/extensions/todo/state/state-reducer.ts +326 -0
  246. package/agent/extensions/todo/state/state.ts +18 -0
  247. package/agent/extensions/todo/state/store.ts +82 -0
  248. package/agent/extensions/todo/state/task-graph.ts +57 -0
  249. package/agent/extensions/todo/todo-overlay.ts +200 -0
  250. package/agent/extensions/todo/todo.ts +155 -0
  251. package/agent/extensions/todo/tool/response-envelope.ts +109 -0
  252. package/agent/extensions/todo/tool/types.ts +206 -0
  253. package/agent/extensions/todo/verify-ref-system.js +0 -0
  254. package/agent/extensions/todo/view/format.ts +177 -0
  255. package/agent/extensions/trim-context/README.md +54 -0
  256. package/agent/extensions/trim-context/index.ts +487 -0
  257. package/agent/extensions/trim-context/install.ps1 +23 -0
  258. package/agent/extensions/trim-context/install.sh +21 -0
  259. package/agent/install.ps1 +527 -0
  260. package/agent/install.sh +511 -0
  261. package/agent/keybindings.json +7 -0
  262. package/bin/kiln.js +359 -0
  263. package/package.json +21 -0
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ # Per-extension installer — macOS / Linux
3
+ # Installs npm dependencies for this extension. No-op if no package.json.
4
+ set -eu
5
+ EXT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+ if [ ! -f "$EXT_DIR/package.json" ]; then
7
+ echo " · no package.json — skipping"
8
+ exit 0
9
+ fi
10
+ if ! command -v npm >/dev/null 2>&1; then
11
+ echo " ✖ npm not found — install Node.js 22+" >&2
12
+ exit 1
13
+ fi
14
+ if [ -f "$EXT_DIR/package-lock.json" ]; then
15
+ echo " · npm ci"
16
+ npm --prefix "$EXT_DIR" ci --no-audit --no-fund
17
+ else
18
+ echo " · npm install"
19
+ npm --prefix "$EXT_DIR" install --no-audit --no-fund
20
+ fi
21
+ echo " ✓ done"
@@ -0,0 +1,38 @@
1
+ # Todo Extension
2
+
3
+ ## Purpose
4
+ Provides a persistent todo list with overlay widget, slash command, and LLM-callable tool. Todos are tracked across sessions and displayed in a dedicated UI overlay. Supports i18n via optional `@juicesharp/rpiv-i18n` SDK.
5
+
6
+ ## Ownership
7
+ - `index.ts` — extension entry, event handlers, overlay lifecycle
8
+ - `todo.ts` — todo tool and command registration
9
+ - `todo-overlay.ts` — TUI overlay widget for todo display
10
+ - `state/` — state management, replay, i18n bridge
11
+
12
+ ## Local Contracts
13
+ - Registers tool: `todo` (tool name preserved for session history compatibility)
14
+ - Registers command: `/todos`
15
+ - Widget key: `rpiv-todos` (preserved for compatibility)
16
+ - State replayed from branch on `session_start`, `session_compact`, `session_tree`
17
+ - `replaceState(sessionId, state)` and `replayFromBranch()` from state modules — the store is keyed by `ctx.sessionManager.getSessionId()` so each session (main or in-process subagent) has an independent todo cell; `dropState(sessionId)` on `session_shutdown` prunes ended sessions
18
+ - Handles stale ctx errors during auto-compaction gracefully
19
+ - Batch items support `as` labels (on create) and `refs` (on subsequent items) for creating and referencing tasks in one call
20
+
21
+ ## Work Guidance
22
+ - Todo state is session-branch-based and replayed on session events
23
+ - Overlay constructed lazily at first `session_start` with UI
24
+ - `hideCompletedTasksFromPreviousTurn()` called on `agent_start`
25
+ - i18n strings registered once at module init (soft optional peer dependency)
26
+ - Auto-clear: when no active tasks remain (all completed, deleted, or empty), the state resets to empty automatically at `agent_end` and after replay on `session_start`/`session_compact`/`session_tree`. This prevents stale completed tasks from persisting across turns. The clear is in-memory only — session lifecycle handlers re-apply it after branch replay so the empty state survives compaction and session transitions.
27
+ - Tool execution triggers overlay update via `tool_execution_end` event
28
+ - Overlay indentation: task prefix is `" └ "` (first line, └ at col 3) and `" "` (continuation, text at col 5), and the overflow summary line also starts with `" └"`. This aligns the `└` tree glyph one column after the first letter of the spinner phrase (the spinner occupies 2 columns, e.g. `"✻ "`), so the todo overlay sits under the phrase rather than under the spinner animation character
29
+
30
+ ## Verification
31
+ - Add todo: use `/todos` command or `todo` tool
32
+ - Verify overlay: check widget displays in TUI
33
+ - Test session persistence: `/new` then verify todos still shown
34
+ - Test compaction: trigger compact, verify todos replay correctly
35
+ - Trigger the agent spinner with at least one todo visible; confirm the `└` glyph in each todo line (and the `+N more` summary line) sits ONE COLUMN AFTER the first letter of the spinner phrase — not under the spinner animation character itself
36
+
37
+ ## Child DOX Index
38
+ None
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 juicesharp
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,55 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Self-contained config utilities — inlined from @juicesharp/rpiv-config so
7
+ // this extension has zero npm dependencies and can be freely edited.
8
+ // ---------------------------------------------------------------------------
9
+
10
+ export interface GuidanceFields {
11
+ promptSnippet?: string;
12
+ promptGuidelines?: string[];
13
+ }
14
+
15
+ function configPath(name: string, file: string = "config.json"): string {
16
+ return join(homedir(), ".config", name, file);
17
+ }
18
+
19
+ function loadJsonConfig<T>(path: string): T {
20
+ if (!existsSync(path)) return {} as T;
21
+ try {
22
+ const parsed = JSON.parse(readFileSync(path, "utf-8")) as unknown;
23
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {} as T;
24
+ return parsed as T;
25
+ } catch {
26
+ return {} as T;
27
+ }
28
+ }
29
+
30
+ export function validateGuidanceFields(fields: unknown): GuidanceFields {
31
+ if (!fields || typeof fields !== "object") return {};
32
+ const g = fields as Record<string, unknown>;
33
+ const result: GuidanceFields = {};
34
+ if (typeof g.promptSnippet === "string" && g.promptSnippet.length > 0) {
35
+ result.promptSnippet = g.promptSnippet;
36
+ }
37
+ if (
38
+ Array.isArray(g.promptGuidelines) &&
39
+ g.promptGuidelines.length > 0 &&
40
+ g.promptGuidelines.every((s) => typeof s === "string" && s.length > 0)
41
+ ) {
42
+ result.promptGuidelines = g.promptGuidelines;
43
+ }
44
+ return result;
45
+ }
46
+
47
+ const CONFIG_PATH = configPath("rpiv-todo");
48
+
49
+ interface TodoConfig {
50
+ guidance?: GuidanceFields;
51
+ }
52
+
53
+ export function loadConfig(): TodoConfig {
54
+ return loadJsonConfig<TodoConfig>(CONFIG_PATH);
55
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * rpiv-todo — Pi extension. Registers the `todo` tool, `/todos` slash
3
+ * command, and the persistent TodoOverlay widget.
4
+ *
5
+ * TUI chrome strings localize at render time via the i18n bridge. Strings are
6
+ * registered with rpiv-i18n here, once, at module init — but only when the
7
+ * SDK is actually installed. If `@juicesharp/rpiv-i18n` is missing (standalone
8
+ * install of just this package), the dynamic-load shim no-ops and the bridge's
9
+ * `t(key, fallback)` returns the inline English literal at every call site.
10
+ * The extension stays online either way.
11
+ *
12
+ * Adding a locale: drop `locales/<code>.json` next to en.json (mirroring the
13
+ * key set). No edit needed here — `registerLocalesFromDir` iterates
14
+ * `SUPPORTED_LOCALES` from the SDK. See `@juicesharp/rpiv-i18n` README →
15
+ * "Contributing translations" for the full convention.
16
+ *
17
+ * Extracted from rpiv-pi@7525a5d. Tool name "todo" and widget key
18
+ * "rpiv-todos" preserved verbatim so existing session history replays
19
+ * correctly after upgrade.
20
+ */
21
+
22
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
23
+ import { I18N_NAMESPACE } from "./state/i18n-bridge.js";
24
+ import { replayFromBranch } from "./state/replay.js";
25
+ import { dropState, emptyState, getState, replaceState } from "./state/store.js";
26
+ import { registerTodosCommand, registerTodoTool, TOOL_NAME } from "./todo.js";
27
+ import { TodoOverlay } from "./todo-overlay.js";
28
+
29
+ type I18nLoader = {
30
+ registerLocalesFromDir: (namespace: string, packageUrl: string, options?: { label?: string }) => void;
31
+ };
32
+
33
+ // Dynamic import keeps `@juicesharp/rpiv-i18n` a soft optional peer: when the
34
+ // SDK is installed alongside this package the strings register and
35
+ // `/languages` flips them live; when it isn't, the import rejects here, we
36
+ // no-op, and the bridge's English-fallback shim keeps the extension online.
37
+ //
38
+ // The `/loader` subpath is used instead of the SDK entry so the i18n-ui +
39
+ // pi-tui modules are not pulled into our load graph just to register strings.
40
+ try {
41
+ const sdk = (await import("@juicesharp/rpiv-i18n/loader")) as I18nLoader;
42
+ sdk.registerLocalesFromDir(I18N_NAMESPACE, import.meta.url, { label: "rpiv-todo" });
43
+ } catch {
44
+ // SDK absent — extension still loads with English-only UI.
45
+ }
46
+
47
+ // pi-core's ExtensionRunner throws this exact phrase from an invalidated ctx
48
+ // proxy after session replacement/reload. Match the stable substring so genuine
49
+ // replay bugs still propagate instead of being silently swallowed.
50
+ function isStaleCtxError(e: unknown): boolean {
51
+ return /stale after session replacement/.test(String(e));
52
+ }
53
+
54
+ export default function (pi: ExtensionAPI) {
55
+ // Todo overlay widget — constructed lazily at the first session_start with UI.
56
+ let todoOverlay: TodoOverlay | undefined;
57
+
58
+ /**
59
+ * If no active tasks remain (all completed, deleted, or empty), reset the
60
+ * state to empty. Called at agent_end and after replay on session lifecycle
61
+ * events so stale completed tasks don't persist across turns.
62
+ *
63
+ * Note: clearing is in-memory only (no tool result written to the branch).
64
+ * Session lifecycle handlers re-check on replay so the empty state survives
65
+ * compaction and session transitions. If a future pi-core ordering change
66
+ * skips those lifecycle events, completed tasks would reappear.
67
+ */
68
+ function autoClearIfNoActiveTasks(sessionId: string): void {
69
+ const state = getState(sessionId);
70
+ if (!state.tasks.some((t) => t.status === "pending" || t.status === "in_progress")) {
71
+ replaceState(sessionId, emptyState());
72
+ }
73
+ }
74
+
75
+ registerTodoTool(pi);
76
+ registerTodosCommand(pi);
77
+
78
+ pi.on("session_start", async (_event, ctx) => {
79
+ const sessionId = ctx.sessionManager.getSessionId();
80
+ replaceState(sessionId, replayFromBranch(ctx));
81
+ autoClearIfNoActiveTasks(sessionId);
82
+ if (ctx.hasUI) {
83
+ todoOverlay ??= new TodoOverlay();
84
+ todoOverlay.setSession(sessionId);
85
+ todoOverlay.setUICtx(ctx.ui);
86
+ todoOverlay.resetCompletedDisplayState();
87
+ todoOverlay.update();
88
+ }
89
+ });
90
+
91
+ pi.on("session_compact", async (_event, ctx) => {
92
+ // Auto-compaction races session disposal: pi-core invalidates the
93
+ // extension runner while still emitting session_compact, so `ctx` may be
94
+ // a dead proxy whose getters throw the stale error. The compacting session
95
+ // is being discarded — the replacement session's session_start replays
96
+ // state — so keep current state on a stale ctx. Other errors are real
97
+ // replay bugs and must propagate.
98
+ try {
99
+ replaceState(ctx.sessionManager.getSessionId(), replayFromBranch(ctx));
100
+ } catch (e) {
101
+ if (!isStaleCtxError(e)) throw e;
102
+ }
103
+ autoClearIfNoActiveTasks(ctx.sessionManager.getSessionId());
104
+ todoOverlay?.resetCompletedDisplayState();
105
+ todoOverlay?.update();
106
+ });
107
+
108
+ pi.on("session_tree", async (_event, ctx) => {
109
+ try {
110
+ replaceState(ctx.sessionManager.getSessionId(), replayFromBranch(ctx));
111
+ } catch (e) {
112
+ if (!isStaleCtxError(e)) throw e;
113
+ }
114
+ autoClearIfNoActiveTasks(ctx.sessionManager.getSessionId());
115
+ todoOverlay?.resetCompletedDisplayState();
116
+ todoOverlay?.update();
117
+ });
118
+
119
+ pi.on("session_shutdown", async (_event, ctx) => {
120
+ try {
121
+ dropState(ctx.sessionManager.getSessionId());
122
+ } catch (e) {
123
+ // A stale ctx proxy after session replacement may throw on any getter;
124
+ // the cell for a replaced session is abandoned regardless.
125
+ if (!isStaleCtxError(e)) throw e;
126
+ }
127
+ todoOverlay?.dispose();
128
+ todoOverlay = undefined;
129
+ });
130
+
131
+ // Reads getTodos() at render time; do NOT call replayFromBranch here
132
+ // (branch is stale — message_end runs after tool_execution_end).
133
+ pi.on("tool_execution_end", async (event) => {
134
+ if (event.toolName !== TOOL_NAME || event.isError) return;
135
+ todoOverlay?.update();
136
+ });
137
+
138
+ pi.on("agent_start", async () => {
139
+ todoOverlay?.hideCompletedTasksFromPreviousTurn();
140
+ todoOverlay?.onAgentTurnStart();
141
+ });
142
+
143
+ // Run auto-clear BEFORE onAgentTurnEnd so the overlay's completed-tracking
144
+ // sets (pendingHide, hiddenCompleted) are still valid for any future logic
145
+ // in onAgentTurnEnd that references them. The overlay resets its display
146
+ // state separately at session lifecycle boundaries.
147
+ pi.on("agent_end", async (_event, ctx) => {
148
+ autoClearIfNoActiveTasks(ctx.sessionManager.getSessionId());
149
+ todoOverlay?.onAgentTurnEnd();
150
+ });
151
+ }
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env pwsh
2
+ # Per-extension installer — Windows / PowerShell
3
+ # Installs npm dependencies for this extension. No-op if no package.json.
4
+ $ErrorActionPreference = "Stop"
5
+ $extDir = $PSScriptRoot
6
+ if (-not $extDir) { $extDir = Split-Path -Parent $MyInvocation.MyCommand.Path }
7
+ if (-not (Test-Path "$extDir/package.json")) {
8
+ Write-Host " - no package.json — skipping" -ForegroundColor DarkGray
9
+ exit 0
10
+ }
11
+ if (-not (Get-Command npm -ErrorAction SilentlyContinue)) {
12
+ Write-Host " x npm not found — install Node.js 22+" -ForegroundColor Red
13
+ exit 1
14
+ }
15
+ if (Test-Path "$extDir/package-lock.json") {
16
+ Write-Host " - npm ci" -ForegroundColor DarkGray
17
+ npm --prefix $extDir ci --no-audit --no-fund
18
+ } else {
19
+ Write-Host " - npm install" -ForegroundColor DarkGray
20
+ npm --prefix $extDir install --no-audit --no-fund
21
+ }
22
+ if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
23
+ Write-Host " + done" -ForegroundColor Green
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ # Per-extension installer — macOS / Linux
3
+ # Installs npm dependencies for this extension. No-op if no package.json.
4
+ set -eu
5
+ EXT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+ if [ ! -f "$EXT_DIR/package.json" ]; then
7
+ echo " · no package.json — skipping"
8
+ exit 0
9
+ fi
10
+ if ! command -v npm >/dev/null 2>&1; then
11
+ echo " ✖ npm not found — install Node.js 22+" >&2
12
+ exit 1
13
+ fi
14
+ if [ -f "$EXT_DIR/package-lock.json" ]; then
15
+ echo " · npm ci"
16
+ npm --prefix "$EXT_DIR" ci --no-audit --no-fund
17
+ else
18
+ echo " · npm install"
19
+ npm --prefix "$EXT_DIR" install --no-audit --no-fund
20
+ fi
21
+ echo " ✓ done"
@@ -0,0 +1,17 @@
1
+ {
2
+ "_meta.notes": "Auto-translated draft. Native-speaker review welcome via PR. Unicode box-drawing characters (──) stay untranslated. Note: 'overlay.more' renders as '+5 weitere' which is grammatically loose for plural agreement — accepted for badge brevity.",
3
+
4
+ "status.pending": "ausstehend",
5
+ "status.in_progress": "in Bearbeitung",
6
+ "status.completed": "erledigt",
7
+ "status.deleted": "gelöscht",
8
+
9
+ "overlay.heading": "Todos",
10
+ "overlay.more": "weitere",
11
+
12
+ "command.no_todos": "Noch keine Todos. Bitte den Agenten, welche hinzuzufügen!",
13
+ "command.requires_interactive": "/todos erfordert den interaktiven Modus",
14
+ "command.section.pending": "── Ausstehend ──",
15
+ "command.section.in_progress": "── In Bearbeitung ──",
16
+ "command.section.completed": "── Erledigt ──"
17
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "status.pending": "pending",
3
+ "status.in_progress": "in progress",
4
+ "status.completed": "completed",
5
+ "status.deleted": "deleted",
6
+
7
+ "overlay.heading": "Todos",
8
+ "overlay.more": "more",
9
+
10
+ "command.no_todos": "No todos yet. Ask the agent to add some!",
11
+ "command.requires_interactive": "/todos requires interactive mode",
12
+ "command.section.pending": "── Pending ──",
13
+ "command.section.in_progress": "── In Progress ──",
14
+ "command.section.completed": "── Completed ──"
15
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "_meta.notes": "Auto-translated draft. Native-speaker review welcome via PR. Unicode box-drawing characters (──) stay untranslated.",
3
+
4
+ "status.pending": "pendientes",
5
+ "status.in_progress": "en curso",
6
+ "status.completed": "completadas",
7
+ "status.deleted": "eliminada",
8
+
9
+ "overlay.heading": "Tareas",
10
+ "overlay.more": "más",
11
+
12
+ "command.no_todos": "Sin tareas aún. ¡Pídele al agente que añada algunas!",
13
+ "command.requires_interactive": "/todos requiere modo interactivo",
14
+ "command.section.pending": "── Pendientes ──",
15
+ "command.section.in_progress": "── En curso ──",
16
+ "command.section.completed": "── Completadas ──"
17
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "_meta.notes": "Auto-translated draft. Native-speaker review welcome via PR. Unicode box-drawing characters (──) stay untranslated.",
3
+
4
+ "status.pending": "en attente",
5
+ "status.in_progress": "en cours",
6
+ "status.completed": "terminées",
7
+ "status.deleted": "supprimée",
8
+
9
+ "overlay.heading": "Tâches",
10
+ "overlay.more": "autres",
11
+
12
+ "command.no_todos": "Pas encore de tâches. Demandez à l'agent d'en ajouter !",
13
+ "command.requires_interactive": "/todos nécessite le mode interactif",
14
+ "command.section.pending": "── En attente ──",
15
+ "command.section.in_progress": "── En cours ──",
16
+ "command.section.completed": "── Terminées ──"
17
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "_meta.notes": "Auto-translated draft. Native-speaker review welcome via PR. Unicode box-drawing characters (──) stay untranslated.",
3
+
4
+ "status.pending": "pendentes",
5
+ "status.in_progress": "em andamento",
6
+ "status.completed": "concluídas",
7
+ "status.deleted": "excluída",
8
+
9
+ "overlay.heading": "Tarefas",
10
+ "overlay.more": "mais",
11
+
12
+ "command.no_todos": "Nenhuma tarefa ainda. Peça ao agente para adicionar algumas!",
13
+ "command.requires_interactive": "/todos requer modo interativo",
14
+ "command.section.pending": "── Pendentes ──",
15
+ "command.section.in_progress": "── Em andamento ──",
16
+ "command.section.completed": "── Concluídas ──"
17
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "_meta.notes": "Auto-translated draft. Native-speaker review welcome via PR. Unicode box-drawing characters (──) stay untranslated.",
3
+
4
+ "status.pending": "pendentes",
5
+ "status.in_progress": "em curso",
6
+ "status.completed": "concluídas",
7
+ "status.deleted": "eliminada",
8
+
9
+ "overlay.heading": "Tarefas",
10
+ "overlay.more": "mais",
11
+
12
+ "command.no_todos": "Sem tarefas ainda. Peça ao agente para adicionar algumas!",
13
+ "command.requires_interactive": "/todos requer modo interativo",
14
+ "command.section.pending": "── Pendentes ──",
15
+ "command.section.in_progress": "── Em curso ──",
16
+ "command.section.completed": "── Concluídas ──"
17
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "_meta.notes": "Автоперевод. Приветствуется проверка носителем языка через PR. Символы юникода (──) не переводятся.",
3
+
4
+ "status.pending": "ожидание",
5
+ "status.in_progress": "в работе",
6
+ "status.completed": "выполнено",
7
+ "status.deleted": "удалена",
8
+
9
+ "overlay.heading": "Задачи",
10
+ "overlay.more": "ещё",
11
+
12
+ "command.no_todos": "Задач пока нет. Попросите агента добавить!",
13
+ "command.requires_interactive": "/todos требует интерактивного режима",
14
+ "command.section.pending": "── Ожидание ──",
15
+ "command.section.in_progress": "── В работе ──",
16
+ "command.section.completed": "── Выполнено ──"
17
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "_meta.notes": "Автопереклад. Привітна перевірка носієм мови через PR. Символи юнікоду (──) не перекладаються.",
3
+
4
+ "status.pending": "очікування",
5
+ "status.in_progress": "у роботі",
6
+ "status.completed": "виконано",
7
+ "status.deleted": "видалено",
8
+
9
+ "overlay.heading": "Завдання",
10
+ "overlay.more": "ще",
11
+
12
+ "command.no_todos": "Завдань поки немає. Попросіть агента додати!",
13
+ "command.requires_interactive": "/todos потребує інтерактивного режиму",
14
+ "command.section.pending": "── Очікування ──",
15
+ "command.section.in_progress": "── У роботі ──",
16
+ "command.section.completed": "── Виконано ──"
17
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "_meta.notes": "中文翻译。欢迎中文母语者通过 PR 审校。",
3
+
4
+ "status.pending": "待处理",
5
+ "status.in_progress": "进行中",
6
+ "status.completed": "已完成",
7
+ "status.deleted": "已删除",
8
+
9
+ "overlay.heading": "任务清单",
10
+ "overlay.more": "更多",
11
+
12
+ "command.no_todos": "暂无任务。可以让 agent 添加一些!",
13
+ "command.requires_interactive": "/todos 需要交互模式",
14
+ "command.section.pending": "── 待处理 ──",
15
+ "command.section.in_progress": "── 进行中 ──",
16
+ "command.section.completed": "── 已完成 ──"
17
+ }