@vitos-pizza/vitos-pizza 0.1.0 → 0.2.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 (259) hide show
  1. package/AGENTS.md +158 -158
  2. package/CHANGELOG.md +42 -24
  3. package/LICENSE +21 -21
  4. package/README.md +237 -234
  5. package/assets/logo.svg +28 -28
  6. package/node_modules/@vitos-pizza/agent-mode/extensions/index.ts +138 -117
  7. package/node_modules/@vitos-pizza/agent-mode/package.json +3 -3
  8. package/node_modules/@vitos-pizza/agent-mode/src/apply-mode.ts +60 -60
  9. package/node_modules/@vitos-pizza/agent-mode/src/mode-events.ts +102 -102
  10. package/node_modules/@vitos-pizza/agent-mode/src/modes.ts +43 -43
  11. package/node_modules/@vitos-pizza/agent-mode/src/plan-instructions.ts +85 -44
  12. package/node_modules/@vitos-pizza/agent-mode/tests/apply-mode.test.ts +36 -36
  13. package/node_modules/@vitos-pizza/agent-mode/tests/mode-events.test.ts +22 -22
  14. package/node_modules/@vitos-pizza/agent-mode/tests/modes.test.ts +38 -38
  15. package/node_modules/@vitos-pizza/agent-mode/tests/plan-instructions.test.ts +68 -45
  16. package/node_modules/@vitos-pizza/agent-mode/tsconfig.json +13 -13
  17. package/node_modules/@vitos-pizza/agent-mode/vitest.config.ts +8 -8
  18. package/node_modules/@vitos-pizza/keybindings/extensions/index.ts +104 -104
  19. package/node_modules/@vitos-pizza/keybindings/package.json +1 -1
  20. package/node_modules/@vitos-pizza/keybindings/presets/shortcuts.json +3 -3
  21. package/node_modules/@vitos-pizza/keybindings/src/bind.ts +57 -57
  22. package/node_modules/@vitos-pizza/keybindings/src/config.ts +84 -84
  23. package/node_modules/@vitos-pizza/keybindings/src/registry.ts +43 -43
  24. package/node_modules/@vitos-pizza/keybindings/src/types.ts +54 -54
  25. package/node_modules/@vitos-pizza/keybindings/tests/config.test.ts +83 -83
  26. package/node_modules/@vitos-pizza/keybindings/tests/registry.test.ts +142 -142
  27. package/node_modules/@vitos-pizza/keybindings/tsconfig.json +13 -13
  28. package/node_modules/@vitos-pizza/keybindings/vitest.config.ts +8 -8
  29. package/node_modules/@vitos-pizza/permission-system/extensions/index.ts +162 -162
  30. package/node_modules/@vitos-pizza/permission-system/package.json +2 -2
  31. package/node_modules/@vitos-pizza/permission-system/src/bash/matcher.ts +54 -51
  32. package/node_modules/@vitos-pizza/permission-system/src/bash/parser.ts +40 -40
  33. package/node_modules/@vitos-pizza/permission-system/src/config-paths.ts +23 -23
  34. package/node_modules/@vitos-pizza/permission-system/src/detect-preset-mode.ts +61 -61
  35. package/node_modules/@vitos-pizza/permission-system/src/expand-home.ts +12 -12
  36. package/node_modules/@vitos-pizza/permission-system/src/forwarding/forwarder.ts +224 -224
  37. package/node_modules/@vitos-pizza/permission-system/src/forwarding/subagent-registry.ts +61 -61
  38. package/node_modules/@vitos-pizza/permission-system/src/gates/path-utils.ts +66 -66
  39. package/node_modules/@vitos-pizza/permission-system/src/gates/pipeline.ts +151 -155
  40. package/node_modules/@vitos-pizza/permission-system/src/handlers/before-agent-start.ts +86 -65
  41. package/node_modules/@vitos-pizza/permission-system/src/handlers/skill-input.ts +1 -1
  42. package/node_modules/@vitos-pizza/permission-system/src/handlers/tool-call-gate.ts +204 -199
  43. package/node_modules/@vitos-pizza/permission-system/src/mode-api.ts +44 -44
  44. package/node_modules/@vitos-pizza/permission-system/src/permission-evaluator.ts +233 -216
  45. package/node_modules/@vitos-pizza/permission-system/src/permission-session.ts +62 -62
  46. package/node_modules/@vitos-pizza/permission-system/src/policy-loader.ts +211 -211
  47. package/node_modules/@vitos-pizza/permission-system/src/sanitizers/skill-prompt.ts +99 -99
  48. package/node_modules/@vitos-pizza/permission-system/src/sanitizers/system-prompt.ts +221 -221
  49. package/node_modules/@vitos-pizza/permission-system/src/service.ts +66 -66
  50. package/node_modules/@vitos-pizza/permission-system/src/session-approvals.ts +4 -1
  51. package/node_modules/@vitos-pizza/permission-system/src/types.ts +80 -80
  52. package/node_modules/@vitos-pizza/permission-system/src/ui/approval-summary.ts +43 -43
  53. package/node_modules/@vitos-pizza/permission-system/src/ui/config-modal.ts +36 -36
  54. package/node_modules/@vitos-pizza/permission-system/src/ui/permission-dialog.ts +52 -52
  55. package/node_modules/@vitos-pizza/permission-system/src/wildcard-matcher.ts +81 -81
  56. package/node_modules/@vitos-pizza/permission-system/src/yaml-frontmatter.ts +84 -84
  57. package/node_modules/@vitos-pizza/permission-system/src/yolo/runtime-api.ts +49 -49
  58. package/node_modules/@vitos-pizza/permission-system/tests/bash-parser.test.ts +32 -32
  59. package/node_modules/@vitos-pizza/permission-system/tests/before-agent-start.test.ts +61 -0
  60. package/node_modules/@vitos-pizza/permission-system/tests/detect-preset-mode.test.ts +68 -68
  61. package/node_modules/@vitos-pizza/permission-system/tests/forwarder.test.ts +55 -55
  62. package/node_modules/@vitos-pizza/permission-system/tests/gates.test.ts +170 -61
  63. package/node_modules/@vitos-pizza/permission-system/tests/path-utils.test.ts +68 -68
  64. package/node_modules/@vitos-pizza/permission-system/tests/permission-evaluator.test.ts +82 -55
  65. package/node_modules/@vitos-pizza/permission-system/tests/policy-loader.test.ts +25 -25
  66. package/node_modules/@vitos-pizza/permission-system/tests/system-prompt-sanitizer.test.ts +22 -22
  67. package/node_modules/@vitos-pizza/permission-system/tests/wildcard-matcher.test.ts +27 -27
  68. package/node_modules/@vitos-pizza/permission-system/tsconfig.json +13 -13
  69. package/node_modules/@vitos-pizza/permission-system/vitest.config.ts +8 -8
  70. package/node_modules/@vitos-pizza/question/package.json +1 -1
  71. package/node_modules/@vitos-pizza/question/src/question-ui.ts +5 -1
  72. package/node_modules/@vitos-pizza/question/src/register-tool.ts +1 -4
  73. package/node_modules/@vitos-pizza/question/tests/question-ui-width-cache.test.ts +45 -0
  74. package/node_modules/@vitos-pizza/question/tests/register-tool-render.test.ts +48 -45
  75. package/node_modules/@vitos-pizza/session-title/extensions/index.ts +137 -137
  76. package/node_modules/@vitos-pizza/session-title/package.json +3 -3
  77. package/node_modules/@vitos-pizza/session-title/src/build-title-prompt.ts +16 -16
  78. package/node_modules/@vitos-pizza/session-title/src/extract-title-context.ts +55 -55
  79. package/node_modules/@vitos-pizza/session-title/src/fast-rules.ts +48 -48
  80. package/node_modules/@vitos-pizza/session-title/src/load-settings.ts +70 -70
  81. package/node_modules/@vitos-pizza/session-title/src/normalize-title.ts +20 -20
  82. package/node_modules/@vitos-pizza/session-title/src/parse-title-response.ts +6 -6
  83. package/node_modules/@vitos-pizza/session-title/src/resolve-title-model.ts +33 -33
  84. package/node_modules/@vitos-pizza/session-title/src/schedule-title-job.ts +53 -53
  85. package/node_modules/@vitos-pizza/session-title/src/should-schedule.ts +30 -30
  86. package/node_modules/@vitos-pizza/session-title/src/title-agent.ts +60 -60
  87. package/node_modules/@vitos-pizza/session-title/src/truncate-input.ts +10 -10
  88. package/node_modules/@vitos-pizza/session-title/src/types.ts +29 -29
  89. package/node_modules/@vitos-pizza/session-title/tests/build-title-prompt.test.ts +34 -34
  90. package/node_modules/@vitos-pizza/session-title/tests/extension.test.ts +198 -198
  91. package/node_modules/@vitos-pizza/session-title/tests/extract-title-context.test.ts +48 -48
  92. package/node_modules/@vitos-pizza/session-title/tests/fast-rules.test.ts +43 -43
  93. package/node_modules/@vitos-pizza/session-title/tests/parse-title-response.test.ts +34 -34
  94. package/node_modules/@vitos-pizza/session-title/tests/should-schedule.test.ts +30 -30
  95. package/node_modules/@vitos-pizza/session-title/tests/title-agent.test.ts +154 -154
  96. package/node_modules/@vitos-pizza/session-title/tests/truncate-input.test.ts +15 -15
  97. package/node_modules/@vitos-pizza/session-title/tsconfig.json +13 -13
  98. package/node_modules/@vitos-pizza/session-title/vitest.config.ts +8 -8
  99. package/node_modules/@vitos-pizza/subagents/agents/planner.md +46 -43
  100. package/node_modules/@vitos-pizza/subagents/agents/scout.md +40 -40
  101. package/node_modules/@vitos-pizza/subagents/agents/title.md +13 -13
  102. package/node_modules/@vitos-pizza/subagents/agents/worker.md +36 -36
  103. package/node_modules/@vitos-pizza/subagents/extensions/index.ts +164 -164
  104. package/node_modules/@vitos-pizza/subagents/package.json +1 -1
  105. package/node_modules/@vitos-pizza/subagents/skills/subagents/SKILL.md +86 -80
  106. package/node_modules/@vitos-pizza/subagents/src/agents.ts +166 -166
  107. package/node_modules/@vitos-pizza/subagents/src/async/job-tracker.ts +71 -71
  108. package/node_modules/@vitos-pizza/subagents/src/async/spawn-async.ts +220 -220
  109. package/node_modules/@vitos-pizza/subagents/src/async/storage.ts +57 -57
  110. package/node_modules/@vitos-pizza/subagents/src/env.ts +4 -4
  111. package/node_modules/@vitos-pizza/subagents/src/execute-subagent.ts +285 -285
  112. package/node_modules/@vitos-pizza/subagents/src/progress.ts +187 -187
  113. package/node_modules/@vitos-pizza/subagents/src/render-animation.ts +40 -40
  114. package/node_modules/@vitos-pizza/subagents/src/render.ts +428 -428
  115. package/node_modules/@vitos-pizza/subagents/src/rpc/channels.ts +21 -21
  116. package/node_modules/@vitos-pizza/subagents/src/rpc/client.ts +144 -144
  117. package/node_modules/@vitos-pizza/subagents/src/rpc/server.ts +11 -11
  118. package/node_modules/@vitos-pizza/subagents/src/run-agent.ts +313 -313
  119. package/node_modules/@vitos-pizza/subagents/src/runtime.ts +102 -102
  120. package/node_modules/@vitos-pizza/subagents/src/schema.ts +62 -62
  121. package/node_modules/@vitos-pizza/subagents/src/spawn.ts +104 -104
  122. package/node_modules/@vitos-pizza/subagents/src/types.ts +92 -92
  123. package/node_modules/@vitos-pizza/subagents/src/utils.ts +100 -100
  124. package/node_modules/@vitos-pizza/subagents/src/wait.ts +159 -159
  125. package/node_modules/@vitos-pizza/subagents/tests/agents.test.ts +19 -19
  126. package/node_modules/@vitos-pizza/subagents/tests/execute-subagent.test.ts +96 -96
  127. package/node_modules/@vitos-pizza/subagents/tests/extension.test.ts +42 -42
  128. package/node_modules/@vitos-pizza/subagents/tests/progress.test.ts +206 -206
  129. package/node_modules/@vitos-pizza/subagents/tests/rpc.test.ts +74 -74
  130. package/node_modules/@vitos-pizza/subagents/tsconfig.json +13 -13
  131. package/node_modules/@vitos-pizza/subagents/vitest.config.ts +8 -8
  132. package/node_modules/@vitos-pizza/ui-enhancements/package.json +1 -1
  133. package/node_modules/@vitos-pizza/ui-enhancements/src/chrome/agent-mode-badge.ts +60 -60
  134. package/node_modules/@vitos-pizza/ui-enhancements/src/chrome/border-status.ts +14 -1
  135. package/node_modules/@vitos-pizza/ui-enhancements/src/chrome/resize-recovery.ts +63 -0
  136. package/node_modules/@vitos-pizza/ui-enhancements/tests/agent-mode-badge.test.ts +35 -35
  137. package/node_modules/@vitos-pizza/ui-enhancements/tests/resize-recovery.test.ts +135 -0
  138. package/node_modules/@vitos-pizza/websearch/package.json +1 -1
  139. package/node_modules/node-addon-api/tools/conversion.js +0 -0
  140. package/node_modules/node-gyp-build/bin.js +0 -0
  141. package/node_modules/node-gyp-build/build-test.js +0 -0
  142. package/node_modules/node-gyp-build/optional.js +0 -0
  143. package/package.json +11 -9
  144. package/packages/agent-mode/extensions/index.ts +138 -117
  145. package/packages/agent-mode/package.json +3 -3
  146. package/packages/agent-mode/src/apply-mode.ts +60 -60
  147. package/packages/agent-mode/src/mode-events.ts +102 -102
  148. package/packages/agent-mode/src/modes.ts +43 -43
  149. package/packages/agent-mode/src/plan-instructions.ts +85 -44
  150. package/packages/agent-mode/tsconfig.json +13 -13
  151. package/packages/agent-mode/vitest.config.ts +8 -8
  152. package/packages/keybindings/extensions/index.ts +104 -104
  153. package/packages/keybindings/package.json +1 -1
  154. package/packages/keybindings/presets/shortcuts.json +3 -3
  155. package/packages/keybindings/src/bind.ts +57 -57
  156. package/packages/keybindings/src/config.ts +84 -84
  157. package/packages/keybindings/src/registry.ts +43 -43
  158. package/packages/keybindings/src/types.ts +54 -54
  159. package/packages/keybindings/tsconfig.json +13 -13
  160. package/packages/keybindings/vitest.config.ts +8 -8
  161. package/packages/permission-system/extensions/index.ts +162 -162
  162. package/packages/permission-system/node_modules/web-tree-sitter/debug/tree-sitter.wasm +0 -0
  163. package/packages/permission-system/node_modules/web-tree-sitter/tree-sitter.wasm +0 -0
  164. package/packages/permission-system/package.json +2 -2
  165. package/packages/permission-system/src/bash/matcher.ts +54 -51
  166. package/packages/permission-system/src/bash/parser.ts +40 -40
  167. package/packages/permission-system/src/config-paths.ts +23 -23
  168. package/packages/permission-system/src/detect-preset-mode.ts +61 -61
  169. package/packages/permission-system/src/expand-home.ts +12 -12
  170. package/packages/permission-system/src/forwarding/forwarder.ts +224 -224
  171. package/packages/permission-system/src/forwarding/subagent-registry.ts +61 -61
  172. package/packages/permission-system/src/gates/path-utils.ts +66 -66
  173. package/packages/permission-system/src/gates/pipeline.ts +151 -155
  174. package/packages/permission-system/src/handlers/before-agent-start.ts +86 -65
  175. package/packages/permission-system/src/handlers/skill-input.ts +1 -1
  176. package/packages/permission-system/src/handlers/tool-call-gate.ts +204 -199
  177. package/packages/permission-system/src/mode-api.ts +44 -44
  178. package/packages/permission-system/src/permission-evaluator.ts +233 -216
  179. package/packages/permission-system/src/permission-session.ts +62 -62
  180. package/packages/permission-system/src/policy-loader.ts +211 -211
  181. package/packages/permission-system/src/sanitizers/skill-prompt.ts +99 -99
  182. package/packages/permission-system/src/sanitizers/system-prompt.ts +221 -221
  183. package/packages/permission-system/src/service.ts +66 -66
  184. package/packages/permission-system/src/session-approvals.ts +4 -1
  185. package/packages/permission-system/src/types.ts +80 -80
  186. package/packages/permission-system/src/ui/approval-summary.ts +43 -43
  187. package/packages/permission-system/src/ui/config-modal.ts +36 -36
  188. package/packages/permission-system/src/ui/permission-dialog.ts +52 -52
  189. package/packages/permission-system/src/wildcard-matcher.ts +81 -81
  190. package/packages/permission-system/src/yaml-frontmatter.ts +84 -84
  191. package/packages/permission-system/src/yolo/runtime-api.ts +49 -49
  192. package/packages/permission-system/tsconfig.json +13 -13
  193. package/packages/permission-system/vitest.config.ts +8 -8
  194. package/packages/question/package.json +1 -1
  195. package/packages/question/src/question-ui.ts +5 -1
  196. package/packages/question/src/register-tool.ts +1 -4
  197. package/packages/session-title/extensions/index.ts +137 -137
  198. package/packages/session-title/package.json +3 -3
  199. package/packages/session-title/src/build-title-prompt.ts +16 -16
  200. package/packages/session-title/src/extract-title-context.ts +55 -55
  201. package/packages/session-title/src/fast-rules.ts +48 -48
  202. package/packages/session-title/src/load-settings.ts +70 -70
  203. package/packages/session-title/src/normalize-title.ts +20 -20
  204. package/packages/session-title/src/parse-title-response.ts +6 -6
  205. package/packages/session-title/src/resolve-title-model.ts +33 -33
  206. package/packages/session-title/src/schedule-title-job.ts +53 -53
  207. package/packages/session-title/src/should-schedule.ts +30 -30
  208. package/packages/session-title/src/title-agent.ts +60 -60
  209. package/packages/session-title/src/truncate-input.ts +10 -10
  210. package/packages/session-title/src/types.ts +29 -29
  211. package/packages/session-title/tsconfig.json +13 -13
  212. package/packages/session-title/vitest.config.ts +8 -8
  213. package/packages/subagents/agents/planner.md +46 -43
  214. package/packages/subagents/agents/scout.md +40 -40
  215. package/packages/subagents/agents/title.md +13 -13
  216. package/packages/subagents/agents/worker.md +36 -36
  217. package/packages/subagents/extensions/index.ts +164 -164
  218. package/packages/subagents/package.json +1 -1
  219. package/packages/subagents/skills/subagents/SKILL.md +86 -80
  220. package/packages/subagents/src/agents.ts +166 -166
  221. package/packages/subagents/src/async/job-tracker.ts +71 -71
  222. package/packages/subagents/src/async/spawn-async.ts +220 -220
  223. package/packages/subagents/src/async/storage.ts +57 -57
  224. package/packages/subagents/src/env.ts +4 -4
  225. package/packages/subagents/src/execute-subagent.ts +285 -285
  226. package/packages/subagents/src/progress.ts +187 -187
  227. package/packages/subagents/src/render-animation.ts +40 -40
  228. package/packages/subagents/src/render.ts +428 -428
  229. package/packages/subagents/src/rpc/channels.ts +21 -21
  230. package/packages/subagents/src/rpc/client.ts +144 -144
  231. package/packages/subagents/src/rpc/server.ts +11 -11
  232. package/packages/subagents/src/run-agent.ts +313 -313
  233. package/packages/subagents/src/runtime.ts +102 -102
  234. package/packages/subagents/src/schema.ts +62 -62
  235. package/packages/subagents/src/spawn.ts +104 -104
  236. package/packages/subagents/src/types.ts +92 -92
  237. package/packages/subagents/src/utils.ts +100 -100
  238. package/packages/subagents/src/wait.ts +159 -159
  239. package/packages/subagents/tsconfig.json +13 -13
  240. package/packages/subagents/vitest.config.ts +8 -8
  241. package/packages/todoist/extensions/index.ts +163 -0
  242. package/packages/todoist/package.json +34 -0
  243. package/packages/todoist/src/events.ts +7 -0
  244. package/packages/todoist/src/silent-render.ts +8 -0
  245. package/packages/todoist/src/state.ts +147 -0
  246. package/packages/todoist/src/tools.ts +175 -0
  247. package/packages/todoist/src/types.ts +34 -0
  248. package/packages/todoist/src/widget.ts +109 -0
  249. package/packages/todoist/tsconfig.json +13 -0
  250. package/packages/todoist/vitest.config.ts +8 -0
  251. package/packages/ui-enhancements/package.json +1 -1
  252. package/packages/ui-enhancements/src/chrome/agent-mode-badge.ts +60 -60
  253. package/packages/ui-enhancements/src/chrome/border-status.ts +14 -1
  254. package/packages/ui-enhancements/src/chrome/resize-recovery.ts +63 -0
  255. package/packages/websearch/package.json +1 -1
  256. package/scripts/sync-pi-manifest.mjs +1 -1
  257. package/packages/permission-system/node_modules/web-tree-sitter/lib/tree-sitter.cjs +0 -2988
  258. package/packages/permission-system/node_modules/web-tree-sitter/lib/tree-sitter.wasm +0 -0
  259. package/packages/permission-system/node_modules/web-tree-sitter/lib/tree-sitter.wasm.map +0 -1
@@ -1,166 +1,166 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import {
5
- CONFIG_DIR_NAME,
6
- getAgentDir,
7
- parseFrontmatter,
8
- } from "@earendil-works/pi-coding-agent";
9
- import type { AgentScope } from "./types.ts";
10
-
11
- export interface AgentConfig {
12
- name: string;
13
- description: string;
14
- tools?: string[];
15
- model?: string;
16
- thinking?: string;
17
- systemPromptMode?: "append" | "replace";
18
- systemPrompt: string;
19
- source: "builtin" | "user" | "project";
20
- filePath: string;
21
- }
22
-
23
- export interface AgentDiscoveryResult {
24
- agents: AgentConfig[];
25
- projectAgentsDir: string | null;
26
- builtinAgentsDir: string;
27
- }
28
-
29
- const THINKING_LEVELS = new Set([
30
- "off",
31
- "minimal",
32
- "low",
33
- "medium",
34
- "high",
35
- "xhigh",
36
- "max",
37
- ]);
38
-
39
- export function getBuiltinAgentsDir(): string {
40
- return path.join(
41
- path.dirname(fileURLToPath(import.meta.url)),
42
- "..",
43
- "agents",
44
- );
45
- }
46
-
47
- function loadAgentsFromDir(
48
- dir: string,
49
- source: AgentConfig["source"],
50
- ): AgentConfig[] {
51
- if (!fs.existsSync(dir)) return [];
52
-
53
- let entries: fs.Dirent[];
54
- try {
55
- entries = fs.readdirSync(dir, { withFileTypes: true });
56
- } catch {
57
- return [];
58
- }
59
-
60
- const agents: AgentConfig[] = [];
61
- for (const entry of entries) {
62
- if (!entry.name.endsWith(".md")) continue;
63
- if (!entry.isFile() && !entry.isSymbolicLink()) continue;
64
-
65
- const filePath = path.join(dir, entry.name);
66
- let content: string;
67
- try {
68
- content = fs.readFileSync(filePath, "utf-8");
69
- } catch {
70
- continue;
71
- }
72
-
73
- const { frontmatter, body } = parseFrontmatter<Record<string, string>>(
74
- content,
75
- );
76
- if (!frontmatter.name || !frontmatter.description) continue;
77
-
78
- const tools = frontmatter.tools
79
- ?.split(",")
80
- .map((tool) => tool.trim())
81
- .filter(Boolean);
82
-
83
- const systemPromptMode =
84
- frontmatter.systemPromptMode === "append" ? "append" : "replace";
85
-
86
- agents.push({
87
- name: frontmatter.name,
88
- description: frontmatter.description,
89
- tools: tools && tools.length > 0 ? tools : undefined,
90
- model: frontmatter.model,
91
- thinking: frontmatter.thinking,
92
- systemPromptMode,
93
- systemPrompt: body,
94
- source,
95
- filePath,
96
- });
97
- }
98
-
99
- return agents;
100
- }
101
-
102
- function isDirectory(candidate: string): boolean {
103
- try {
104
- return fs.statSync(candidate).isDirectory();
105
- } catch {
106
- return false;
107
- }
108
- }
109
-
110
- function findNearestProjectAgentsDir(cwd: string): string | null {
111
- let currentDir = cwd;
112
- while (true) {
113
- const candidate = path.join(currentDir, CONFIG_DIR_NAME, "agents");
114
- if (isDirectory(candidate)) return candidate;
115
-
116
- const parentDir = path.dirname(currentDir);
117
- if (parentDir === currentDir) return null;
118
- currentDir = parentDir;
119
- }
120
- }
121
-
122
- export function applyThinkingSuffix(
123
- model: string | undefined,
124
- thinking: string | undefined,
125
- ): string | undefined {
126
- if (!model || !thinking) return model;
127
- const colonIdx = model.lastIndexOf(":");
128
- if (
129
- colonIdx !== -1 &&
130
- THINKING_LEVELS.has(model.substring(colonIdx + 1))
131
- ) {
132
- return `${model.slice(0, colonIdx)}:${thinking}`;
133
- }
134
- return `${model}:${thinking}`;
135
- }
136
-
137
- export function discoverAgents(
138
- cwd: string,
139
- scope: AgentScope = "both",
140
- ): AgentDiscoveryResult {
141
- const builtinAgentsDir = getBuiltinAgentsDir();
142
- const userDir = path.join(getAgentDir(), "agents");
143
- const projectAgentsDir = findNearestProjectAgentsDir(cwd);
144
-
145
- const builtinAgents = loadAgentsFromDir(builtinAgentsDir, "builtin");
146
- const userAgents = scope === "project" ? [] : loadAgentsFromDir(userDir, "user");
147
- const projectAgents =
148
- scope === "user" || !projectAgentsDir
149
- ? []
150
- : loadAgentsFromDir(projectAgentsDir, "project");
151
-
152
- const agentMap = new Map<string, AgentConfig>();
153
- for (const agent of builtinAgents) agentMap.set(agent.name, agent);
154
- if (scope === "both" || scope === "user") {
155
- for (const agent of userAgents) agentMap.set(agent.name, agent);
156
- }
157
- if (scope === "both" || scope === "project") {
158
- for (const agent of projectAgents) agentMap.set(agent.name, agent);
159
- }
160
-
161
- return {
162
- agents: Array.from(agentMap.values()),
163
- projectAgentsDir,
164
- builtinAgentsDir,
165
- };
166
- }
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import {
5
+ CONFIG_DIR_NAME,
6
+ getAgentDir,
7
+ parseFrontmatter,
8
+ } from "@earendil-works/pi-coding-agent";
9
+ import type { AgentScope } from "./types.ts";
10
+
11
+ export interface AgentConfig {
12
+ name: string;
13
+ description: string;
14
+ tools?: string[];
15
+ model?: string;
16
+ thinking?: string;
17
+ systemPromptMode?: "append" | "replace";
18
+ systemPrompt: string;
19
+ source: "builtin" | "user" | "project";
20
+ filePath: string;
21
+ }
22
+
23
+ export interface AgentDiscoveryResult {
24
+ agents: AgentConfig[];
25
+ projectAgentsDir: string | null;
26
+ builtinAgentsDir: string;
27
+ }
28
+
29
+ const THINKING_LEVELS = new Set([
30
+ "off",
31
+ "minimal",
32
+ "low",
33
+ "medium",
34
+ "high",
35
+ "xhigh",
36
+ "max",
37
+ ]);
38
+
39
+ export function getBuiltinAgentsDir(): string {
40
+ return path.join(
41
+ path.dirname(fileURLToPath(import.meta.url)),
42
+ "..",
43
+ "agents",
44
+ );
45
+ }
46
+
47
+ function loadAgentsFromDir(
48
+ dir: string,
49
+ source: AgentConfig["source"],
50
+ ): AgentConfig[] {
51
+ if (!fs.existsSync(dir)) return [];
52
+
53
+ let entries: fs.Dirent[];
54
+ try {
55
+ entries = fs.readdirSync(dir, { withFileTypes: true });
56
+ } catch {
57
+ return [];
58
+ }
59
+
60
+ const agents: AgentConfig[] = [];
61
+ for (const entry of entries) {
62
+ if (!entry.name.endsWith(".md")) continue;
63
+ if (!entry.isFile() && !entry.isSymbolicLink()) continue;
64
+
65
+ const filePath = path.join(dir, entry.name);
66
+ let content: string;
67
+ try {
68
+ content = fs.readFileSync(filePath, "utf-8");
69
+ } catch {
70
+ continue;
71
+ }
72
+
73
+ const { frontmatter, body } = parseFrontmatter<Record<string, string>>(
74
+ content,
75
+ );
76
+ if (!frontmatter.name || !frontmatter.description) continue;
77
+
78
+ const tools = frontmatter.tools
79
+ ?.split(",")
80
+ .map((tool) => tool.trim())
81
+ .filter(Boolean);
82
+
83
+ const systemPromptMode =
84
+ frontmatter.systemPromptMode === "append" ? "append" : "replace";
85
+
86
+ agents.push({
87
+ name: frontmatter.name,
88
+ description: frontmatter.description,
89
+ tools: tools && tools.length > 0 ? tools : undefined,
90
+ model: frontmatter.model,
91
+ thinking: frontmatter.thinking,
92
+ systemPromptMode,
93
+ systemPrompt: body,
94
+ source,
95
+ filePath,
96
+ });
97
+ }
98
+
99
+ return agents;
100
+ }
101
+
102
+ function isDirectory(candidate: string): boolean {
103
+ try {
104
+ return fs.statSync(candidate).isDirectory();
105
+ } catch {
106
+ return false;
107
+ }
108
+ }
109
+
110
+ function findNearestProjectAgentsDir(cwd: string): string | null {
111
+ let currentDir = cwd;
112
+ while (true) {
113
+ const candidate = path.join(currentDir, CONFIG_DIR_NAME, "agents");
114
+ if (isDirectory(candidate)) return candidate;
115
+
116
+ const parentDir = path.dirname(currentDir);
117
+ if (parentDir === currentDir) return null;
118
+ currentDir = parentDir;
119
+ }
120
+ }
121
+
122
+ export function applyThinkingSuffix(
123
+ model: string | undefined,
124
+ thinking: string | undefined,
125
+ ): string | undefined {
126
+ if (!model || !thinking) return model;
127
+ const colonIdx = model.lastIndexOf(":");
128
+ if (
129
+ colonIdx !== -1 &&
130
+ THINKING_LEVELS.has(model.substring(colonIdx + 1))
131
+ ) {
132
+ return `${model.slice(0, colonIdx)}:${thinking}`;
133
+ }
134
+ return `${model}:${thinking}`;
135
+ }
136
+
137
+ export function discoverAgents(
138
+ cwd: string,
139
+ scope: AgentScope = "both",
140
+ ): AgentDiscoveryResult {
141
+ const builtinAgentsDir = getBuiltinAgentsDir();
142
+ const userDir = path.join(getAgentDir(), "agents");
143
+ const projectAgentsDir = findNearestProjectAgentsDir(cwd);
144
+
145
+ const builtinAgents = loadAgentsFromDir(builtinAgentsDir, "builtin");
146
+ const userAgents = scope === "project" ? [] : loadAgentsFromDir(userDir, "user");
147
+ const projectAgents =
148
+ scope === "user" || !projectAgentsDir
149
+ ? []
150
+ : loadAgentsFromDir(projectAgentsDir, "project");
151
+
152
+ const agentMap = new Map<string, AgentConfig>();
153
+ for (const agent of builtinAgents) agentMap.set(agent.name, agent);
154
+ if (scope === "both" || scope === "user") {
155
+ for (const agent of userAgents) agentMap.set(agent.name, agent);
156
+ }
157
+ if (scope === "both" || scope === "project") {
158
+ for (const agent of projectAgents) agentMap.set(agent.name, agent);
159
+ }
160
+
161
+ return {
162
+ agents: Array.from(agentMap.values()),
163
+ projectAgentsDir,
164
+ builtinAgentsDir,
165
+ };
166
+ }
@@ -1,71 +1,71 @@
1
- import {
2
- SUBAGENT_ASYNC_COMPLETE,
3
- SUBAGENT_ASYNC_STARTED,
4
- } from "../rpc/channels.ts";
5
- import type { AsyncRunStatus, ExecuteSubagentInput } from "../types.ts";
6
-
7
- export interface AsyncJobTracker {
8
- track(runId: string, status: AsyncRunStatus): void;
9
- update(runId: string, patch: Partial<AsyncRunStatus>): void;
10
- get(runId: string): AsyncRunStatus | undefined;
11
- list(): AsyncRunStatus[];
12
- remove(runId: string): void;
13
- clear(): void;
14
- }
15
-
16
- export function createAsyncJobTracker(): AsyncJobTracker {
17
- const jobs = new Map<string, AsyncRunStatus>();
18
-
19
- return {
20
- track(runId, status) {
21
- jobs.set(runId, status);
22
- },
23
- update(runId, patch) {
24
- const current = jobs.get(runId);
25
- if (!current) return;
26
- jobs.set(runId, { ...current, ...patch, updatedAt: Date.now() });
27
- },
28
- get(runId) {
29
- return jobs.get(runId);
30
- },
31
- list() {
32
- return Array.from(jobs.values());
33
- },
34
- remove(runId) {
35
- jobs.delete(runId);
36
- },
37
- clear() {
38
- jobs.clear();
39
- },
40
- };
41
- }
42
-
43
- export interface SubagentEventBus {
44
- emit(channel: string, payload: unknown): void;
45
- on(channel: string, handler: (payload: unknown) => void): () => void;
46
- }
47
-
48
- export function emitAsyncStarted(
49
- events: SubagentEventBus | undefined,
50
- payload: {
51
- id: string;
52
- mode: AsyncRunStatus["mode"];
53
- sessionId: string | null;
54
- agents: string[];
55
- },
56
- ): void {
57
- events?.emit(SUBAGENT_ASYNC_STARTED, payload);
58
- }
59
-
60
- export function emitAsyncComplete(
61
- events: SubagentEventBus | undefined,
62
- payload: {
63
- id: string;
64
- exitCode: number;
65
- finalOutput: string;
66
- },
67
- ): void {
68
- events?.emit(SUBAGENT_ASYNC_COMPLETE, payload);
69
- }
70
-
71
- export type AsyncExecuteInput = ExecuteSubagentInput;
1
+ import {
2
+ SUBAGENT_ASYNC_COMPLETE,
3
+ SUBAGENT_ASYNC_STARTED,
4
+ } from "../rpc/channels.ts";
5
+ import type { AsyncRunStatus, ExecuteSubagentInput } from "../types.ts";
6
+
7
+ export interface AsyncJobTracker {
8
+ track(runId: string, status: AsyncRunStatus): void;
9
+ update(runId: string, patch: Partial<AsyncRunStatus>): void;
10
+ get(runId: string): AsyncRunStatus | undefined;
11
+ list(): AsyncRunStatus[];
12
+ remove(runId: string): void;
13
+ clear(): void;
14
+ }
15
+
16
+ export function createAsyncJobTracker(): AsyncJobTracker {
17
+ const jobs = new Map<string, AsyncRunStatus>();
18
+
19
+ return {
20
+ track(runId, status) {
21
+ jobs.set(runId, status);
22
+ },
23
+ update(runId, patch) {
24
+ const current = jobs.get(runId);
25
+ if (!current) return;
26
+ jobs.set(runId, { ...current, ...patch, updatedAt: Date.now() });
27
+ },
28
+ get(runId) {
29
+ return jobs.get(runId);
30
+ },
31
+ list() {
32
+ return Array.from(jobs.values());
33
+ },
34
+ remove(runId) {
35
+ jobs.delete(runId);
36
+ },
37
+ clear() {
38
+ jobs.clear();
39
+ },
40
+ };
41
+ }
42
+
43
+ export interface SubagentEventBus {
44
+ emit(channel: string, payload: unknown): void;
45
+ on(channel: string, handler: (payload: unknown) => void): () => void;
46
+ }
47
+
48
+ export function emitAsyncStarted(
49
+ events: SubagentEventBus | undefined,
50
+ payload: {
51
+ id: string;
52
+ mode: AsyncRunStatus["mode"];
53
+ sessionId: string | null;
54
+ agents: string[];
55
+ },
56
+ ): void {
57
+ events?.emit(SUBAGENT_ASYNC_STARTED, payload);
58
+ }
59
+
60
+ export function emitAsyncComplete(
61
+ events: SubagentEventBus | undefined,
62
+ payload: {
63
+ id: string;
64
+ exitCode: number;
65
+ finalOutput: string;
66
+ },
67
+ ): void {
68
+ events?.emit(SUBAGENT_ASYNC_COMPLETE, payload);
69
+ }
70
+
71
+ export type AsyncExecuteInput = ExecuteSubagentInput;