@oh-my-pi/pi-coding-agent 15.5.15 → 15.7.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 (274) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/types/capability/rule-buckets.d.ts +30 -0
  3. package/dist/types/capability/rule.d.ts +7 -0
  4. package/dist/types/cli/classify-install-target.d.ts +0 -10
  5. package/dist/types/cli/completion-gen.d.ts +80 -0
  6. package/dist/types/cli/initial-message.d.ts +1 -1
  7. package/dist/types/cli/tiny-models-cli.d.ts +9 -0
  8. package/dist/types/commands/complete.d.ts +6 -0
  9. package/dist/types/commands/completions.d.ts +13 -0
  10. package/dist/types/commands/setup.d.ts +10 -1
  11. package/dist/types/commands/tiny-models.d.ts +22 -0
  12. package/dist/types/commit/analysis/conventional.d.ts +1 -1
  13. package/dist/types/commit/analysis/summary.d.ts +1 -1
  14. package/dist/types/commit/changelog/generate.d.ts +1 -1
  15. package/dist/types/commit/changelog/index.d.ts +2 -2
  16. package/dist/types/commit/map-reduce/map-phase.d.ts +1 -1
  17. package/dist/types/commit/map-reduce/reduce-phase.d.ts +1 -1
  18. package/dist/types/config/model-id-affixes.d.ts +10 -0
  19. package/dist/types/config/settings-schema.d.ts +402 -17
  20. package/dist/types/discovery/builtin-defaults.d.ts +1 -0
  21. package/dist/types/discovery/builtin-rules/index.d.ts +7 -0
  22. package/dist/types/discovery/helpers.d.ts +1 -1
  23. package/dist/types/discovery/index.d.ts +1 -0
  24. package/dist/types/discovery/substitute-plugin-root.d.ts +0 -4
  25. package/dist/types/edit/hashline/block-resolver.d.ts +9 -0
  26. package/dist/types/edit/hashline/index.d.ts +1 -0
  27. package/dist/types/eval/js/shared/rewrite-imports.d.ts +16 -1
  28. package/dist/types/eval/py/kernel.d.ts +3 -0
  29. package/dist/types/eval/py/runtime.d.ts +11 -1
  30. package/dist/types/export/html/template.generated.d.ts +1 -1
  31. package/dist/types/internal-urls/agent-protocol.d.ts +2 -1
  32. package/dist/types/internal-urls/artifact-protocol.d.ts +2 -1
  33. package/dist/types/internal-urls/local-protocol.d.ts +2 -1
  34. package/dist/types/internal-urls/memory-protocol.d.ts +2 -1
  35. package/dist/types/internal-urls/omp-protocol.d.ts +2 -1
  36. package/dist/types/internal-urls/router.d.ts +8 -1
  37. package/dist/types/internal-urls/rule-protocol.d.ts +2 -1
  38. package/dist/types/internal-urls/skill-protocol.d.ts +2 -1
  39. package/dist/types/internal-urls/types.d.ts +26 -0
  40. package/dist/types/main.d.ts +1 -0
  41. package/dist/types/memory-backend/index.d.ts +1 -0
  42. package/dist/types/memory-backend/resolve.d.ts +2 -1
  43. package/dist/types/memory-backend/types.d.ts +7 -1
  44. package/dist/types/mnemosyne/backend.d.ts +4 -0
  45. package/dist/types/mnemosyne/config.d.ts +29 -0
  46. package/dist/types/mnemosyne/index.d.ts +3 -0
  47. package/dist/types/mnemosyne/state.d.ts +72 -0
  48. package/dist/types/modes/components/custom-editor.d.ts +2 -3
  49. package/dist/types/modes/components/hook-selector.d.ts +27 -0
  50. package/dist/types/modes/components/index.d.ts +2 -0
  51. package/dist/types/modes/components/segment-track.d.ts +22 -0
  52. package/dist/types/modes/components/status-line/context-thresholds.d.ts +6 -0
  53. package/dist/types/modes/components/tiny-title-download-progress.d.ts +11 -0
  54. package/dist/types/modes/components/welcome.d.ts +22 -0
  55. package/dist/types/modes/controllers/extension-ui-controller.d.ts +4 -1
  56. package/dist/types/modes/gradient-highlight.d.ts +23 -0
  57. package/dist/types/modes/interactive-mode.d.ts +7 -4
  58. package/dist/types/modes/internal-url-autocomplete.d.ts +43 -0
  59. package/dist/types/modes/orchestrate.d.ts +10 -0
  60. package/dist/types/modes/setup-wizard/index.d.ts +16 -0
  61. package/dist/types/modes/setup-wizard/scenes/glyph.d.ts +2 -0
  62. package/dist/types/modes/setup-wizard/scenes/outro.d.ts +2 -0
  63. package/dist/types/modes/setup-wizard/scenes/providers.d.ts +2 -0
  64. package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +19 -0
  65. package/dist/types/modes/setup-wizard/scenes/splash.d.ts +11 -0
  66. package/dist/types/modes/setup-wizard/scenes/theme.d.ts +2 -0
  67. package/dist/types/modes/setup-wizard/scenes/types.d.ts +43 -0
  68. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +19 -0
  69. package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +14 -0
  70. package/dist/types/modes/theme/defaults/index.d.ts +8406 -8406
  71. package/dist/types/modes/theme/shimmer.d.ts +2 -0
  72. package/dist/types/modes/theme/theme.d.ts +11 -0
  73. package/dist/types/modes/types.d.ts +5 -1
  74. package/dist/types/modes/ultrathink.d.ts +3 -3
  75. package/dist/types/modes/utils/keybinding-matchers.d.ts +5 -0
  76. package/dist/types/sdk.d.ts +3 -0
  77. package/dist/types/session/agent-session.d.ts +33 -0
  78. package/dist/types/system-prompt.d.ts +2 -0
  79. package/dist/types/task/executor.d.ts +2 -0
  80. package/dist/types/task/render.d.ts +5 -1
  81. package/dist/types/tiny/device.d.ts +78 -0
  82. package/dist/types/tiny/dtype.d.ts +85 -0
  83. package/dist/types/tiny/models.d.ts +185 -0
  84. package/dist/types/tiny/text.d.ts +19 -0
  85. package/dist/types/tiny/title-client.d.ts +32 -0
  86. package/dist/types/tiny/title-protocol.d.ts +74 -0
  87. package/dist/types/tiny/worker.d.ts +2 -0
  88. package/dist/types/tools/bash.d.ts +3 -2
  89. package/dist/types/tools/eval.d.ts +1 -1
  90. package/dist/types/tools/index.d.ts +7 -4
  91. package/dist/types/tools/memory-edit.d.ts +40 -0
  92. package/dist/types/tools/{hindsight-recall.d.ts → memory-recall.d.ts} +6 -6
  93. package/dist/types/tools/{hindsight-reflect.d.ts → memory-reflect.d.ts} +6 -6
  94. package/dist/types/tools/memory-render.d.ts +60 -0
  95. package/dist/types/tools/{hindsight-retain.d.ts → memory-retain.d.ts} +6 -6
  96. package/dist/types/tools/todo-write.d.ts +8 -0
  97. package/dist/types/tools/tool-result.d.ts +2 -0
  98. package/dist/types/tui/code-cell.d.ts +2 -0
  99. package/dist/types/tui/output-block.d.ts +17 -0
  100. package/dist/types/utils/title-generator.d.ts +3 -0
  101. package/package.json +18 -14
  102. package/scripts/build-binary.ts +1 -0
  103. package/src/capability/rule-buckets.ts +64 -0
  104. package/src/capability/rule.ts +8 -0
  105. package/src/cli/completion-gen.ts +550 -0
  106. package/src/cli/setup-cli.ts +5 -3
  107. package/src/cli/tiny-models-cli.ts +127 -0
  108. package/src/cli-commands.ts +3 -0
  109. package/src/cli.ts +9 -15
  110. package/src/commands/complete.ts +66 -0
  111. package/src/commands/completions.ts +60 -0
  112. package/src/commands/setup.ts +29 -4
  113. package/src/commands/tiny-models.ts +36 -0
  114. package/src/config/model-equivalence.ts +43 -2
  115. package/src/config/model-id-affixes.ts +64 -0
  116. package/src/config/model-registry.ts +84 -10
  117. package/src/config/settings-schema.ts +275 -15
  118. package/src/discovery/builtin-defaults.ts +39 -0
  119. package/src/discovery/builtin-rules/index.ts +48 -0
  120. package/src/discovery/builtin-rules/rs-box-leak.md +48 -0
  121. package/src/discovery/builtin-rules/rs-future-prelude.md +23 -0
  122. package/src/discovery/builtin-rules/rs-lazylock.md +51 -0
  123. package/src/discovery/builtin-rules/rs-match-ergonomics.md +67 -0
  124. package/src/discovery/builtin-rules/rs-parking-lot.md +44 -0
  125. package/src/discovery/builtin-rules/rs-result-type.md +19 -0
  126. package/src/discovery/builtin-rules/ts-bare-catch.md +38 -0
  127. package/src/discovery/builtin-rules/ts-import-type.md +42 -0
  128. package/src/discovery/builtin-rules/ts-no-any.md +56 -0
  129. package/src/discovery/builtin-rules/ts-no-dynamic-import.md +39 -0
  130. package/src/discovery/builtin-rules/ts-no-return-type.md +45 -0
  131. package/src/discovery/builtin-rules/ts-no-tiny-functions.md +50 -0
  132. package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +65 -0
  133. package/src/discovery/builtin-rules/ts-set-map.md +28 -0
  134. package/src/discovery/index.ts +1 -0
  135. package/src/edit/hashline/block-resolver.ts +14 -0
  136. package/src/edit/hashline/diff.ts +9 -8
  137. package/src/edit/hashline/execute.ts +2 -1
  138. package/src/edit/hashline/index.ts +1 -0
  139. package/src/eval/__tests__/shared-executors.test.ts +36 -0
  140. package/src/eval/js/shared/local-module-loader.ts +13 -1
  141. package/src/eval/js/shared/rewrite-imports.ts +31 -26
  142. package/src/eval/py/kernel.ts +37 -15
  143. package/src/eval/py/runtime.ts +57 -28
  144. package/src/export/html/template.generated.ts +1 -1
  145. package/src/export/html/template.js +0 -12
  146. package/src/export/ttsr.ts +2 -0
  147. package/src/internal-urls/agent-protocol.ts +18 -1
  148. package/src/internal-urls/artifact-protocol.ts +19 -1
  149. package/src/internal-urls/docs-index.generated.ts +8 -7
  150. package/src/internal-urls/local-protocol.ts +14 -1
  151. package/src/internal-urls/memory-protocol.ts +6 -1
  152. package/src/internal-urls/omp-protocol.ts +5 -1
  153. package/src/internal-urls/router.ts +20 -1
  154. package/src/internal-urls/rule-protocol.ts +8 -1
  155. package/src/internal-urls/skill-protocol.ts +8 -1
  156. package/src/internal-urls/types.ts +27 -0
  157. package/src/lsp/render.ts +1 -1
  158. package/src/main.ts +18 -1
  159. package/src/mcp/oauth-flow.ts +2 -2
  160. package/src/memory-backend/index.ts +1 -0
  161. package/src/memory-backend/resolve.ts +4 -1
  162. package/src/memory-backend/types.ts +8 -1
  163. package/src/mnemosyne/backend.ts +374 -0
  164. package/src/mnemosyne/config.ts +160 -0
  165. package/src/mnemosyne/index.ts +3 -0
  166. package/src/mnemosyne/state.ts +548 -0
  167. package/src/modes/acp/acp-agent.ts +11 -6
  168. package/src/modes/components/agent-dashboard.ts +4 -4
  169. package/src/modes/components/custom-editor.ts +3 -2
  170. package/src/modes/components/diff.ts +2 -2
  171. package/src/modes/components/extensions/extension-list.ts +3 -2
  172. package/src/modes/components/footer.ts +5 -6
  173. package/src/modes/components/history-search.ts +3 -3
  174. package/src/modes/components/hook-selector.ts +92 -8
  175. package/src/modes/components/index.ts +2 -0
  176. package/src/modes/components/mcp-add-wizard.ts +3 -3
  177. package/src/modes/components/model-selector.ts +5 -4
  178. package/src/modes/components/oauth-selector.ts +3 -3
  179. package/src/modes/components/segment-track.ts +52 -0
  180. package/src/modes/components/session-observer-overlay.ts +19 -13
  181. package/src/modes/components/session-selector.ts +3 -3
  182. package/src/modes/components/settings-defs.ts +7 -0
  183. package/src/modes/components/status-line/context-thresholds.ts +11 -0
  184. package/src/modes/components/status-line/segments.ts +2 -2
  185. package/src/modes/components/tiny-title-download-progress.ts +90 -0
  186. package/src/modes/components/tips.txt +13 -0
  187. package/src/modes/components/tool-execution.ts +72 -4
  188. package/src/modes/components/tree-selector.ts +3 -3
  189. package/src/modes/components/user-message-selector.ts +3 -3
  190. package/src/modes/components/welcome.ts +102 -43
  191. package/src/modes/controllers/command-controller.ts +16 -1
  192. package/src/modes/controllers/extension-ui-controller.ts +3 -1
  193. package/src/modes/controllers/input-controller.ts +69 -21
  194. package/src/modes/gradient-highlight.ts +70 -0
  195. package/src/modes/interactive-mode.ts +75 -114
  196. package/src/modes/internal-url-autocomplete.ts +143 -0
  197. package/src/modes/orchestrate.ts +36 -0
  198. package/src/modes/prompt-action-autocomplete.ts +12 -0
  199. package/src/modes/setup-wizard/index.ts +88 -0
  200. package/src/modes/setup-wizard/scenes/glyph.ts +96 -0
  201. package/src/modes/setup-wizard/scenes/outro.ts +35 -0
  202. package/src/modes/setup-wizard/scenes/providers.ts +69 -0
  203. package/src/modes/setup-wizard/scenes/sign-in.ts +193 -0
  204. package/src/modes/setup-wizard/scenes/splash.ts +201 -0
  205. package/src/modes/setup-wizard/scenes/theme.ts +299 -0
  206. package/src/modes/setup-wizard/scenes/types.ts +48 -0
  207. package/src/modes/setup-wizard/scenes/web-search.ts +128 -0
  208. package/src/modes/setup-wizard/wizard-overlay.ts +275 -0
  209. package/src/modes/theme/shimmer.ts +5 -0
  210. package/src/modes/theme/theme.ts +44 -20
  211. package/src/modes/types.ts +6 -1
  212. package/src/modes/ultrathink.ts +9 -53
  213. package/src/modes/utils/keybinding-matchers.ts +11 -0
  214. package/src/prompts/system/memory-consolidation-system.md +8 -0
  215. package/src/prompts/system/memory-extraction-system.md +26 -0
  216. package/src/prompts/{commands/orchestrate.md → system/orchestrate-notice.md} +6 -17
  217. package/src/prompts/system/system-prompt.md +2 -0
  218. package/src/prompts/system/tiny-title-system.md +8 -0
  219. package/src/prompts/tools/memory-edit.md +8 -0
  220. package/src/prompts/tools/read.md +4 -0
  221. package/src/prompts/tools/task.md +4 -7
  222. package/src/sdk.ts +13 -21
  223. package/src/session/agent-session.ts +128 -44
  224. package/src/slash-commands/builtin-registry.ts +18 -1
  225. package/src/system-prompt.ts +4 -0
  226. package/src/task/commands.ts +1 -5
  227. package/src/task/executor.ts +8 -0
  228. package/src/task/index.ts +2 -0
  229. package/src/task/render.ts +69 -26
  230. package/src/tiny/device.ts +117 -0
  231. package/src/tiny/dtype.ts +101 -0
  232. package/src/tiny/models.ts +218 -0
  233. package/src/tiny/text.ts +54 -0
  234. package/src/tiny/title-client.ts +395 -0
  235. package/src/tiny/title-protocol.ts +51 -0
  236. package/src/tiny/worker.ts +587 -0
  237. package/src/tools/bash.ts +74 -29
  238. package/src/tools/browser/tab-worker.ts +1 -1
  239. package/src/tools/eval.ts +9 -4
  240. package/src/tools/index.ts +17 -22
  241. package/src/tools/memory-edit.ts +59 -0
  242. package/src/tools/memory-recall.ts +100 -0
  243. package/src/tools/memory-reflect.ts +88 -0
  244. package/src/tools/memory-render.ts +185 -0
  245. package/src/tools/memory-retain.ts +91 -0
  246. package/src/tools/read.ts +1 -0
  247. package/src/tools/renderers.ts +4 -2
  248. package/src/tools/todo-write.ts +128 -29
  249. package/src/tools/tool-result.ts +8 -0
  250. package/src/tui/code-cell.ts +6 -1
  251. package/src/tui/output-block.ts +199 -38
  252. package/src/utils/title-generator.ts +115 -13
  253. package/dist/types/tools/recipe/index.d.ts +0 -46
  254. package/dist/types/tools/recipe/render.d.ts +0 -36
  255. package/dist/types/tools/recipe/runner.d.ts +0 -60
  256. package/dist/types/tools/recipe/runners/cargo.d.ts +0 -16
  257. package/dist/types/tools/recipe/runners/index.d.ts +0 -2
  258. package/dist/types/tools/recipe/runners/just.d.ts +0 -2
  259. package/dist/types/tools/recipe/runners/make.d.ts +0 -2
  260. package/dist/types/tools/recipe/runners/pkg.d.ts +0 -2
  261. package/dist/types/tools/recipe/runners/task.d.ts +0 -2
  262. package/src/prompts/tools/recipe.md +0 -16
  263. package/src/tools/hindsight-recall.ts +0 -69
  264. package/src/tools/hindsight-reflect.ts +0 -58
  265. package/src/tools/hindsight-retain.ts +0 -57
  266. package/src/tools/recipe/index.ts +0 -81
  267. package/src/tools/recipe/render.ts +0 -19
  268. package/src/tools/recipe/runner.ts +0 -219
  269. package/src/tools/recipe/runners/cargo.ts +0 -131
  270. package/src/tools/recipe/runners/index.ts +0 -8
  271. package/src/tools/recipe/runners/just.ts +0 -73
  272. package/src/tools/recipe/runners/make.ts +0 -101
  273. package/src/tools/recipe/runners/pkg.ts +0 -167
  274. package/src/tools/recipe/runners/task.ts +0 -72
@@ -1,73 +0,0 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
- import { $which, isEnoent, logger } from "@oh-my-pi/pi-utils";
4
- import type { DetectedRunner, RunnerTask, TaskRunner } from "../runner";
5
-
6
- interface JustDumpRecipeRaw {
7
- name?: string;
8
- doc?: string | null;
9
- private?: boolean;
10
- parameters?: Array<{ name?: string }>;
11
- }
12
-
13
- interface JustDump {
14
- recipes?: Record<string, JustDumpRecipeRaw>;
15
- }
16
-
17
- const JUSTFILE_NAMES = ["justfile", "Justfile", ".justfile"] as const;
18
-
19
- async function hasJustfile(cwd: string): Promise<boolean> {
20
- for (const name of JUSTFILE_NAMES) {
21
- try {
22
- const stat = await fs.stat(path.join(cwd, name));
23
- if (stat.isFile()) return true;
24
- } catch (err) {
25
- if (!isEnoent(err)) throw err;
26
- }
27
- }
28
- return false;
29
- }
30
-
31
- async function dumpJustTasks(cwd: string): Promise<RunnerTask[] | null> {
32
- try {
33
- const proc = Bun.spawn(["just", "--dump", "--dump-format=json"], {
34
- cwd,
35
- stdin: "ignore",
36
- stdout: "pipe",
37
- stderr: "pipe",
38
- });
39
- const [stdout, exit] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
40
- if (exit !== 0) return null;
41
- const dump = JSON.parse(stdout) as JustDump;
42
- const tasks: RunnerTask[] = [];
43
- for (const recipe of Object.values(dump.recipes ?? {})) {
44
- if (!recipe.name || recipe.private) continue;
45
- const parameters = (recipe.parameters ?? [])
46
- .map(parameter => parameter.name)
47
- .filter((name): name is string => typeof name === "string" && name.length > 0);
48
- const doc = typeof recipe.doc === "string" && recipe.doc.length > 0 ? recipe.doc : undefined;
49
- tasks.push({ name: recipe.name, doc, parameters });
50
- }
51
- return tasks;
52
- } catch (err) {
53
- logger.debug("just task detection failed", { error: err instanceof Error ? err.message : String(err) });
54
- return null;
55
- }
56
- }
57
-
58
- export const justRunner: TaskRunner = {
59
- id: "just",
60
- label: "Just",
61
- async detect(cwd: string): Promise<DetectedRunner | null> {
62
- try {
63
- if (!$which("just")) return null;
64
- if (!(await hasJustfile(cwd))) return null;
65
- const tasks = await dumpJustTasks(cwd);
66
- if (!tasks || tasks.length === 0) return null;
67
- return { id: "just", label: "Just", commandPrefix: "just", tasks };
68
- } catch (err) {
69
- logger.debug("just runner probe failed", { error: err instanceof Error ? err.message : String(err) });
70
- return null;
71
- }
72
- },
73
- };
@@ -1,101 +0,0 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
- import { $which, isEnoent, logger } from "@oh-my-pi/pi-utils";
4
- import type { DetectedRunner, RunnerTask, TaskRunner } from "../runner";
5
-
6
- const MAKEFILE_NAMES = ["Makefile", "makefile", "GNUmakefile"] as const;
7
- const TARGET_PATTERN = /^(?<name>[A-Za-z_][A-Za-z0-9_-]*)\s*:(?!=).*?(?:##\s*(?<doc>.+))?$/u;
8
- const PHONY_PATTERN = /^\.PHONY\s*:\s*(?<targets>.*)$/u;
9
-
10
- interface MakeTargetInfo {
11
- name: string;
12
- doc?: string;
13
- order: number;
14
- phony: boolean;
15
- }
16
-
17
- async function findMakefile(cwd: string): Promise<string | null> {
18
- for (const name of MAKEFILE_NAMES) {
19
- const candidate = path.join(cwd, name);
20
- try {
21
- const stat = await fs.stat(candidate);
22
- if (stat.isFile()) return candidate;
23
- } catch (err) {
24
- if (!isEnoent(err)) throw err;
25
- }
26
- }
27
- return null;
28
- }
29
-
30
- function isVariableAssignment(line: string, name: string): boolean {
31
- return new RegExp(`^\\s*${name}\\s*[:?+]?=`, "u").test(line);
32
- }
33
-
34
- function parsePhonyTargets(line: string): string[] {
35
- const match = PHONY_PATTERN.exec(line);
36
- if (!match?.groups?.targets) return [];
37
- return match.groups.targets
38
- .split(/\s+/u)
39
- .map(target => target.trim())
40
- .filter(target => /^[A-Za-z_][A-Za-z0-9_-]*$/u.test(target));
41
- }
42
-
43
- function parseMakeTargets(text: string): RunnerTask[] {
44
- const targets = new Map<string, MakeTargetInfo>();
45
- const phonyTargets: string[] = [];
46
- let order = 0;
47
-
48
- for (const line of text.split("\n")) {
49
- for (const target of parsePhonyTargets(line)) {
50
- if (!phonyTargets.includes(target)) phonyTargets.push(target);
51
- }
52
-
53
- const match = TARGET_PATTERN.exec(line);
54
- const name = match?.groups?.name;
55
- if (!name || name === ".PHONY" || isVariableAssignment(line, name)) continue;
56
- if (targets.has(name)) continue;
57
- const rawDoc = match?.groups?.doc?.trim();
58
- const doc = rawDoc && rawDoc.length > 0 ? rawDoc : undefined;
59
- targets.set(name, { name, doc, order, phony: false });
60
- order += 1;
61
- }
62
-
63
- for (const phony of phonyTargets) {
64
- const existing = targets.get(phony);
65
- if (existing) {
66
- existing.phony = true;
67
- continue;
68
- }
69
- targets.set(phony, { name: phony, order, phony: true });
70
- order += 1;
71
- }
72
-
73
- const hasPhonyTargets = phonyTargets.length > 0;
74
- return [...targets.values()]
75
- .sort((left, right) => left.order - right.order)
76
- .flatMap(target => {
77
- if (!hasPhonyTargets || target.phony) {
78
- return [{ name: target.name, doc: target.doc, parameters: [] }];
79
- }
80
- if (!target.doc) return [];
81
- return [{ name: target.name, doc: `${target.doc} (file target)`, parameters: [] }];
82
- });
83
- }
84
-
85
- export const makeRunner: TaskRunner = {
86
- id: "make",
87
- label: "Make",
88
- async detect(cwd: string): Promise<DetectedRunner | null> {
89
- try {
90
- if (!$which("make")) return null;
91
- const makefile = await findMakefile(cwd);
92
- if (!makefile) return null;
93
- const tasks = parseMakeTargets(await Bun.file(makefile).text());
94
- if (tasks.length === 0) return null;
95
- return { id: "make", label: "Make", commandPrefix: "make", tasks };
96
- } catch (err) {
97
- logger.debug("make runner probe failed", { error: err instanceof Error ? err.message : String(err) });
98
- return null;
99
- }
100
- },
101
- };
@@ -1,167 +0,0 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
- import { $which, isEnoent, logger } from "@oh-my-pi/pi-utils";
4
- import type { DetectedRunner, RunnerTask, TaskRunner } from "../runner";
5
-
6
- interface PackageJsonInfo {
7
- name?: string;
8
- scripts: string[];
9
- workspaces: string[];
10
- }
11
-
12
- async function resolvePackageRunner(cwd: string): Promise<string> {
13
- const [bunLock, bunLockb, pnpmLock, yarnLock, npmLock, npmShrink] = await Promise.all([
14
- isFile(path.join(cwd, "bun.lock")),
15
- isFile(path.join(cwd, "bun.lockb")),
16
- isFile(path.join(cwd, "pnpm-lock.yaml")),
17
- isFile(path.join(cwd, "yarn.lock")),
18
- isFile(path.join(cwd, "package-lock.json")),
19
- isFile(path.join(cwd, "npm-shrinkwrap.json")),
20
- ]);
21
- if (bunLock || bunLockb) return "bun run";
22
- if (pnpmLock) return "pnpm run";
23
- if (yarnLock) return "yarn";
24
- if (npmLock || npmShrink) return "npm run";
25
- if ($which("bun")) return "bun run";
26
- return "npm run";
27
- }
28
-
29
- function isRecord(value: unknown): value is Record<string, unknown> {
30
- return typeof value === "object" && value !== null && !Array.isArray(value);
31
- }
32
-
33
- function shellQuote(value: string): string {
34
- return `'${value.replaceAll("'", `'\\''`)}'`;
35
- }
36
-
37
- async function isFile(filePath: string): Promise<boolean> {
38
- try {
39
- const stat = await fs.stat(filePath);
40
- return stat.isFile();
41
- } catch (err) {
42
- if (isEnoent(err)) return false;
43
- throw err;
44
- }
45
- }
46
-
47
- function parseWorkspacePatterns(pkg: Record<string, unknown>): string[] {
48
- const { workspaces } = pkg;
49
- if (Array.isArray(workspaces)) return workspaces.filter((entry): entry is string => typeof entry === "string");
50
- if (isRecord(workspaces) && Array.isArray(workspaces.packages)) {
51
- return workspaces.packages.filter((entry): entry is string => typeof entry === "string");
52
- }
53
- return [];
54
- }
55
-
56
- function normalizeWorkspacePattern(pattern: string): string {
57
- const negated = pattern.startsWith("!");
58
- const body = negated ? pattern.slice(1) : pattern;
59
- const normalizedBody = body.endsWith("package.json") ? body : `${body.replace(/\/+$/u, "")}/package.json`;
60
- return negated ? `!${normalizedBody}` : normalizedBody;
61
- }
62
-
63
- async function readPackageJson(filePath: string): Promise<PackageJsonInfo | null> {
64
- try {
65
- const pkg = (await Bun.file(filePath).json()) as unknown;
66
- if (!isRecord(pkg)) return null;
67
- const scripts = isRecord(pkg.scripts)
68
- ? Object.entries(pkg.scripts)
69
- .filter((entry): entry is [string, string] => typeof entry[1] === "string" && entry[0].length > 0)
70
- .map(([name]) => name)
71
- : [];
72
- const name = typeof pkg.name === "string" && pkg.name.length > 0 ? pkg.name : undefined;
73
- return { name, scripts, workspaces: parseWorkspacePatterns(pkg) };
74
- } catch (err) {
75
- if (!isEnoent(err)) {
76
- logger.debug("package.json script detection failed", {
77
- error: err instanceof Error ? err.message : String(err),
78
- });
79
- }
80
- return null;
81
- }
82
- }
83
-
84
- async function findWorkspacePackageJsons(cwd: string, patterns: string[]): Promise<string[]> {
85
- const includePatterns = patterns.filter(pattern => !pattern.startsWith("!")).map(normalizeWorkspacePattern);
86
- const excludePatterns = patterns.filter(pattern => pattern.startsWith("!")).map(normalizeWorkspacePattern);
87
-
88
- const collect = async (pattern: string): Promise<string[]> => {
89
- const out: string[] = [];
90
- for await (const entry of new Bun.Glob(pattern).scan({ cwd, onlyFiles: true })) {
91
- out.push(path.normalize(String(entry)));
92
- }
93
- return out;
94
- };
95
-
96
- const [excludedLists, includedLists] = await Promise.all([
97
- Promise.all(excludePatterns.map(pattern => collect(pattern.slice(1)))),
98
- Promise.all(includePatterns.map(pattern => collect(pattern))),
99
- ]);
100
- const excluded = new Set<string>(excludedLists.flat());
101
- const files = new Set<string>();
102
- for (const entry of includedLists.flat()) {
103
- if (entry !== "package.json" && !excluded.has(entry)) files.add(entry);
104
- }
105
- return [...files].sort((left, right) => left.localeCompare(right));
106
- }
107
-
108
- function packageTaskName(packageName: string | undefined, packageDir: string, scriptName: string): string {
109
- return `${packageName ?? packageDir}/${scriptName}`;
110
- }
111
-
112
- function tasksForPackage(options: { pkg: PackageJsonInfo; packageDir: string; namespaced: boolean }): RunnerTask[] {
113
- return options.pkg.scripts.map(scriptName => ({
114
- name: options.namespaced ? packageTaskName(options.pkg.name, options.packageDir, scriptName) : scriptName,
115
- doc: options.namespaced ? options.packageDir : undefined,
116
- parameters: [],
117
- cwd: options.namespaced ? options.packageDir : undefined,
118
- commandName: shellQuote(scriptName),
119
- }));
120
- }
121
-
122
- async function readPackageTasks(cwd: string): Promise<RunnerTask[] | null> {
123
- const rootPkg = await readPackageJson(path.join(cwd, "package.json"));
124
- if (!rootPkg) return null;
125
- const workspacePackageJsons = await findWorkspacePackageJsons(cwd, rootPkg.workspaces);
126
- const tasks: RunnerTask[] = [];
127
-
128
- if (rootPkg.scripts.length > 0) {
129
- tasks.push(
130
- ...tasksForPackage({
131
- pkg: rootPkg,
132
- packageDir: ".",
133
- namespaced: false,
134
- }),
135
- );
136
- }
137
-
138
- const pkgs = await Promise.all(workspacePackageJsons.map(p => readPackageJson(path.join(cwd, p))));
139
- pkgs.forEach((pkg, index) => {
140
- if (!pkg || pkg.scripts.length === 0) return;
141
- const packageDir = path.dirname(workspacePackageJsons[index]);
142
- tasks.push(
143
- ...tasksForPackage({
144
- pkg,
145
- packageDir,
146
- namespaced: true,
147
- }),
148
- );
149
- });
150
-
151
- return tasks.length > 0 ? tasks : null;
152
- }
153
-
154
- export const pkgRunner: TaskRunner = {
155
- id: "pkg",
156
- label: "Pkg",
157
- async detect(cwd: string): Promise<DetectedRunner | null> {
158
- try {
159
- const [commandPrefix, tasks] = await Promise.all([resolvePackageRunner(cwd), readPackageTasks(cwd)]);
160
- if (!tasks || tasks.length === 0) return null;
161
- return { id: "pkg", label: "Pkg", commandPrefix, tasks };
162
- } catch (err) {
163
- logger.debug("package runner probe failed", { error: err instanceof Error ? err.message : String(err) });
164
- return null;
165
- }
166
- },
167
- };
@@ -1,72 +0,0 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
- import { $which, isEnoent, logger } from "@oh-my-pi/pi-utils";
4
- import type { DetectedRunner, RunnerTask, TaskRunner } from "../runner";
5
-
6
- interface TaskListEntry {
7
- name?: string;
8
- desc?: string;
9
- summary?: string;
10
- }
11
-
12
- interface TaskListJson {
13
- tasks?: TaskListEntry[];
14
- }
15
-
16
- const TASKFILE_NAMES = ["Taskfile.yml", "Taskfile.yaml"] as const;
17
-
18
- async function hasTaskfile(cwd: string): Promise<boolean> {
19
- for (const name of TASKFILE_NAMES) {
20
- try {
21
- const stat = await fs.stat(path.join(cwd, name));
22
- if (stat.isFile()) return true;
23
- } catch (err) {
24
- if (!isEnoent(err)) throw err;
25
- }
26
- }
27
- return false;
28
- }
29
-
30
- async function listTaskfileTasks(cwd: string): Promise<RunnerTask[] | null> {
31
- try {
32
- const proc = Bun.spawn(["task", "--list-all", "--json"], {
33
- cwd,
34
- stdin: "ignore",
35
- stdout: "pipe",
36
- stderr: "pipe",
37
- });
38
- const [stdout, exit] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
39
- if (exit !== 0) return null;
40
- const list = JSON.parse(stdout) as TaskListJson;
41
- const tasks = (list.tasks ?? [])
42
- .filter(
43
- (task): task is TaskListEntry & { name: string } => typeof task.name === "string" && task.name.length > 0,
44
- )
45
- .map(task => {
46
- const desc = typeof task.desc === "string" && task.desc.length > 0 ? task.desc : undefined;
47
- const summary = typeof task.summary === "string" && task.summary.length > 0 ? task.summary : undefined;
48
- return { name: task.name, doc: desc ?? summary, parameters: [] };
49
- });
50
- return tasks.length > 0 ? tasks : null;
51
- } catch (err) {
52
- logger.debug("task runner list failed", { error: err instanceof Error ? err.message : String(err) });
53
- return null;
54
- }
55
- }
56
-
57
- export const taskRunner: TaskRunner = {
58
- id: "task",
59
- label: "Task",
60
- async detect(cwd: string): Promise<DetectedRunner | null> {
61
- try {
62
- if (!$which("task")) return null;
63
- if (!(await hasTaskfile(cwd))) return null;
64
- const tasks = await listTaskfileTasks(cwd);
65
- if (!tasks || tasks.length === 0) return null;
66
- return { id: "task", label: "Task", commandPrefix: "task", tasks };
67
- } catch (err) {
68
- logger.debug("task runner probe failed", { error: err instanceof Error ? err.message : String(err) });
69
- return null;
70
- }
71
- },
72
- };