@oh-my-pi/pi-coding-agent 13.18.0 → 14.0.2

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 (235) hide show
  1. package/CHANGELOG.md +316 -1
  2. package/package.json +86 -24
  3. package/scripts/format-prompts.ts +2 -2
  4. package/src/autoresearch/apply-contract-to-state.ts +24 -0
  5. package/src/autoresearch/contract.ts +0 -44
  6. package/src/autoresearch/dashboard.ts +1 -2
  7. package/src/autoresearch/git.ts +116 -30
  8. package/src/autoresearch/helpers.ts +49 -0
  9. package/src/autoresearch/index.ts +28 -187
  10. package/src/autoresearch/prompt.md +26 -9
  11. package/src/autoresearch/state.ts +0 -6
  12. package/src/autoresearch/tools/init-experiment.ts +202 -117
  13. package/src/autoresearch/tools/log-experiment.ts +123 -178
  14. package/src/autoresearch/tools/run-experiment.ts +48 -10
  15. package/src/autoresearch/types.ts +2 -2
  16. package/src/capability/index.ts +4 -2
  17. package/src/cli/file-processor.ts +3 -3
  18. package/src/cli/grep-cli.ts +8 -8
  19. package/src/cli/grievances-cli.ts +78 -0
  20. package/src/cli/read-cli.ts +67 -0
  21. package/src/cli/setup-cli.ts +4 -4
  22. package/src/cli/update-cli.ts +3 -3
  23. package/src/cli.ts +2 -0
  24. package/src/commands/grep.ts +6 -1
  25. package/src/commands/grievances.ts +20 -0
  26. package/src/commands/read.ts +33 -0
  27. package/src/commit/agentic/agent.ts +5 -8
  28. package/src/commit/agentic/index.ts +22 -26
  29. package/src/commit/agentic/tools/analyze-file.ts +3 -3
  30. package/src/commit/agentic/tools/git-file-diff.ts +3 -6
  31. package/src/commit/agentic/tools/git-hunk.ts +3 -3
  32. package/src/commit/agentic/tools/git-overview.ts +6 -9
  33. package/src/commit/agentic/tools/index.ts +6 -8
  34. package/src/commit/agentic/tools/propose-commit.ts +4 -7
  35. package/src/commit/agentic/tools/recent-commits.ts +3 -3
  36. package/src/commit/agentic/tools/split-commit.ts +4 -4
  37. package/src/commit/agentic/validation.ts +1 -1
  38. package/src/commit/analysis/conventional.ts +4 -4
  39. package/src/commit/analysis/summary.ts +3 -3
  40. package/src/commit/changelog/generate.ts +4 -4
  41. package/src/commit/changelog/index.ts +5 -9
  42. package/src/commit/map-reduce/map-phase.ts +4 -4
  43. package/src/commit/map-reduce/reduce-phase.ts +4 -4
  44. package/src/commit/pipeline.ts +13 -16
  45. package/src/config/keybindings.ts +7 -6
  46. package/src/config/prompt-templates.ts +44 -226
  47. package/src/config/resolve-config-value.ts +4 -2
  48. package/src/config/settings-schema.ts +98 -2
  49. package/src/config/settings.ts +25 -26
  50. package/src/dap/client.ts +674 -0
  51. package/src/dap/config.ts +150 -0
  52. package/src/dap/defaults.json +211 -0
  53. package/src/dap/index.ts +4 -0
  54. package/src/dap/session.ts +1255 -0
  55. package/src/dap/types.ts +600 -0
  56. package/src/debug/log-viewer.ts +3 -2
  57. package/src/discovery/builtin.ts +1 -2
  58. package/src/discovery/codex.ts +2 -2
  59. package/src/discovery/github.ts +2 -1
  60. package/src/discovery/helpers.ts +2 -2
  61. package/src/discovery/opencode.ts +2 -2
  62. package/src/edit/diff.ts +818 -0
  63. package/src/edit/index.ts +309 -0
  64. package/src/edit/line-hash.ts +67 -0
  65. package/src/edit/modes/chunk.ts +454 -0
  66. package/src/{patch → edit/modes}/hashline.ts +741 -361
  67. package/src/{patch/applicator.ts → edit/modes/patch.ts} +420 -117
  68. package/src/{patch/fuzzy.ts → edit/modes/replace.ts} +519 -197
  69. package/src/{patch → edit}/normalize.ts +97 -76
  70. package/src/{patch/shared.ts → edit/renderer.ts} +181 -108
  71. package/src/exec/bash-executor.ts +4 -2
  72. package/src/exec/idle-timeout-watchdog.ts +126 -0
  73. package/src/exec/non-interactive-env.ts +5 -0
  74. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +6 -18
  75. package/src/extensibility/custom-commands/bundled/review/index.ts +45 -43
  76. package/src/extensibility/custom-commands/loader.ts +1 -2
  77. package/src/extensibility/custom-tools/loader.ts +34 -11
  78. package/src/extensibility/custom-tools/types.ts +1 -1
  79. package/src/extensibility/extensions/loader.ts +9 -4
  80. package/src/extensibility/extensions/runner.ts +24 -1
  81. package/src/extensibility/extensions/types.ts +4 -2
  82. package/src/extensibility/hooks/loader.ts +5 -6
  83. package/src/extensibility/hooks/types.ts +2 -2
  84. package/src/extensibility/plugins/doctor.ts +2 -1
  85. package/src/extensibility/plugins/marketplace/fetcher.ts +2 -57
  86. package/src/extensibility/plugins/marketplace/source-resolver.ts +4 -4
  87. package/src/extensibility/slash-commands.ts +3 -7
  88. package/src/index.ts +3 -1
  89. package/src/internal-urls/docs-index.generated.ts +11 -11
  90. package/src/ipy/executor.ts +58 -17
  91. package/src/ipy/gateway-coordinator.ts +6 -4
  92. package/src/ipy/kernel.ts +45 -22
  93. package/src/ipy/runtime.ts +2 -2
  94. package/src/lsp/client.ts +7 -4
  95. package/src/lsp/clients/lsp-linter-client.ts +4 -4
  96. package/src/lsp/config.ts +2 -2
  97. package/src/lsp/defaults.json +688 -154
  98. package/src/lsp/index.ts +234 -45
  99. package/src/lsp/lspmux.ts +2 -2
  100. package/src/lsp/startup-events.ts +13 -0
  101. package/src/lsp/types.ts +12 -1
  102. package/src/lsp/utils.ts +8 -1
  103. package/src/main.ts +125 -47
  104. package/src/memories/index.ts +4 -5
  105. package/src/modes/acp/acp-agent.ts +563 -163
  106. package/src/modes/acp/acp-event-mapper.ts +9 -1
  107. package/src/modes/acp/acp-mode.ts +4 -2
  108. package/src/modes/components/agent-dashboard.ts +3 -4
  109. package/src/modes/components/diff.ts +6 -7
  110. package/src/modes/components/footer.ts +9 -29
  111. package/src/modes/components/hook-editor.ts +3 -3
  112. package/src/modes/components/hook-selector.ts +6 -1
  113. package/src/modes/components/read-tool-group.ts +6 -12
  114. package/src/modes/components/session-observer-overlay.ts +472 -0
  115. package/src/modes/components/settings-defs.ts +24 -0
  116. package/src/modes/components/status-line.ts +15 -61
  117. package/src/modes/components/tool-execution.ts +1 -1
  118. package/src/modes/components/welcome.ts +1 -1
  119. package/src/modes/controllers/btw-controller.ts +2 -2
  120. package/src/modes/controllers/command-controller.ts +4 -2
  121. package/src/modes/controllers/event-controller.ts +59 -2
  122. package/src/modes/controllers/extension-ui-controller.ts +1 -0
  123. package/src/modes/controllers/input-controller.ts +15 -8
  124. package/src/modes/controllers/selector-controller.ts +26 -0
  125. package/src/modes/index.ts +20 -2
  126. package/src/modes/interactive-mode.ts +278 -69
  127. package/src/modes/rpc/host-tools.ts +186 -0
  128. package/src/modes/rpc/rpc-client.ts +178 -13
  129. package/src/modes/rpc/rpc-mode.ts +73 -3
  130. package/src/modes/rpc/rpc-types.ts +53 -1
  131. package/src/modes/session-observer-registry.ts +146 -0
  132. package/src/modes/shared.ts +0 -42
  133. package/src/modes/theme/theme.ts +80 -8
  134. package/src/modes/types.ts +4 -2
  135. package/src/modes/utils/keybinding-matchers.ts +9 -0
  136. package/src/prompts/system/custom-system-prompt.md +5 -0
  137. package/src/prompts/system/system-prompt.md +8 -1
  138. package/src/prompts/tools/chunk-edit.md +219 -0
  139. package/src/prompts/tools/debug.md +43 -0
  140. package/src/prompts/tools/grep.md +3 -0
  141. package/src/prompts/tools/lsp.md +5 -5
  142. package/src/prompts/tools/read-chunk.md +17 -0
  143. package/src/prompts/tools/read.md +19 -5
  144. package/src/sdk.ts +216 -165
  145. package/src/secrets/index.ts +1 -1
  146. package/src/secrets/obfuscator.ts +25 -17
  147. package/src/session/agent-session.ts +381 -286
  148. package/src/session/agent-storage.ts +12 -12
  149. package/src/session/compaction/branch-summarization.ts +3 -3
  150. package/src/session/compaction/compaction.ts +5 -6
  151. package/src/session/compaction/utils.ts +3 -3
  152. package/src/session/history-storage.ts +62 -19
  153. package/src/session/messages.ts +3 -3
  154. package/src/session/session-dump-format.ts +203 -0
  155. package/src/session/session-manager.ts +15 -5
  156. package/src/session/session-storage.ts +4 -2
  157. package/src/session/streaming-output.ts +1 -1
  158. package/src/session/tool-choice-queue.ts +213 -0
  159. package/src/slash-commands/builtin-registry.ts +56 -8
  160. package/src/ssh/connection-manager.ts +2 -2
  161. package/src/ssh/sshfs-mount.ts +5 -5
  162. package/src/stt/downloader.ts +4 -4
  163. package/src/stt/recorder.ts +4 -4
  164. package/src/stt/transcriber.ts +2 -2
  165. package/src/system-prompt.ts +25 -13
  166. package/src/task/agents.ts +5 -6
  167. package/src/task/commands.ts +2 -5
  168. package/src/task/executor.ts +32 -4
  169. package/src/task/index.ts +91 -82
  170. package/src/task/template.ts +2 -2
  171. package/src/task/types.ts +25 -0
  172. package/src/task/worktree.ts +131 -149
  173. package/src/tools/ask.ts +2 -3
  174. package/src/tools/ast-edit.ts +7 -7
  175. package/src/tools/ast-grep.ts +7 -7
  176. package/src/tools/auto-generated-guard.ts +36 -41
  177. package/src/tools/await-tool.ts +2 -2
  178. package/src/tools/bash.ts +5 -23
  179. package/src/tools/browser.ts +4 -5
  180. package/src/tools/calculator.ts +2 -3
  181. package/src/tools/cancel-job.ts +2 -2
  182. package/src/tools/checkpoint.ts +3 -3
  183. package/src/tools/debug.ts +1007 -0
  184. package/src/tools/exit-plan-mode.ts +3 -3
  185. package/src/tools/fetch.ts +67 -3
  186. package/src/tools/find.ts +4 -5
  187. package/src/tools/fs-cache-invalidation.ts +5 -0
  188. package/src/tools/gemini-image.ts +13 -5
  189. package/src/tools/gh.ts +130 -308
  190. package/src/tools/grep.ts +57 -9
  191. package/src/tools/index.ts +44 -22
  192. package/src/tools/inspect-image.ts +4 -4
  193. package/src/tools/output-meta.ts +1 -1
  194. package/src/tools/python.ts +19 -6
  195. package/src/tools/read.ts +211 -146
  196. package/src/tools/render-mermaid.ts +2 -3
  197. package/src/tools/render-utils.ts +20 -6
  198. package/src/tools/renderers.ts +3 -1
  199. package/src/tools/report-tool-issue.ts +80 -0
  200. package/src/tools/resolve.ts +70 -39
  201. package/src/tools/search-tool-bm25.ts +2 -2
  202. package/src/tools/ssh.ts +2 -2
  203. package/src/tools/todo-write.ts +2 -2
  204. package/src/tools/tool-timeouts.ts +1 -0
  205. package/src/tools/write.ts +5 -6
  206. package/src/tui/tree-list.ts +3 -1
  207. package/src/utils/clipboard.ts +80 -0
  208. package/src/utils/commit-message-generator.ts +2 -3
  209. package/src/utils/edit-mode.ts +49 -0
  210. package/src/utils/external-editor.ts +11 -5
  211. package/src/utils/file-display-mode.ts +6 -5
  212. package/src/utils/file-mentions.ts +8 -7
  213. package/src/utils/git.ts +1400 -0
  214. package/src/utils/image-loading.ts +98 -0
  215. package/src/utils/title-generator.ts +2 -3
  216. package/src/utils/tools-manager.ts +6 -6
  217. package/src/web/scrapers/choosealicense.ts +1 -1
  218. package/src/web/search/index.ts +3 -3
  219. package/src/web/search/render.ts +6 -4
  220. package/src/autoresearch/command-initialize.md +0 -34
  221. package/src/commit/git/errors.ts +0 -9
  222. package/src/commit/git/index.ts +0 -210
  223. package/src/commit/git/operations.ts +0 -54
  224. package/src/patch/diff.ts +0 -433
  225. package/src/patch/index.ts +0 -888
  226. package/src/patch/parser.ts +0 -532
  227. package/src/patch/types.ts +0 -292
  228. package/src/prompts/agents/oracle.md +0 -77
  229. package/src/tools/gh-cli.ts +0 -125
  230. package/src/tools/pending-action.ts +0 -49
  231. package/src/utils/child-process.ts +0 -88
  232. package/src/utils/frontmatter.ts +0 -117
  233. package/src/utils/image-input.ts +0 -274
  234. package/src/utils/mime.ts +0 -53
  235. package/src/utils/prompt-format.ts +0 -170
@@ -1,292 +0,0 @@
1
- /**
2
- * Shared types for the edit tool module.
3
- */
4
-
5
- // ═══════════════════════════════════════════════════════════════════════════
6
- // File System Abstraction
7
- // ═══════════════════════════════════════════════════════════════════════════
8
-
9
- /** Abstraction for file system operations to support LSP writethrough */
10
- export interface FileSystem {
11
- exists(path: string): Promise<boolean>;
12
- read(path: string): Promise<string>;
13
- readBinary?: (path: string) => Promise<Uint8Array>;
14
- write(path: string, content: string): Promise<void>;
15
- delete(path: string): Promise<void>;
16
- mkdir(path: string): Promise<void>;
17
- }
18
-
19
- // ═══════════════════════════════════════════════════════════════════════════
20
- // Fuzzy Matching Types
21
- // ═══════════════════════════════════════════════════════════════════════════
22
-
23
- /** Result of a fuzzy match operation */
24
- export interface FuzzyMatch {
25
- /** The actual text that was matched */
26
- actualText: string;
27
- /** Character index where the match starts */
28
- startIndex: number;
29
- /** Line number where the match starts (1-indexed) */
30
- startLine: number;
31
- /** Confidence score (0-1, where 1 is exact match) */
32
- confidence: number;
33
- }
34
-
35
- /** Outcome of attempting to find a match */
36
- export interface MatchOutcome {
37
- /** The match if found with sufficient confidence */
38
- match?: FuzzyMatch;
39
- /** The closest match found (may be below threshold) */
40
- closest?: FuzzyMatch;
41
- /** Number of occurrences if multiple exact matches found */
42
- occurrences?: number;
43
- /** Line numbers where occurrences were found (1-indexed) */
44
- occurrenceLines?: number[];
45
- /** Preview snippets for each occurrence (up to 5) */
46
- occurrencePreviews?: string[];
47
- /** Number of fuzzy matches above threshold */
48
- fuzzyMatches?: number;
49
- /** True when a dominant fuzzy match was accepted despite multiple candidates */
50
- dominantFuzzy?: boolean;
51
- }
52
-
53
- /** Result of a sequence search */
54
- export type SequenceMatchStrategy =
55
- | "exact"
56
- | "trim-trailing"
57
- | "trim"
58
- | "comment-prefix"
59
- | "unicode"
60
- | "prefix"
61
- | "substring"
62
- | "fuzzy"
63
- | "fuzzy-dominant"
64
- | "character";
65
-
66
- export interface SequenceSearchResult {
67
- /** Starting line index of the match (0-indexed) */
68
- index: number | undefined;
69
- /** Confidence score (1.0 for exact match, lower for fuzzy) */
70
- confidence: number;
71
- /** Number of matches at the same confidence level (for ambiguity detection) */
72
- matchCount?: number;
73
- /** Sample of matching indices (0-indexed, up to a small limit) */
74
- matchIndices?: number[];
75
- /** Matching strategy used */
76
- strategy?: SequenceMatchStrategy;
77
- }
78
-
79
- /** Result of a context line search */
80
- export type ContextMatchStrategy = "exact" | "trim" | "unicode" | "prefix" | "substring" | "fuzzy";
81
-
82
- export interface ContextLineResult {
83
- /** Index of the matching line (0-indexed) */
84
- index: number | undefined;
85
- /** Confidence score (1.0 for exact match, lower for fuzzy) */
86
- confidence: number;
87
- /** Number of matches at the same confidence level (for ambiguity detection) */
88
- matchCount?: number;
89
- /** Sample of matching indices (0-indexed, up to a small limit) */
90
- matchIndices?: number[];
91
- /** Matching strategy used */
92
- strategy?: ContextMatchStrategy;
93
- }
94
-
95
- // ═══════════════════════════════════════════════════════════════════════════
96
- // Patch Types
97
- // ═══════════════════════════════════════════════════════════════════════════
98
-
99
- export type Operation = "create" | "delete" | "update";
100
-
101
- /** Input for a patch operation */
102
- export interface PatchInput {
103
- /** File path (relative or absolute) */
104
- path: string;
105
- /** Operation type */
106
- op: Operation;
107
- /** New path for rename (update only) */
108
- rename?: string;
109
- /** File content (create) or diff hunks (update) */
110
- diff?: string;
111
- }
112
-
113
- /** Normalized patch input used internally by the applicator. */
114
- export interface NormalizedPatchInput {
115
- path: string;
116
- op: Operation;
117
- rename?: string;
118
- diff?: string;
119
- }
120
-
121
- export function normalizePatchInput(input: PatchInput): NormalizedPatchInput {
122
- return {
123
- path: input.path,
124
- op: input.op ?? "update",
125
- rename: input.rename,
126
- diff: input.diff,
127
- };
128
- }
129
-
130
- /** A single hunk/chunk in a diff */
131
- export interface DiffHunk {
132
- /** Context line to narrow down position (e.g., class/method definition) */
133
- changeContext?: string;
134
- /** 1-based line hint from unified diff headers (old file) */
135
- oldStartLine?: number;
136
- /** 1-based line hint from unified diff headers (new file) */
137
- newStartLine?: number;
138
- /** True if the hunk contains context lines (space-prefixed) */
139
- hasContextLines: boolean;
140
- /** Lines to be replaced (old content) */
141
- oldLines: string[];
142
- /** Lines to replace with (new content) */
143
- newLines: string[];
144
- /** If true, oldLines must occur at end of file */
145
- isEndOfFile: boolean;
146
- }
147
-
148
- /** Describes a change made to a file */
149
- export interface FileChange {
150
- type: Operation;
151
- path: string;
152
- newPath?: string;
153
- oldContent?: string;
154
- newContent?: string;
155
- }
156
-
157
- /** Result of applying a patch */
158
- export interface ApplyPatchResult {
159
- change: FileChange;
160
- warnings?: string[];
161
- }
162
-
163
- /** Options for applying a patch */
164
- export interface ApplyPatchOptions {
165
- /** Working directory for resolving relative paths */
166
- cwd: string;
167
- /** Dry run - compute changes without writing */
168
- dryRun?: boolean;
169
- /** Similarity threshold for fuzzy matching */
170
- fuzzyThreshold?: number;
171
- /** Allow fuzzy/partial matching when applying hunks */
172
- allowFuzzy?: boolean;
173
- /** File system abstraction (defaults to Bun-based implementation) */
174
- fs?: FileSystem;
175
- }
176
-
177
- // ═══════════════════════════════════════════════════════════════════════════
178
- // Diff Generation Types
179
- // ═══════════════════════════════════════════════════════════════════════════
180
-
181
- /** Result of generating a diff */
182
- export interface DiffResult {
183
- /** The unified diff string */
184
- diff: string;
185
- /** Line number of the first change in the new file */
186
- firstChangedLine: number | undefined;
187
- }
188
-
189
- /** Error from diff computation */
190
- export interface DiffError {
191
- error: string;
192
- }
193
-
194
- // ═══════════════════════════════════════════════════════════════════════════
195
- // Hashline Types
196
- // ═══════════════════════════════════════════════════════════════════════════
197
-
198
- /**
199
- * Hashline edit operation/input types are schema-derived in `patch/index.ts`
200
- * via `Static<typeof hashlineEditItemSchema>` and `Static<typeof hashlineEditSchema>`.
201
- */
202
-
203
- /** A single hash mismatch found during validation */
204
- export interface HashMismatch {
205
- /** 1-indexed line number */
206
- line: number;
207
- /** Hash the caller provided */
208
- expected: string;
209
- /** Hash computed from the current file content */
210
- actual: string;
211
- }
212
-
213
- // ═══════════════════════════════════════════════════════════════════════════
214
- // Error Classes
215
- // ═══════════════════════════════════════════════════════════════════════════
216
-
217
- export class ParseError extends Error {
218
- constructor(
219
- message: string,
220
- public readonly lineNumber?: number,
221
- ) {
222
- super(lineNumber !== undefined ? `Line ${lineNumber}: ${message}` : message);
223
- this.name = "ParseError";
224
- }
225
- }
226
-
227
- export class ApplyPatchError extends Error {
228
- constructor(message: string) {
229
- super(message);
230
- this.name = "ApplyPatchError";
231
- }
232
- }
233
-
234
- export class EditMatchError extends Error {
235
- constructor(
236
- public readonly path: string,
237
- public readonly searchText: string,
238
- public readonly closest: FuzzyMatch | undefined,
239
- public readonly options: { allowFuzzy: boolean; threshold: number; fuzzyMatches?: number },
240
- ) {
241
- super(EditMatchError.formatMessage(path, searchText, closest, options));
242
- this.name = "EditMatchError";
243
- }
244
-
245
- static formatMessage(
246
- path: string,
247
- searchText: string,
248
- closest: FuzzyMatch | undefined,
249
- options: { allowFuzzy: boolean; threshold: number; fuzzyMatches?: number },
250
- ): string {
251
- if (!closest) {
252
- return options.allowFuzzy
253
- ? `Could not find a close enough match in ${path}.`
254
- : `Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`;
255
- }
256
-
257
- const similarity = Math.round(closest.confidence * 100);
258
- const searchLines = searchText.split("\n");
259
- const actualLines = closest.actualText.split("\n");
260
- const { oldLine, newLine } = findFirstDifferentLine(searchLines, actualLines);
261
- const thresholdPercent = Math.round(options.threshold * 100);
262
-
263
- const hint = options.allowFuzzy
264
- ? options.fuzzyMatches && options.fuzzyMatches > 1
265
- ? `Found ${options.fuzzyMatches} high-confidence matches. Provide more context to make it unique.`
266
- : `Closest match was below the ${thresholdPercent}% similarity threshold.`
267
- : "Fuzzy matching is disabled. Enable 'Edit fuzzy match' in settings to accept high-confidence matches.";
268
-
269
- return [
270
- options.allowFuzzy
271
- ? `Could not find a close enough match in ${path}.`
272
- : `Could not find the exact text in ${path}.`,
273
- ``,
274
- `Closest match (${similarity}% similar) at line ${closest.startLine}:`,
275
- ` - ${oldLine}`,
276
- ` + ${newLine}`,
277
- hint,
278
- ].join("\n");
279
- }
280
- }
281
-
282
- function findFirstDifferentLine(oldLines: string[], newLines: string[]): { oldLine: string; newLine: string } {
283
- const max = Math.max(oldLines.length, newLines.length);
284
- for (let i = 0; i < max; i++) {
285
- const oldLine = oldLines[i] ?? "";
286
- const newLine = newLines[i] ?? "";
287
- if (oldLine !== newLine) {
288
- return { oldLine, newLine };
289
- }
290
- }
291
- return { oldLine: oldLines[0] ?? "", newLine: newLines[0] ?? "" };
292
- }
@@ -1,77 +0,0 @@
1
- ---
2
- name: oracle
3
- description: Deep reasoning advisor for debugging dead ends, architecture decisions, and second opinions. Read-only.
4
- tools: read, grep, find, bash, lsp, web_search, ast_grep
5
- spawns: explore
6
- model: pi/slow
7
- thinking-level: high
8
- blocking: true
9
- ---
10
-
11
- You are a senior diagnostician and strategic technical advisor. You receive problems other agents are stuck on — doom loops, mysterious failures, architectural tradeoffs, subtle bugs — and return clear, actionable analysis.
12
-
13
- You diagnose, explain, and recommend. You do not implement. Others act on your findings.
14
-
15
- <critical>
16
- You **MUST** operate as read-only. You **MUST NOT** write, edit, or modify files, nor execute any state-changing commands.
17
- </critical>
18
-
19
- <directives>
20
- - You **MUST** reason from first principles. The caller already tried the obvious.
21
- - You **MUST** use tools to verify claims. You **MUST NOT** speculate about code behavior — read it.
22
- - You **MUST** identify root causes, not symptoms. If the caller says "X is broken", determine *why* X is broken.
23
- - You **MUST** surface hidden assumptions — in the code, in the caller's framing, in the environment.
24
- - You **SHOULD** consider at least two hypotheses before converging on one.
25
- - You **SHOULD** invoke tools in parallel when investigating multiple hypotheses.
26
- - When the problem is architectural, you **MUST** weigh tradeoffs explicitly: what does each option cost, what does it buy, what does it foreclose.
27
- </directives>
28
-
29
- <decision-framework>
30
- Apply pragmatic minimalism:
31
- - **Bias toward simplicity**: The right solution is the least complex one that fulfills actual requirements. Resist hypothetical future needs.
32
- - **Leverage what exists**: Favor modifications to current code and established patterns over introducing new components. New dependencies or infrastructure require explicit justification.
33
- - **One clear path**: Present a single primary recommendation. Mention alternatives only when they offer substantially different tradeoffs worth considering.
34
- - **Match depth to complexity**: Quick questions get quick answers. Reserve thorough analysis for genuinely complex problems.
35
- - **Signal the investment**: Tag recommendations with estimated effort — Quick (<1h), Short (1-4h), Medium (1-2d), Large (3d+).
36
- </decision-framework>
37
-
38
- <procedure>
39
- 1. Read the problem statement carefully. Identify what was already tried and why it failed.
40
- 2. Form 2-3 hypotheses for the root cause.
41
- 3. Use tools to gather evidence — read relevant code, trace data flow, check types, grep for related patterns. Parallelize independent reads.
42
- 4. Eliminate hypotheses based on evidence. Narrow to the most likely cause.
43
- 5. If the problem is a decision (not a bug), lay out options with concrete tradeoffs.
44
- 6. Deliver a clear verdict with supporting evidence.
45
- </procedure>
46
-
47
- <output>
48
- Structure your response in tiers:
49
-
50
- **Always include:**
51
- - **Diagnosis**: What is actually wrong, or what the real tradeoff is. 2-3 sentences.
52
- - **Evidence**: Specific file paths, line numbers, code excerpts that support your conclusion.
53
- - **Recommendation**: What to do about it — concrete, actionable, with enough detail that an implementing agent can act without re-investigating. Numbered steps, each 1-2 sentences.
54
-
55
- **Include when relevant:**
56
- - **Caveats**: Anything you are not confident about. Uncertainty **MUST** be stated, not hidden.
57
- - **Risks**: Edge cases, failure modes, or mitigation strategies.
58
-
59
- **Only when genuinely applicable:**
60
- - **Escalation triggers**: Conditions that would justify a more complex solution.
61
- - **Alternative sketch**: High-level outline of an alternative path (not a full design).
62
-
63
- You **MUST NOT** pad with meta-commentary. Dense and useful beats long and thorough.
64
- </output>
65
-
66
- <scope-discipline>
67
- - Recommend ONLY what was asked. No unsolicited improvements.
68
- - If you notice other issues, list at most 2 as "Optional future considerations" at the end.
69
- - You **MUST NOT** expand the problem surface beyond the original request.
70
- - Exhaust provided context before reaching for tools. External lookups fill genuine gaps, not curiosity.
71
- </scope-discipline>
72
-
73
- <critical>
74
- You **MUST** keep going until you have a clear answer or have exhausted available evidence.
75
- Before finalizing: re-scan for unstated assumptions, verify claims are grounded in code not invented, check for overly strong language not justified by evidence.
76
- This matters. The caller is stuck. Get it right.
77
- </critical>
@@ -1,125 +0,0 @@
1
- import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
2
-
3
- export interface GhCommandResult {
4
- exitCode: number;
5
- stdout: string;
6
- stderr: string;
7
- }
8
-
9
- export interface GhCommandOptions {
10
- repoProvided?: boolean;
11
- trimOutput?: boolean;
12
- }
13
-
14
- export function isGhAvailable(): boolean {
15
- return Boolean(Bun.which("gh"));
16
- }
17
-
18
- function formatGhFailure(args: string[], stdout: string, stderr: string, options?: GhCommandOptions): string {
19
- const output = stderr || stdout;
20
- const message = output.trim();
21
-
22
- if (message.includes("gh auth login") || message.includes("not logged into any GitHub hosts")) {
23
- return "GitHub CLI is not authenticated. Run `gh auth login`.";
24
- }
25
-
26
- if (
27
- !options?.repoProvided &&
28
- (message.includes("not a git repository") ||
29
- message.includes("no git remotes found") ||
30
- message.includes("unable to determine current repository"))
31
- ) {
32
- return "GitHub repository context is unavailable. Pass `repo` explicitly or run the tool inside a GitHub checkout.";
33
- }
34
-
35
- if (message.length > 0) {
36
- return message;
37
- }
38
-
39
- return `GitHub CLI command failed: gh ${args.join(" ")}`;
40
- }
41
-
42
- export async function runGhCommand(
43
- cwd: string,
44
- args: string[],
45
- signal?: AbortSignal,
46
- options?: GhCommandOptions,
47
- ): Promise<GhCommandResult> {
48
- throwIfAborted(signal);
49
-
50
- if (!isGhAvailable()) {
51
- throw new ToolError("GitHub CLI (gh) is not installed. Install it from https://cli.github.com/.");
52
- }
53
-
54
- try {
55
- const child = Bun.spawn(["gh", ...args], {
56
- cwd,
57
- stdin: "ignore",
58
- stdout: "pipe",
59
- stderr: "pipe",
60
- windowsHide: true,
61
- signal,
62
- });
63
-
64
- if (!child.stdout || !child.stderr) {
65
- throw new ToolError("Failed to capture GitHub CLI output.");
66
- }
67
-
68
- const [stdout, stderr, exitCode] = await Promise.all([
69
- new Response(child.stdout).text(),
70
- new Response(child.stderr).text(),
71
- child.exited,
72
- ]);
73
-
74
- throwIfAborted(signal);
75
-
76
- return {
77
- exitCode: exitCode ?? 0,
78
- stdout: options?.trimOutput === false ? stdout : stdout.trim(),
79
- stderr: options?.trimOutput === false ? stderr : stderr.trim(),
80
- };
81
- } catch (error) {
82
- if (signal?.aborted) {
83
- throw new ToolAbortError();
84
- }
85
- throw error;
86
- }
87
- }
88
-
89
- export async function runGhJson<T>(
90
- cwd: string,
91
- args: string[],
92
- signal?: AbortSignal,
93
- options?: GhCommandOptions,
94
- ): Promise<T> {
95
- const result = await runGhCommand(cwd, args, signal, options);
96
-
97
- if (result.exitCode !== 0) {
98
- throw new ToolError(formatGhFailure(args, result.stdout, result.stderr, options));
99
- }
100
-
101
- if (!result.stdout) {
102
- throw new ToolError("GitHub CLI returned empty output.");
103
- }
104
-
105
- try {
106
- return JSON.parse(result.stdout) as T;
107
- } catch {
108
- throw new ToolError("GitHub CLI returned invalid JSON output.");
109
- }
110
- }
111
-
112
- export async function runGhText(
113
- cwd: string,
114
- args: string[],
115
- signal?: AbortSignal,
116
- options?: GhCommandOptions,
117
- ): Promise<string> {
118
- const result = await runGhCommand(cwd, args, signal, options);
119
-
120
- if (result.exitCode !== 0) {
121
- throw new ToolError(formatGhFailure(args, result.stdout, result.stderr, options));
122
- }
123
-
124
- return result.stdout;
125
- }
@@ -1,49 +0,0 @@
1
- import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
2
-
3
- export interface PendingAction {
4
- label: string;
5
- sourceToolName: string;
6
- apply(reason: string): Promise<AgentToolResult<unknown>>;
7
- reject?(reason: string): Promise<AgentToolResult<unknown> | undefined>;
8
- details?: unknown;
9
- }
10
-
11
- export class PendingActionStore {
12
- #actions: PendingAction[] = [];
13
- #pushListeners = new Set<(action: PendingAction, count: number) => void>();
14
-
15
- push(action: PendingAction): void {
16
- this.#actions.push(action);
17
- const count = this.#actions.length;
18
- for (const listener of this.#pushListeners) {
19
- listener(action, count);
20
- }
21
- }
22
-
23
- peek(): PendingAction | null {
24
- return this.#actions.at(-1) ?? null;
25
- }
26
-
27
- pop(): PendingAction | null {
28
- return this.#actions.pop() ?? null;
29
- }
30
-
31
- subscribePush(listener: (action: PendingAction, count: number) => void): () => void {
32
- this.#pushListeners.add(listener);
33
- return () => {
34
- this.#pushListeners.delete(listener);
35
- };
36
- }
37
-
38
- clear(): void {
39
- this.#actions = [];
40
- }
41
-
42
- get count(): number {
43
- return this.#actions.length;
44
- }
45
-
46
- get hasPending(): boolean {
47
- return this.#actions.length > 0;
48
- }
49
- }
@@ -1,88 +0,0 @@
1
- import type { ChildProcess } from "node:child_process";
2
-
3
- const EXIT_STDIO_GRACE_MS = 100;
4
-
5
- /**
6
- * Wait for a child process to terminate without hanging on inherited stdio handles.
7
- *
8
- * Daemonized descendants can inherit the child's stdout/stderr pipe handles. In that
9
- * case the child emits `exit`, but `close` can hang forever even though the original
10
- * process is already gone. We wait briefly for stdio to end, then forcibly stop
11
- * tracking the inherited handles.
12
- */
13
- export function waitForChildProcess(child: ChildProcess): Promise<number | null> {
14
- const { promise, resolve, reject } = Promise.withResolvers<number | null>();
15
-
16
- let settled = false;
17
- let exited = false;
18
- let exitCode: number | null = null;
19
- let postExitTimer: NodeJS.Timeout | undefined;
20
- let stdoutEnded = child.stdout === null;
21
- let stderrEnded = child.stderr === null;
22
-
23
- const cleanup = () => {
24
- if (postExitTimer) {
25
- clearTimeout(postExitTimer);
26
- postExitTimer = undefined;
27
- }
28
- child.removeListener("error", onError);
29
- child.removeListener("exit", onExit);
30
- child.removeListener("close", onClose);
31
- child.stdout?.removeListener("end", onStdoutEnd);
32
- child.stderr?.removeListener("end", onStderrEnd);
33
- };
34
-
35
- const finalize = (code: number | null) => {
36
- if (settled) return;
37
- settled = true;
38
- cleanup();
39
- child.stdout?.destroy();
40
- child.stderr?.destroy();
41
- resolve(code);
42
- };
43
-
44
- const maybeFinalizeAfterExit = () => {
45
- if (!exited || settled) return;
46
- if (stdoutEnded && stderrEnded) {
47
- finalize(exitCode);
48
- }
49
- };
50
-
51
- const onStdoutEnd = () => {
52
- stdoutEnded = true;
53
- maybeFinalizeAfterExit();
54
- };
55
-
56
- const onStderrEnd = () => {
57
- stderrEnded = true;
58
- maybeFinalizeAfterExit();
59
- };
60
-
61
- const onError = (err: Error) => {
62
- if (settled) return;
63
- settled = true;
64
- cleanup();
65
- reject(err);
66
- };
67
-
68
- const onExit = (code: number | null) => {
69
- exited = true;
70
- exitCode = code;
71
- maybeFinalizeAfterExit();
72
- if (!settled) {
73
- postExitTimer = setTimeout(() => finalize(code), EXIT_STDIO_GRACE_MS);
74
- }
75
- };
76
-
77
- const onClose = (code: number | null) => {
78
- finalize(code);
79
- };
80
-
81
- child.stdout?.once("end", onStdoutEnd);
82
- child.stderr?.once("end", onStderrEnd);
83
- child.once("error", onError);
84
- child.once("exit", onExit);
85
- child.once("close", onClose);
86
-
87
- return promise;
88
- }