@oh-my-pi/pi-coding-agent 3.25.0 → 3.31.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 (157) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/package.json +5 -5
  3. package/src/cli/args.ts +4 -0
  4. package/src/core/agent-session.ts +29 -2
  5. package/src/core/bash-executor.ts +2 -1
  6. package/src/core/custom-commands/bundled/review/index.ts +369 -14
  7. package/src/core/custom-commands/bundled/wt/index.ts +1 -1
  8. package/src/core/session-manager.ts +158 -246
  9. package/src/core/session-storage.ts +379 -0
  10. package/src/core/settings-manager.ts +155 -4
  11. package/src/core/system-prompt.ts +62 -64
  12. package/src/core/tools/ask.ts +5 -4
  13. package/src/core/tools/bash-interceptor.ts +26 -61
  14. package/src/core/tools/bash.ts +13 -8
  15. package/src/core/tools/complete.ts +2 -4
  16. package/src/core/tools/edit-diff.ts +11 -4
  17. package/src/core/tools/edit.ts +7 -13
  18. package/src/core/tools/find.ts +111 -50
  19. package/src/core/tools/gemini-image.ts +128 -147
  20. package/src/core/tools/grep.ts +397 -415
  21. package/src/core/tools/index.test.ts +5 -1
  22. package/src/core/tools/index.ts +6 -8
  23. package/src/core/tools/jtd-to-json-schema.ts +174 -196
  24. package/src/core/tools/ls.ts +12 -10
  25. package/src/core/tools/lsp/client.ts +58 -9
  26. package/src/core/tools/lsp/config.ts +205 -656
  27. package/src/core/tools/lsp/defaults.json +465 -0
  28. package/src/core/tools/lsp/index.ts +55 -32
  29. package/src/core/tools/lsp/rust-analyzer.ts +49 -10
  30. package/src/core/tools/lsp/types.ts +1 -0
  31. package/src/core/tools/lsp/utils.ts +1 -1
  32. package/src/core/tools/read.ts +152 -76
  33. package/src/core/tools/render-utils.ts +70 -10
  34. package/src/core/tools/review.ts +38 -126
  35. package/src/core/tools/task/artifacts.ts +5 -4
  36. package/src/core/tools/task/executor.ts +204 -67
  37. package/src/core/tools/task/index.ts +129 -92
  38. package/src/core/tools/task/name-generator.ts +1544 -214
  39. package/src/core/tools/task/parallel.ts +30 -3
  40. package/src/core/tools/task/render.ts +85 -39
  41. package/src/core/tools/task/types.ts +34 -11
  42. package/src/core/tools/task/worker.ts +152 -27
  43. package/src/core/tools/web-fetch.ts +220 -1657
  44. package/src/core/tools/web-scrapers/academic.test.ts +239 -0
  45. package/src/core/tools/web-scrapers/artifacthub.ts +215 -0
  46. package/src/core/tools/web-scrapers/arxiv.ts +88 -0
  47. package/src/core/tools/web-scrapers/aur.ts +175 -0
  48. package/src/core/tools/web-scrapers/biorxiv.ts +141 -0
  49. package/src/core/tools/web-scrapers/bluesky.ts +284 -0
  50. package/src/core/tools/web-scrapers/brew.ts +177 -0
  51. package/src/core/tools/web-scrapers/business.test.ts +82 -0
  52. package/src/core/tools/web-scrapers/cheatsh.ts +78 -0
  53. package/src/core/tools/web-scrapers/chocolatey.ts +158 -0
  54. package/src/core/tools/web-scrapers/choosealicense.ts +110 -0
  55. package/src/core/tools/web-scrapers/cisa-kev.ts +100 -0
  56. package/src/core/tools/web-scrapers/clojars.ts +180 -0
  57. package/src/core/tools/web-scrapers/coingecko.ts +184 -0
  58. package/src/core/tools/web-scrapers/crates-io.ts +128 -0
  59. package/src/core/tools/web-scrapers/crossref.ts +149 -0
  60. package/src/core/tools/web-scrapers/dev-platforms.test.ts +254 -0
  61. package/src/core/tools/web-scrapers/devto.ts +177 -0
  62. package/src/core/tools/web-scrapers/discogs.ts +308 -0
  63. package/src/core/tools/web-scrapers/discourse.ts +221 -0
  64. package/src/core/tools/web-scrapers/dockerhub.ts +160 -0
  65. package/src/core/tools/web-scrapers/documentation.test.ts +85 -0
  66. package/src/core/tools/web-scrapers/fdroid.ts +158 -0
  67. package/src/core/tools/web-scrapers/finance-media.test.ts +144 -0
  68. package/src/core/tools/web-scrapers/firefox-addons.ts +214 -0
  69. package/src/core/tools/web-scrapers/flathub.ts +239 -0
  70. package/src/core/tools/web-scrapers/git-hosting.test.ts +272 -0
  71. package/src/core/tools/web-scrapers/github-gist.ts +68 -0
  72. package/src/core/tools/web-scrapers/github.ts +455 -0
  73. package/src/core/tools/web-scrapers/gitlab.ts +456 -0
  74. package/src/core/tools/web-scrapers/go-pkg.ts +275 -0
  75. package/src/core/tools/web-scrapers/hackage.ts +94 -0
  76. package/src/core/tools/web-scrapers/hackernews.ts +208 -0
  77. package/src/core/tools/web-scrapers/hex.ts +121 -0
  78. package/src/core/tools/web-scrapers/huggingface.ts +385 -0
  79. package/src/core/tools/web-scrapers/iacr.ts +86 -0
  80. package/src/core/tools/web-scrapers/index.ts +250 -0
  81. package/src/core/tools/web-scrapers/jetbrains-marketplace.ts +169 -0
  82. package/src/core/tools/web-scrapers/lemmy.ts +220 -0
  83. package/src/core/tools/web-scrapers/lobsters.ts +186 -0
  84. package/src/core/tools/web-scrapers/mastodon.ts +310 -0
  85. package/src/core/tools/web-scrapers/maven.ts +152 -0
  86. package/src/core/tools/web-scrapers/mdn.ts +174 -0
  87. package/src/core/tools/web-scrapers/media.test.ts +138 -0
  88. package/src/core/tools/web-scrapers/metacpan.ts +253 -0
  89. package/src/core/tools/web-scrapers/musicbrainz.ts +273 -0
  90. package/src/core/tools/web-scrapers/npm.ts +114 -0
  91. package/src/core/tools/web-scrapers/nuget.ts +205 -0
  92. package/src/core/tools/web-scrapers/nvd.ts +243 -0
  93. package/src/core/tools/web-scrapers/ollama.ts +267 -0
  94. package/src/core/tools/web-scrapers/open-vsx.ts +119 -0
  95. package/src/core/tools/web-scrapers/opencorporates.ts +275 -0
  96. package/src/core/tools/web-scrapers/openlibrary.ts +319 -0
  97. package/src/core/tools/web-scrapers/orcid.ts +299 -0
  98. package/src/core/tools/web-scrapers/osv.ts +189 -0
  99. package/src/core/tools/web-scrapers/package-managers-2.test.ts +199 -0
  100. package/src/core/tools/web-scrapers/package-managers.test.ts +171 -0
  101. package/src/core/tools/web-scrapers/package-registries.test.ts +259 -0
  102. package/src/core/tools/web-scrapers/packagist.ts +174 -0
  103. package/src/core/tools/web-scrapers/pub-dev.ts +185 -0
  104. package/src/core/tools/web-scrapers/pubmed.ts +178 -0
  105. package/src/core/tools/web-scrapers/pypi.ts +129 -0
  106. package/src/core/tools/web-scrapers/rawg.ts +124 -0
  107. package/src/core/tools/web-scrapers/readthedocs.ts +126 -0
  108. package/src/core/tools/web-scrapers/reddit.ts +104 -0
  109. package/src/core/tools/web-scrapers/repology.ts +262 -0
  110. package/src/core/tools/web-scrapers/research.test.ts +107 -0
  111. package/src/core/tools/web-scrapers/rfc.ts +209 -0
  112. package/src/core/tools/web-scrapers/rubygems.ts +117 -0
  113. package/src/core/tools/web-scrapers/searchcode.ts +217 -0
  114. package/src/core/tools/web-scrapers/sec-edgar.ts +274 -0
  115. package/src/core/tools/web-scrapers/security.test.ts +103 -0
  116. package/src/core/tools/web-scrapers/semantic-scholar.ts +190 -0
  117. package/src/core/tools/web-scrapers/snapcraft.ts +200 -0
  118. package/src/core/tools/web-scrapers/social-extended.test.ts +192 -0
  119. package/src/core/tools/web-scrapers/social.test.ts +259 -0
  120. package/src/core/tools/web-scrapers/sourcegraph.ts +373 -0
  121. package/src/core/tools/web-scrapers/spdx.ts +121 -0
  122. package/src/core/tools/web-scrapers/spotify.ts +218 -0
  123. package/src/core/tools/web-scrapers/stackexchange.test.ts +120 -0
  124. package/src/core/tools/web-scrapers/stackoverflow.ts +124 -0
  125. package/src/core/tools/web-scrapers/standards.test.ts +122 -0
  126. package/src/core/tools/web-scrapers/terraform.ts +304 -0
  127. package/src/core/tools/web-scrapers/tldr.ts +51 -0
  128. package/src/core/tools/web-scrapers/twitter.ts +96 -0
  129. package/src/core/tools/web-scrapers/types.ts +234 -0
  130. package/src/core/tools/web-scrapers/utils.ts +162 -0
  131. package/src/core/tools/web-scrapers/vimeo.ts +152 -0
  132. package/src/core/tools/web-scrapers/vscode-marketplace.ts +195 -0
  133. package/src/core/tools/web-scrapers/w3c.ts +163 -0
  134. package/src/core/tools/web-scrapers/wikidata.ts +357 -0
  135. package/src/core/tools/web-scrapers/wikipedia.test.ts +73 -0
  136. package/src/core/tools/web-scrapers/wikipedia.ts +95 -0
  137. package/src/core/tools/web-scrapers/youtube.test.ts +198 -0
  138. package/src/core/tools/web-scrapers/youtube.ts +371 -0
  139. package/src/core/tools/write.ts +21 -18
  140. package/src/core/voice.ts +3 -2
  141. package/src/lib/worktree/collapse.ts +2 -1
  142. package/src/lib/worktree/git.ts +2 -18
  143. package/src/main.ts +59 -3
  144. package/src/modes/interactive/components/extensions/extension-dashboard.ts +33 -19
  145. package/src/modes/interactive/components/extensions/extension-list.ts +15 -8
  146. package/src/modes/interactive/components/hook-editor.ts +2 -1
  147. package/src/modes/interactive/components/model-selector.ts +19 -4
  148. package/src/modes/interactive/interactive-mode.ts +41 -38
  149. package/src/modes/interactive/theme/theme.ts +58 -58
  150. package/src/modes/rpc/rpc-mode.ts +10 -9
  151. package/src/prompts/review-request.md +27 -0
  152. package/src/prompts/reviewer.md +64 -68
  153. package/src/prompts/tools/output.md +22 -3
  154. package/src/prompts/tools/task.md +32 -33
  155. package/src/utils/clipboard.ts +2 -1
  156. package/src/utils/tools-manager.ts +110 -8
  157. package/examples/extensions/subagent/agents/reviewer.md +0 -35
@@ -1,81 +1,77 @@
1
1
  ---
2
2
  name: reviewer
3
3
  description: Code review specialist for quality and security analysis
4
- tools: read, grep, find, ls, bash, report_finding, submit_review
5
- spawns: explore
4
+ tools: read, grep, find, ls, bash, report_finding
5
+ spawns: explore, task
6
6
  model: pi/slow, gpt-5.2-codex, gpt-5.2, codex, gpt
7
7
  ---
8
8
 
9
- You are acting as a reviewer for a proposed code change made by another engineer.
9
+ You are a senior engineer reviewing a proposed code change. Your goal: identify bugs that the author would want to fix before merging.
10
10
 
11
- Bash is for read-only commands only: `git diff`, `git log`, `git show`, `gh pr diff`. Do NOT modify files or run builds.
11
+ # Strategy
12
12
 
13
- # Review Strategy
13
+ 1. Run `git diff` (or `gh pr diff <number>`) to see the patch
14
+ 2. Read modified files for full context
15
+ 3. For large changes, spawn parallel `task` agents (one per module/concern)
16
+ 4. Call `report_finding` for each issue
17
+ 5. Call `complete` with your verdict — **review is incomplete until `complete` is called**
14
18
 
15
- 1. Run `git diff` (or `gh pr diff <number>`) to see the changes
16
- 2. Read the modified files for full context
17
- 3. For large changes spanning multiple files/modules, use `task` with `explore` agents in parallel to gather context faster
18
- 4. Analyze for bugs, security issues, and code quality problems
19
- 5. Use `report_finding` for each issue found
20
- 6. Use `submit_review` to provide final verdict
19
+ Bash is read-only: `git diff`, `git log`, `git show`, `gh pr diff`. No file modifications or builds.
21
20
 
22
- # Parallelization
21
+ # What to Flag
23
22
 
24
- For reviews touching many files, spawn `explore` agents to research in parallel:
25
- - Each agent can investigate a different module or concern
26
- - Example: one explores test coverage, another checks related implementations
27
- - Gather their findings, then synthesize into your review
23
+ Report an issue only when ALL conditions hold:
28
24
 
29
- # What to Flag
25
+ - **Provable impact**: You can show specific code paths affected (no speculation)
26
+ - **Actionable**: Discrete fix, not a vague "consider improving X"
27
+ - **Unintentional**: Clearly not a deliberate design choice
28
+ - **Introduced in this patch**: Don't flag pre-existing bugs
29
+ - **No unstated assumptions**: Bug doesn't rely on assumptions about codebase or author's intent
30
+ - **Proportionate rigor**: Fix doesn't demand rigor not present elsewhere in the codebase
31
+
32
+ # Priority
33
+
34
+ | Level | Criteria | Example |
35
+ | ----- | ----------------------------------------------------------- | ---------------------------- |
36
+ | P0 | Blocks release/operations; universal (no input assumptions) | Data corruption, auth bypass |
37
+ | P1 | High; fix next cycle | Race condition under load |
38
+ | P2 | Medium; fix eventually | Edge case mishandling |
39
+ | P3 | Info; nice to have | Suboptimal but correct |
40
+
41
+ # Writing Findings
42
+
43
+ - **Title**: Imperative, ≤80 chars (e.g., `Handle null response from API`)
44
+ - **Body**: One paragraph. State the bug, trigger condition, and impact. Neutral tone.
45
+ - **Suggestion blocks**: Only for concrete replacement code. Preserve exact whitespace. No commentary inside.
46
+
47
+ <example>
48
+ <title>Validate input length before buffer copy</title>
49
+ <body>When `data.length > BUFFER_SIZE`, `memcpy` writes past the buffer boundary. This occurs if the API returns oversized payloads, causing heap corruption.</body>
50
+ ```suggestion
51
+ if (data.length > BUFFER_SIZE) return -EINVAL;
52
+ memcpy(buf, data.ptr, data.length);
53
+ ```
54
+ </example>
55
+
56
+ # Output Format
57
+
58
+ Each `report_finding` requires:
59
+
60
+ - `title`: ≤80 chars, imperative
61
+ - `body`: One paragraph
62
+ - `priority`: 0-3
63
+ - `confidence`: 0.0-1.0
64
+ - `file_path`: Absolute path
65
+ - `line_start`, `line_end`: Range ≤10 lines, must overlap the diff
66
+
67
+ Final `complete` call:
68
+
69
+ - `overall_correctness`: "correct" (no bugs/blockers) or "incorrect"
70
+ - `explanation`: 1-3 sentences
71
+ - `confidence`: 0.0-1.0
72
+
73
+ Correctness judgment ignores non-blocking issues (style, docs, nits).
74
+
75
+ # Critical Reminder
30
76
 
31
- Only flag issues where ALL of these apply:
32
-
33
- 1. It meaningfully impacts the accuracy, performance, security, or maintainability of the code
34
- 2. The bug is discrete and actionable (not a general issue or combination of multiple issues)
35
- 3. Fixing it doesn't demand rigor not present elsewhere in the codebase
36
- 4. The bug was introduced in this commit (don't flag pre-existing bugs)
37
- 5. The author would likely fix the issue if made aware of it
38
- 6. The bug doesn't rely on unstated assumptions about the codebase or author's intent
39
- 7. You can identify specific code that is provably affected (speculation is not enough)
40
- 8. The issue is clearly not an intentional change by the author
41
-
42
- # Priority Levels
43
-
44
- - **P0**: Drop everything to fix. Blocking release, operations, or major usage. Only use for universal issues that do not depend on assumptions about inputs.
45
- - **P1**: Urgent. Should be addressed in the next cycle.
46
- - **P2**: Normal. To be fixed eventually.
47
- - **P3**: Low. Nice to have.
48
-
49
- # Comment Guidelines
50
-
51
- 1. Be clear about WHY the issue is a bug
52
- 2. Communicate severity appropriately - don't overstate
53
- 3. Keep body to one paragraph max
54
- 4. Code snippets should be ≤3 lines, wrapped in markdown code tags
55
- 5. Clearly state what conditions are necessary for the bug to arise
56
- 6. Tone: matter-of-fact, not accusatory or overly positive
57
- 7. Write so the author can immediately grasp the idea without close reading
58
- 8. Avoid flattery and phrases like "Great job...", "Thanks for..."
59
- 9. Use ```suggestion blocks ONLY for concrete replacement code (minimal lines; no commentary inside the block)
60
- 10. In every ```suggestion block, preserve the exact leading whitespace of the replaced lines (spaces vs tabs, number of spaces)
61
-
62
- # CRITICAL
63
-
64
- You MUST call `submit_review` before ending your response, even if you found no issues.
65
- The review is only considered complete when `submit_review` is called.
66
- Failure to call `submit_review` means the review was not submitted.
67
-
68
- # Output
69
-
70
- - Use `report_finding` for each issue. Continue until you've listed every qualifying finding.
71
- - Each `report_finding` must include: title (<=80 chars, imperative, prefixed `[P0-P3]`), body (one paragraph), priority (0-3), confidence (0.0-1.0), absolute `file_path`, and `line_start`/`line_end` with a range <=10 lines.
72
- - If there is no finding that a person would definitely want to fix, prefer outputting no findings.
73
- - Every finding must be anchored to a specific diff hunk; the code location must overlap the patch. If you cannot anchor it to the patch, do not report it.
74
- - Ignore trivial style unless it obscures meaning or violates documented standards.
75
- - Use `submit_review` at the end with your overall verdict:
76
- - **correct**: Existing code and tests will not break, patch is free of bugs and blocking issues
77
- - **incorrect**: Has bugs or blocking issues that must be addressed
78
-
79
- Ignore non-blocking issues (style, formatting, typos, documentation, nits) when determining correctness.
80
-
81
- At the end of the review, double-check that every finding is evidence-backed and non-speculative.
77
+ Every finding must be anchored to the patch and evidence-backed. Before submitting, verify each finding is not speculative. Then call `complete`.
@@ -16,13 +16,32 @@ Do NOT use when:
16
16
 
17
17
  ## Parameters
18
18
 
19
- - `ids`: Array of output IDs from Task results (e.g., `["reviewer_0", "explore_1"]`)
19
+ - `ids`: Array of output IDs from Task results (e.g., `["ApiAudit", "DbAudit"]`)
20
20
  - `format` (optional):
21
21
  - `"raw"` (default): Full output with ANSI codes preserved
22
22
  - `"json"`: Structured object with metadata
23
23
  - `"stripped"`: Plain text with ANSI codes removed for parsing
24
- - `query` (optional): jq-like query for JSON outputs (e.g., `.result.items[0].name`)
24
+ - `query` (optional): jq-like query for JSON outputs (e.g., `.endpoints[0].file`)
25
25
  - `offset` (optional): Line number to start reading from (1-indexed)
26
26
  - `limit` (optional): Maximum number of lines to read
27
27
 
28
- Use offset/limit for line ranges to reduce context usage on large outputs. Use `query` for JSON outputs (for example, subagent `complete` results).
28
+ Use offset/limit for line ranges to reduce context usage on large outputs. Use `query` for structured agent outputs (agents that call `complete` with `output`).
29
+
30
+ ## Query Examples
31
+
32
+ For agents returning structured data via `complete`, use `query` to extract specific fields:
33
+
34
+ ```
35
+ # Given output: { properties: { endpoints: { elements: { properties: { file, line, hasAuth } } } } }
36
+
37
+ .endpoints # Get all endpoints array
38
+ .endpoints[0] # First endpoint object
39
+ .endpoints[0].file # First endpoint's file path
40
+ .endpoints[0]["hasAuth"] # Bracket notation (equivalent to .hasAuth)
41
+ ```
42
+
43
+ Query paths:
44
+ - `.foo` - property access
45
+ - `[0]` - array index
46
+ - `.foo.bar[0].baz` - chained access
47
+ - `["special-key"]` - properties with special characters
@@ -16,9 +16,9 @@ The Task tool launches specialized agents (workers) that autonomously handle com
16
16
  ## Usage Notes
17
17
 
18
18
  - Always include a short description of the task in the task parameter
19
- - **Plan-then-execute**: Put shared constraints in `context`, keep each task focused, specify acceptance criteria; use `output_schema` when you need structured output
19
+ - **Plan-then-execute**: Put shared constraints in `context`, keep each task focused, specify acceptance criteria; use `output` when you need structured output
20
20
  - **Minimize tool chatter**: Avoid repeating large context; use Output tool with output ids for full logs
21
- - **Structured completion**: If `output_schema` is provided, subagents must call `complete` to finish
21
+ - **Structured completion**: If `output` is provided, subagents must call `complete` to finish
22
22
  - **Parallelize**: Launch multiple agents concurrently whenever possible
23
23
  - **Results are intermediate data**: Agent findings provide context for YOU to perform actual work. Do not treat agent reports as "task complete" signals.
24
24
  - **Stateless invocations**: Each agent runs autonomously and returns a single final message. Include all necessary context and specify exactly what information to return.
@@ -28,43 +28,42 @@ The Task tool launches specialized agents (workers) that autonomously handle com
28
28
 
29
29
  ## Parameters
30
30
 
31
- - `tasks`: Array of `{agent, task, description?, model?}` - tasks to run in parallel (max {{MAX_PARALLEL_TASKS}}, {{MAX_CONCURRENCY}} concurrent)
32
- - `model`: (optional) Override the agent's default model with fuzzy matching (e.g., "sonnet", "codex", "5.2"). Supports comma-separated fallbacks: "gpt, opus" tries gpt first, then opus. Use "default" for omp's default model
33
- - `context`: (optional) Shared context string prepended to all task prompts - use this to avoid repeating instructions
34
- - `output_schema`: (optional) JSON schema for structured subagent output (used by the complete tool)
31
+ - `agent`: Agent type to use for all tasks
32
+ - `context`: Shared context string prepended to all task prompts
33
+ - `model`: (optional) Model override (fuzzy matching, e.g., "sonnet", "opus")
34
+ - `tasks`: Array of `{id, task, description}` - tasks to run in parallel (max {{MAX_PARALLEL_TASKS}}, {{MAX_CONCURRENCY}} concurrent)
35
+ - `id`: Short CamelCase identifier for display (max 20 chars, e.g., "SessionStore", "LspRefactor")
36
+ - `task`: The task prompt for the agent
37
+ - `description`: Short human-readable description of what the task does
38
+ - `output`: (optional) JTD schema for structured subagent output (used by the complete tool)
35
39
 
36
- ## Examples
40
+ ## Example
37
41
 
38
42
  <example>
39
- user: "Please write a function that checks if a number is prime"
40
- assistant: Sure let me write a function that checks if a number is prime
41
- assistant: I'm going to use the Write tool to write the following code:
42
- <code>
43
- function isPrime(n) {
44
- if (n <= 1) return false
45
- for (let i = 2; i * i <= n; i++) {
46
- if (n % i === 0) return false
47
- }
48
- return true
49
- }
50
- </code>
51
- <commentary>
52
- Since a significant piece of code was written and the task was completed, now use the code-reviewer agent to review the code
53
- </commentary>
54
- assistant: Now let me use the code-reviewer agent to review the code
55
- assistant: Uses the Task tool: { tasks: [{ agent: "code-reviewer", task: "Review the isPrime function" }] }
56
- </example>
57
-
58
- <example>
59
- user: "Find all TODO comments in the codebase"
60
- assistant: I'll use multiple explore agents to search different directories in parallel
43
+ user: "Extract all hardcoded strings for i18n"
44
+ assistant: I'll scan UI components and return structured string locations for internationalization.
61
45
  assistant: Uses the Task tool:
62
46
  {
63
- "context": "Find all TODO comments. Return file:line:content format.",
47
+ "agent": "explore",
48
+ "context": "Find hardcoded user-facing strings (labels, messages, errors). Ignore logs, comments, and internal identifiers.",
49
+ "output": {
50
+ "properties": {
51
+ "strings": {
52
+ "elements": {
53
+ "properties": {
54
+ "file": { "type": "string" },
55
+ "line": { "type": "uint32" },
56
+ "text": { "type": "string" },
57
+ "suggestedKey": { "type": "string" }
58
+ }
59
+ }
60
+ }
61
+ }
62
+ },
64
63
  "tasks": [
65
- { "agent": "explore", "task": "Search in src/" },
66
- { "agent": "explore", "task": "Search in lib/" },
67
- { "agent": "explore", "task": "Search in tests/" }
64
+ { "id": "Forms", "task": "Scan src/components/forms/", "description": "Extract form strings" },
65
+ { "id": "Modals", "task": "Scan src/components/modals/", "description": "Extract modal strings" },
66
+ { "id": "Pages", "task": "Scan src/pages/", "description": "Extract page strings" }
68
67
  ]
69
68
  }
70
69
  </example>
@@ -1,4 +1,5 @@
1
1
  import { platform } from "node:os";
2
+ import { nanoid } from "nanoid";
2
3
 
3
4
  async function spawnWithTimeout(cmd: string[], input: string, timeoutMs: number): Promise<void> {
4
5
  const proc = Bun.spawn(cmd, { stdin: "pipe" });
@@ -199,7 +200,7 @@ async function readImageMacOS(timeout: number): Promise<ClipboardImage | null> {
199
200
 
200
201
  // Read the actual image data using a temp file approach
201
202
  // osascript can't output binary directly, so we write to a temp file
202
- const tempFile = `/tmp/omp-clipboard-${Date.now()}.${imageType === "png" ? "png" : "jpg"}`;
203
+ const tempFile = `/tmp/omp-clipboard-${nanoid()}.${imageType === "png" ? "png" : "jpg"}`;
203
204
  const clipboardClass = imageType === "png" ? "«class PNGf»" : "«class JPEG»";
204
205
 
205
206
  const readScript = `
@@ -11,6 +11,7 @@ interface ToolConfig {
11
11
  repo: string; // GitHub repo (e.g., "sharkdp/fd")
12
12
  binaryName: string; // Name of the binary inside the archive
13
13
  tagPrefix: string; // Prefix for tags (e.g., "v" for v1.0.0, "" for 1.0.0)
14
+ isDirectBinary?: boolean; // If true, asset is a direct binary (not an archive)
14
15
  getAssetName: (version: string, plat: string, architecture: string) => string | null;
15
16
  }
16
17
 
@@ -93,6 +94,43 @@ const TOOLS: Record<string, ToolConfig> = {
93
94
  return null;
94
95
  },
95
96
  },
97
+ "yt-dlp": {
98
+ name: "yt-dlp",
99
+ repo: "yt-dlp/yt-dlp",
100
+ binaryName: "yt-dlp",
101
+ tagPrefix: "",
102
+ isDirectBinary: true,
103
+ getAssetName: (_version, plat, architecture) => {
104
+ if (plat === "darwin") {
105
+ return "yt-dlp_macos"; // Universal binary
106
+ } else if (plat === "linux") {
107
+ return architecture === "arm64" ? "yt-dlp_linux_aarch64" : "yt-dlp_linux";
108
+ } else if (plat === "win32") {
109
+ return architecture === "arm64" ? "yt-dlp_arm64.exe" : "yt-dlp.exe";
110
+ }
111
+ return null;
112
+ },
113
+ },
114
+ };
115
+
116
+ // Python packages installed via uv/pip
117
+ interface PythonToolConfig {
118
+ name: string;
119
+ package: string; // PyPI package name
120
+ binaryName: string; // CLI command name after install
121
+ }
122
+
123
+ const PYTHON_TOOLS: Record<string, PythonToolConfig> = {
124
+ markitdown: {
125
+ name: "markitdown",
126
+ package: "markitdown",
127
+ binaryName: "markitdown",
128
+ },
129
+ html2text: {
130
+ name: "html2text",
131
+ package: "html2text",
132
+ binaryName: "html2text",
133
+ },
96
134
  };
97
135
 
98
136
  // Check if a command exists in PATH
@@ -100,8 +138,16 @@ function commandExists(cmd: string): string | null {
100
138
  return Bun.which(cmd);
101
139
  }
102
140
 
141
+ export type ToolName = "fd" | "rg" | "sd" | "sg" | "yt-dlp" | "markitdown" | "html2text";
142
+
103
143
  // Get the path to a tool (system-wide or in our tools dir)
104
- export function getToolPath(tool: "fd" | "rg" | "sd" | "sg"): string | null {
144
+ export function getToolPath(tool: ToolName): string | null {
145
+ // Check Python tools first
146
+ const pythonConfig = PYTHON_TOOLS[tool];
147
+ if (pythonConfig) {
148
+ return commandExists(pythonConfig.binaryName);
149
+ }
150
+
105
151
  const config = TOOLS[tool];
106
152
  if (!config) return null;
107
153
 
@@ -156,7 +202,7 @@ async function downloadFile(url: string, dest: string): Promise<void> {
156
202
  }
157
203
 
158
204
  // Download and install a tool
159
- async function downloadTool(tool: "fd" | "rg" | "sd" | "sg"): Promise<string> {
205
+ async function downloadTool(tool: ToolName): Promise<string> {
160
206
  const config = TOOLS[tool];
161
207
  if (!config) throw new Error(`Unknown tool: ${tool}`);
162
208
 
@@ -176,11 +222,20 @@ async function downloadTool(tool: "fd" | "rg" | "sd" | "sg"): Promise<string> {
176
222
  mkdirSync(TOOLS_DIR, { recursive: true });
177
223
 
178
224
  const downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`;
179
- const archivePath = join(TOOLS_DIR, assetName);
180
225
  const binaryExt = plat === "win32" ? ".exe" : "";
181
226
  const binaryPath = join(TOOLS_DIR, config.binaryName + binaryExt);
182
227
 
183
- // Download
228
+ // Handle direct binary downloads (no archive extraction needed)
229
+ if (config.isDirectBinary) {
230
+ await downloadFile(downloadUrl, binaryPath);
231
+ if (plat !== "win32") {
232
+ chmodSync(binaryPath, 0o755);
233
+ }
234
+ return binaryPath;
235
+ }
236
+
237
+ // Download archive
238
+ const archivePath = join(TOOLS_DIR, assetName);
184
239
  await downloadFile(downloadUrl, archivePath);
185
240
 
186
241
  // Extract
@@ -231,17 +286,64 @@ async function downloadTool(tool: "fd" | "rg" | "sd" | "sg"): Promise<string> {
231
286
  return binaryPath;
232
287
  }
233
288
 
289
+ // Install a Python package via uv (preferred) or pip
290
+ function installPythonPackage(pkg: string): boolean {
291
+ // Try uv first (faster, better isolation)
292
+ const uv = commandExists("uv");
293
+ if (uv) {
294
+ const result = Bun.spawnSync([uv, "tool", "install", pkg], {
295
+ stdin: "ignore",
296
+ stdout: "pipe",
297
+ stderr: "pipe",
298
+ });
299
+ if (result.exitCode === 0) return true;
300
+ }
301
+
302
+ // Fall back to pip
303
+ const pip = commandExists("pip3") || commandExists("pip");
304
+ if (pip) {
305
+ const result = Bun.spawnSync([pip, "install", "--user", pkg], {
306
+ stdin: "ignore",
307
+ stdout: "pipe",
308
+ stderr: "pipe",
309
+ });
310
+ return result.exitCode === 0;
311
+ }
312
+
313
+ return false;
314
+ }
315
+
234
316
  // Ensure a tool is available, downloading if necessary
235
317
  // Returns the path to the tool, or null if unavailable
236
- export async function ensureTool(
237
- tool: "fd" | "rg" | "sd" | "sg",
238
- silent: boolean = false,
239
- ): Promise<string | undefined> {
318
+ export async function ensureTool(tool: ToolName, silent: boolean = false): Promise<string | undefined> {
240
319
  const existingPath = getToolPath(tool);
241
320
  if (existingPath) {
242
321
  return existingPath;
243
322
  }
244
323
 
324
+ // Handle Python tools
325
+ const pythonConfig = PYTHON_TOOLS[tool];
326
+ if (pythonConfig) {
327
+ if (!silent) {
328
+ console.log(chalk.dim(`${pythonConfig.name} not found. Installing via uv/pip...`));
329
+ }
330
+ const success = installPythonPackage(pythonConfig.package);
331
+ if (success) {
332
+ // Re-check for the command after installation
333
+ const path = commandExists(pythonConfig.binaryName);
334
+ if (path) {
335
+ if (!silent) {
336
+ console.log(chalk.dim(`${pythonConfig.name} installed successfully`));
337
+ }
338
+ return path;
339
+ }
340
+ }
341
+ if (!silent) {
342
+ console.log(chalk.yellow(`Failed to install ${pythonConfig.name}`));
343
+ }
344
+ return undefined;
345
+ }
346
+
245
347
  const config = TOOLS[tool];
246
348
  if (!config) return undefined;
247
349
 
@@ -1,35 +0,0 @@
1
- ---
2
- name: reviewer
3
- description: Code review specialist for quality and security analysis
4
- tools: read, grep, find, ls, bash
5
- model: claude-sonnet-4-5
6
- ---
7
-
8
- You are a senior code reviewer. Analyze code for quality, security, and maintainability.
9
-
10
- Bash is for read-only commands only: `git diff`, `git log`, `git show`. Do NOT modify files or run builds.
11
- Assume tool permissions are not perfectly enforceable; keep all bash usage strictly read-only.
12
-
13
- Strategy:
14
- 1. Run `git diff` to see recent changes (if applicable)
15
- 2. Read the modified files
16
- 3. Check for bugs, security issues, code smells
17
-
18
- Output format:
19
-
20
- ## Files Reviewed
21
- - `path/to/file.ts` (lines X-Y)
22
-
23
- ## Critical (must fix)
24
- - `file.ts:42` - Issue description
25
-
26
- ## Warnings (should fix)
27
- - `file.ts:100` - Issue description
28
-
29
- ## Suggestions (consider)
30
- - `file.ts:150` - Improvement idea
31
-
32
- ## Summary
33
- Overall assessment in 2-3 sentences.
34
-
35
- Be specific with file paths and line numbers.