@oh-my-pi/pi-coding-agent 12.13.0 → 12.14.1
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.
- package/CHANGELOG.md +69 -1
- package/package.json +8 -7
- package/scripts/generate-docs-index.ts +56 -0
- package/src/config/prompt-templates.ts +2 -2
- package/src/config/settings-schema.ts +10 -1
- package/src/discovery/builtin.ts +14 -4
- package/src/extensibility/extensions/types.ts +1 -0
- package/src/internal-urls/docs-index.generated.ts +101 -0
- package/src/internal-urls/docs-protocol.ts +84 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/router.ts +1 -1
- package/src/modes/controllers/event-controller.ts +20 -0
- package/src/modes/interactive-mode.ts +1 -1
- package/src/patch/diff.ts +1 -1
- package/src/patch/hashline.ts +197 -328
- package/src/patch/index.ts +325 -102
- package/src/patch/shared.ts +23 -40
- package/src/prompts/system/system-prompt.md +13 -2
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/grep.md +1 -1
- package/src/prompts/tools/hashline.md +192 -90
- package/src/prompts/tools/read.md +3 -1
- package/src/sdk.ts +17 -0
- package/src/session/agent-session.ts +1 -0
- package/src/tools/fetch.ts +4 -3
- package/src/tools/grep.ts +13 -3
- package/src/tools/read.ts +2 -2
- package/src/web/search/render.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [12.14.1] - 2026-02-19
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed `omp stats` failing on npm/bun installs by including required stats build files in published `@oh-my-pi/omp-stats` package ([#113](https://github.com/can1357/oh-my-pi/pull/113) by [@masonc15](https://github.com/masonc15))
|
|
10
|
+
|
|
11
|
+
## [12.14.0] - 2026-02-19
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Support for `docs://` internal URL protocol to access embedded documentation files (e.g., `docs://sdk.md`)
|
|
16
|
+
- Added `generate-docs-index` npm script to automatically index and embed documentation files at build time
|
|
17
|
+
- Support for executable tool files (.ts, .js, .sh, .bash, .py) in custom tools discovery alongside markdown files
|
|
18
|
+
- Display streamed tool intent in working message during agent execution
|
|
19
|
+
- Added `tools.intentTracing` setting to enable intent tracing, which asks the agent to describe the intent of each tool call before executing it
|
|
20
|
+
- Support for file deletion in hashline edit mode via `delete: true` parameter
|
|
21
|
+
- Support for file renaming/moving in hashline edit mode via `rename` parameter
|
|
22
|
+
- Optional content-replace edit variant in hashline mode (enabled via `PI_HL_REPLACETXT=1` environment variable)
|
|
23
|
+
- Support for grepping internal URLs (artifact://) by resolving them to their backing files
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- System prompt now identifies agent as operating inside Oh My Pi harness and instructs reading docs:// URLs for omp/pi topics
|
|
28
|
+
- Tool discovery now accepts executable script extensions (.ts, .js, .sh, .bash, .py) in addition to .json and .md files
|
|
29
|
+
- Updated bash and read tool documentation to reference `docs://` URL support
|
|
30
|
+
- Hashline format separator changed from pipe (`|`) to colon (`:`) for improved readability (e.g., `LINE#ID:content` instead of `LINE#ID|content`)
|
|
31
|
+
- Hashline hash representation changed from 4-character base36 to 2-character hexadecimal for more compact line references
|
|
32
|
+
- Hashline edit API: renamed `delete` parameter to `rm` for consistency with standard file operations
|
|
33
|
+
- Hashline edit API: renamed `rename` parameter to `mv` for consistency with standard file operations
|
|
34
|
+
- Hashline edit API: content-replace operations now require explicit `op: "replaceText"` field to distinguish from other edit types
|
|
35
|
+
- Hashline documentation terminology updated: references to 'anchors' replaced with 'tags' for clearer semantics
|
|
36
|
+
- Intent tracing now uses `_intent` field name in tool schemas
|
|
37
|
+
- Hashline edit API: renamed `set` operation to `target`/`new_content` for clearer semantics
|
|
38
|
+
- Hashline edit API: renamed `set_range` operation to `first`/`last`/`new_content`
|
|
39
|
+
- Hashline edit API: renamed `insert` operation fields from `body` to `inserted_lines` and made `inserted_lines` required non-empty
|
|
40
|
+
- Hashline edit API: flattened `replace` operation to top-level fields (`old_text`, `new_text`, `all`) when enabled
|
|
41
|
+
- Hashline edit validation now provides more specific error messages indicating which variant is expected
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- Grep tool now properly handles internal URL resolution when searching artifact paths
|
|
46
|
+
- Working message intent updates now fall back to tool execution events when streamed tool arguments omit the intent field
|
|
47
|
+
|
|
5
48
|
## [12.13.0] - 2026-02-19
|
|
49
|
+
|
|
6
50
|
### Breaking Changes
|
|
7
51
|
|
|
8
52
|
- Removed automatic line relocation when hash references become stale; edits with mismatched line hashes now fail with an error instead of silently relocating to matching lines elsewhere in the file
|
|
@@ -171,6 +215,7 @@
|
|
|
171
215
|
- Refactored session directory naming to use single-dash format for home-relative paths and double-dash format for absolute paths, with automatic migration of legacy session directories on first access
|
|
172
216
|
|
|
173
217
|
## [12.8.2] - 2026-02-17
|
|
218
|
+
|
|
174
219
|
### Changed
|
|
175
220
|
|
|
176
221
|
- Changed system environment context to use built-in `os` values for distro, kernel, and CPU model instead of native system-info data
|
|
@@ -183,11 +228,14 @@
|
|
|
183
228
|
## [12.8.0] - 2026-02-16
|
|
184
229
|
|
|
185
230
|
### Changed
|
|
231
|
+
|
|
186
232
|
- Improved `/changelog` performance by displaying only the most recent 3 versions by default, with a `--full` flag for the complete history ([#85](https://github.com/can1357/oh-my-pi/pull/85) by [@tctev](https://github.com/tctev))
|
|
187
233
|
- Centralized builtin slash command definitions and handlers into a shared registry, replacing the large input-controller if-chain dispatch
|
|
188
234
|
|
|
189
235
|
## [12.7.0] - 2026-02-16
|
|
236
|
+
|
|
190
237
|
### Added
|
|
238
|
+
|
|
191
239
|
- Added abort signal support to LSP file operations (`ensureFileOpen`, `refreshFile`) for cancellable file synchronization
|
|
192
240
|
- Added abort signal propagation through LSP request handlers (definition, references, hover, symbols, rename) enabling operation cancellation
|
|
193
241
|
- Added `shouldBypassAutocompleteOnEscape` callback to custom editor for context-aware escape key handling during active operations
|
|
@@ -202,7 +250,9 @@
|
|
|
202
250
|
- Added secret obfuscation: env vars matching secret patterns and `secrets.json` entries are replaced with placeholders before sending to LLM providers, deobfuscated in tool call arguments
|
|
203
251
|
- Added `secrets.enabled` setting to toggle secret obfuscation
|
|
204
252
|
- Added full regex literal support for `secrets.json` entries (`"/pattern/flags"` syntax with escaped `/` handling, automatic `g` flag enforcement)
|
|
253
|
+
|
|
205
254
|
### Changed
|
|
255
|
+
|
|
206
256
|
- Changed context promotion to trigger on context overflow instead of a configurable threshold, promoting to a larger model before attempting compaction
|
|
207
257
|
- Changed context promotion behavior to retry immediately on the promoted model without compacting, providing faster recovery from context limits
|
|
208
258
|
- Changed default grep context lines from 1 before/3 after to 0 before/0 after for more focused search results
|
|
@@ -217,20 +267,25 @@
|
|
|
217
267
|
- Updated web search provider priority order to include Brave (Exa → Brave → Jina → Perplexity → Anthropic → Gemini → Codex → Z.AI)
|
|
218
268
|
- Extended recency filter support to Brave provider alongside Perplexity
|
|
219
269
|
- Changed GitHub issue comment fetching to use paginated API requests with 100 comments per page instead of single request with 50-comment limit
|
|
270
|
+
|
|
220
271
|
### Removed
|
|
221
272
|
|
|
222
273
|
- Removed `contextPromotion.thresholdPercent` setting as context promotion now triggers only on overflow
|
|
223
274
|
|
|
224
275
|
### Fixed
|
|
276
|
+
|
|
225
277
|
- Fixed LSP operations to properly respect abort signals and throw `ToolAbortError` when cancelled
|
|
226
278
|
- Fixed workspace diagnostics process cleanup to remove abort event listeners in finally block
|
|
227
279
|
- Fixed PTY-backed bash execution to enforce timeout completion when detached child processes keep the PTY stream open ([#88](https://github.com/can1357/oh-my-pi/issues/88))
|
|
280
|
+
|
|
228
281
|
## [12.5.1] - 2026-02-15
|
|
282
|
+
|
|
229
283
|
### Added
|
|
230
284
|
|
|
231
285
|
- Added `repeatToolDescriptions` setting to render full tool descriptions in the system prompt instead of a tool name list
|
|
232
286
|
|
|
233
287
|
## [12.5.0] - 2026-02-15
|
|
288
|
+
|
|
234
289
|
### Breaking Changes
|
|
235
290
|
|
|
236
291
|
- Replaced `theme` setting with `theme.dark` and `theme.light` (auto-migrated)
|
|
@@ -281,6 +336,7 @@
|
|
|
281
336
|
- Sanitized debug log display to strip control codes, normalize tabs, and trim width
|
|
282
337
|
|
|
283
338
|
## [12.4.0] - 2026-02-14
|
|
339
|
+
|
|
284
340
|
### Changed
|
|
285
341
|
|
|
286
342
|
- Moved `sanitizeText` function from `@oh-my-pi/pi-utils` to `@oh-my-pi/pi-natives` for better code organization
|
|
@@ -296,6 +352,7 @@
|
|
|
296
352
|
- Fixed Cloudflare returning corrupted bytes when compression is negotiated in web scraper requests
|
|
297
353
|
|
|
298
354
|
## [12.3.0] - 2026-02-14
|
|
355
|
+
|
|
299
356
|
### Added
|
|
300
357
|
|
|
301
358
|
- Added autonomous memory extraction and consolidation system with configurable settings
|
|
@@ -341,6 +398,7 @@
|
|
|
341
398
|
- Fixed fetch tool to preserve actual response metadata (finalUrl, contentType) instead of defaults when requests fail
|
|
342
399
|
|
|
343
400
|
||||||| parent of a70a34c8b (fix(coding-agent/debug): Sanitized debug log rendering)
|
|
401
|
+
|
|
344
402
|
## [12.1.0] - 2026-02-13
|
|
345
403
|
|
|
346
404
|
### Added
|
|
@@ -392,6 +450,7 @@
|
|
|
392
450
|
- Removed @types/jsdom dependency
|
|
393
451
|
|
|
394
452
|
## [11.14.1] - 2026-02-12
|
|
453
|
+
|
|
395
454
|
### Changed
|
|
396
455
|
|
|
397
456
|
- Improved Bun binary detection to check `Bun.env.PI_COMPILED` environment variable
|
|
@@ -403,6 +462,7 @@
|
|
|
403
462
|
- Fixed Bun update process to properly handle version pinning and report installation mismatches
|
|
404
463
|
|
|
405
464
|
## [11.14.0] - 2026-02-12
|
|
465
|
+
|
|
406
466
|
### Added
|
|
407
467
|
|
|
408
468
|
- Added SwiftLint linter client with JSON reporter support for Swift file linting
|
|
@@ -455,6 +515,7 @@
|
|
|
455
515
|
- Refactored browser/file opening across multiple modules to use unified `openPath` utility for improved maintainability
|
|
456
516
|
|
|
457
517
|
## [11.12.0] - 2026-02-11
|
|
518
|
+
|
|
458
519
|
### Added
|
|
459
520
|
|
|
460
521
|
- Added `resolveFileDisplayMode` utility to centralize file display mode resolution across tools (read, grep, file mentions)
|
|
@@ -543,6 +604,7 @@
|
|
|
543
604
|
- Refactored hash line formatting to use async `streamHashLinesFromLines` for better performance
|
|
544
605
|
|
|
545
606
|
## [11.10.3] - 2026-02-10
|
|
607
|
+
|
|
546
608
|
### Added
|
|
547
609
|
|
|
548
610
|
- Exported `./patch/*` subpath for direct access to patch utilities
|
|
@@ -568,6 +630,7 @@
|
|
|
568
630
|
- Removed AggregateError unwrapping from console.warn in CLI initialization
|
|
569
631
|
|
|
570
632
|
## [11.10.1] - 2026-02-10
|
|
633
|
+
|
|
571
634
|
### Changed
|
|
572
635
|
|
|
573
636
|
- Migrated CLI framework from oclif to lightweight pi-utils CLI runner
|
|
@@ -582,6 +645,7 @@
|
|
|
582
645
|
- Removed custom oclif help renderer (oclif-help.ts)
|
|
583
646
|
|
|
584
647
|
## [11.10.0] - 2026-02-10
|
|
648
|
+
|
|
585
649
|
### Breaking Changes
|
|
586
650
|
|
|
587
651
|
- Changed `HashlineEdit.src` from string format (e.g., `"5:ab"`, `"5:ab..9:ef"`) to structured `SrcSpec` object with discriminated union types (`{ kind: "single", ref: "..." }`, `{ kind: "range", start: "...", end: "..." }`, etc.)
|
|
@@ -732,6 +796,7 @@
|
|
|
732
796
|
- Improved bash tool output draining after foreground completion to reduce tail output truncation
|
|
733
797
|
|
|
734
798
|
## [11.8.0] - 2026-02-10
|
|
799
|
+
|
|
735
800
|
### Added
|
|
736
801
|
|
|
737
802
|
- Added `ctx.reload()` method to extension command context to reload extensions, skills, prompts, and themes from disk
|
|
@@ -754,6 +819,7 @@
|
|
|
754
819
|
- Fixed archive extraction error handling to provide clear error messages on failure
|
|
755
820
|
|
|
756
821
|
## [11.7.0] - 2026-02-07
|
|
822
|
+
|
|
757
823
|
### Changed
|
|
758
824
|
|
|
759
825
|
- Enhanced error messages for failed Python cells to include full combined output context instead of just the error message
|
|
@@ -765,6 +831,7 @@
|
|
|
765
831
|
- Fixed tab character rendering in Python tool output display to properly format whitespace in cell output and status events
|
|
766
832
|
|
|
767
833
|
## [11.6.1] - 2026-02-07
|
|
834
|
+
|
|
768
835
|
### Fixed
|
|
769
836
|
|
|
770
837
|
- Fixed potential crash when rendering results with undefined details.results
|
|
@@ -813,6 +880,7 @@
|
|
|
813
880
|
- Removed ability to save screenshots to custom paths or artifacts directory
|
|
814
881
|
|
|
815
882
|
## [11.4.1] - 2026-02-06
|
|
883
|
+
|
|
816
884
|
### Fixed
|
|
817
885
|
|
|
818
886
|
- Fixed tab character display in error messages and bash tool output by properly replacing tabs with spaces
|
|
@@ -4786,4 +4854,4 @@ Initial public release.
|
|
|
4786
4854
|
- Git branch display in footer
|
|
4787
4855
|
- Message queueing during streaming responses
|
|
4788
4856
|
- OAuth integration for Gmail and Google Calendar access
|
|
4789
|
-
- HTML export with syntax highlighting and collapsible sections
|
|
4857
|
+
- HTML export with syntax highlighting and collapsible sections
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.14.1",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -78,18 +78,19 @@
|
|
|
78
78
|
"scripts": {
|
|
79
79
|
"check": "tsgo -p tsconfig.json",
|
|
80
80
|
"format-prompts": "bun scripts/format-prompts.ts",
|
|
81
|
+
"generate-docs-index": "bun scripts/generate-docs-index.ts",
|
|
81
82
|
"build:binary": "cd ../.. && bun --cwd=packages/stats scripts/generate-client-bundle.ts && bun --cwd=packages/natives run embed:native && bun build --compile --define PI_COMPILED=true --root . ./packages/coding-agent/src/cli.ts --outfile packages/coding-agent/dist/omp && bun --cwd=packages/natives run embed:native --reset && bun --cwd=packages/stats scripts/generate-client-bundle.ts --reset",
|
|
82
83
|
"generate-template": "bun scripts/generate-template.ts",
|
|
83
84
|
"test": "bun test"
|
|
84
85
|
},
|
|
85
86
|
"dependencies": {
|
|
86
87
|
"@mozilla/readability": "0.6.0",
|
|
87
|
-
"@oh-my-pi/omp-stats": "12.
|
|
88
|
-
"@oh-my-pi/pi-agent-core": "12.
|
|
89
|
-
"@oh-my-pi/pi-ai": "12.
|
|
90
|
-
"@oh-my-pi/pi-natives": "12.
|
|
91
|
-
"@oh-my-pi/pi-tui": "12.
|
|
92
|
-
"@oh-my-pi/pi-utils": "12.
|
|
88
|
+
"@oh-my-pi/omp-stats": "12.14.1",
|
|
89
|
+
"@oh-my-pi/pi-agent-core": "12.14.1",
|
|
90
|
+
"@oh-my-pi/pi-ai": "12.14.1",
|
|
91
|
+
"@oh-my-pi/pi-natives": "12.14.1",
|
|
92
|
+
"@oh-my-pi/pi-tui": "12.14.1",
|
|
93
|
+
"@oh-my-pi/pi-utils": "12.14.1",
|
|
93
94
|
"@sinclair/typebox": "^0.34.48",
|
|
94
95
|
"@xterm/headless": "^6.0.0",
|
|
95
96
|
"ajv": "^8.18.0",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Glob } from "bun";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
|
|
6
|
+
const docsDir = new URL("../../../docs/", import.meta.url).pathname;
|
|
7
|
+
const outputPath = new URL("../src/internal-urls/docs-index.generated.ts", import.meta.url).pathname;
|
|
8
|
+
const importBase = "../../../../docs";
|
|
9
|
+
|
|
10
|
+
function toIdentifier(relativePath: string): string {
|
|
11
|
+
const withoutExt = relativePath.replace(/\.md$/i, "");
|
|
12
|
+
const parts = withoutExt
|
|
13
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
14
|
+
.filter(Boolean)
|
|
15
|
+
.map((part, index) => {
|
|
16
|
+
if (index === 0) {
|
|
17
|
+
return part.toLowerCase();
|
|
18
|
+
}
|
|
19
|
+
return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const base = parts.length > 0 ? parts.join("") : "doc";
|
|
23
|
+
const safeBase = /^[0-9]/.test(base) ? `doc${base}` : base;
|
|
24
|
+
return `${safeBase}Md`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const glob = new Glob("**/*.md");
|
|
28
|
+
const entries: string[] = [];
|
|
29
|
+
for await (const relativePath of glob.scan(docsDir)) {
|
|
30
|
+
entries.push(relativePath.split(path.sep).join("/"));
|
|
31
|
+
}
|
|
32
|
+
entries.sort();
|
|
33
|
+
|
|
34
|
+
const usedIdentifiers = new Set<string>();
|
|
35
|
+
const docs = entries.map((relativePath) => {
|
|
36
|
+
let identifier = toIdentifier(relativePath);
|
|
37
|
+
let suffix = 2;
|
|
38
|
+
while (usedIdentifiers.has(identifier)) {
|
|
39
|
+
identifier = `${toIdentifier(relativePath)}${suffix}`;
|
|
40
|
+
suffix++;
|
|
41
|
+
}
|
|
42
|
+
usedIdentifiers.add(identifier);
|
|
43
|
+
return { relativePath, identifier };
|
|
44
|
+
});
|
|
45
|
+
docs.sort((a, b) => a.identifier.localeCompare(b.identifier) || a.relativePath.localeCompare(b.relativePath));
|
|
46
|
+
|
|
47
|
+
const imports = docs
|
|
48
|
+
.map(({ relativePath, identifier }) => `import ${identifier} from "${importBase}/${relativePath}" with { type: "text" };`)
|
|
49
|
+
.join("\n");
|
|
50
|
+
|
|
51
|
+
const mapEntries = docs.map(({ relativePath, identifier }) => `\t"${relativePath}": ${identifier},`).join("\n");
|
|
52
|
+
|
|
53
|
+
const output = `// Auto-generated by scripts/generate-docs-index.ts - DO NOT EDIT\n\n${imports}\n\nexport const EMBEDDED_DOCS: Readonly<Record<string, string>> = {\n${mapEntries}\n};\n\nexport const EMBEDDED_DOC_FILENAMES = Object.keys(EMBEDDED_DOCS).sort();\n`;
|
|
54
|
+
|
|
55
|
+
await Bun.write(outputPath, output);
|
|
56
|
+
console.log(`Generated ${path.relative(process.cwd(), outputPath)} (${docs.length} docs)`);
|
|
@@ -247,11 +247,11 @@ handlebars.registerHelper("hlineref", (lineNum: unknown, content: unknown): stri
|
|
|
247
247
|
|
|
248
248
|
/**
|
|
249
249
|
* {{hlinefull lineNum "content"}} — format a full read-style line with prefix.
|
|
250
|
-
* Returns `"lineNum#hash
|
|
250
|
+
* Returns `"lineNum#hash:content"`.
|
|
251
251
|
*/
|
|
252
252
|
handlebars.registerHelper("hlinefull", (lineNum: unknown, content: unknown): string => {
|
|
253
253
|
const { ref, text } = formatHashlineRef(lineNum, content);
|
|
254
|
-
return `${ref}
|
|
254
|
+
return `${ref}:${text}`;
|
|
255
255
|
});
|
|
256
256
|
|
|
257
257
|
export function renderPromptTemplate(template: string, context: TemplateContext = {}): string {
|
|
@@ -287,7 +287,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
287
287
|
ui: {
|
|
288
288
|
tab: "config",
|
|
289
289
|
label: "Read hash lines",
|
|
290
|
-
description: "Include line hashes in read output for hashline edit mode (LINE#ID
|
|
290
|
+
description: "Include line hashes in read output for hashline edit mode (LINE#ID:content)",
|
|
291
291
|
},
|
|
292
292
|
},
|
|
293
293
|
showHardwareCursor: {
|
|
@@ -502,6 +502,15 @@ export const SETTINGS_SCHEMA = {
|
|
|
502
502
|
description: "Launch browser in headless mode (disable to show browser UI)",
|
|
503
503
|
},
|
|
504
504
|
},
|
|
505
|
+
"tools.intentTracing": {
|
|
506
|
+
type: "boolean",
|
|
507
|
+
default: false,
|
|
508
|
+
ui: {
|
|
509
|
+
tab: "tools",
|
|
510
|
+
label: "Intent tracing",
|
|
511
|
+
description: "Ask the agent to describe the intent of each tool call before executing it",
|
|
512
|
+
},
|
|
513
|
+
},
|
|
505
514
|
|
|
506
515
|
// ─────────────────────────────────────────────────────────────────────────
|
|
507
516
|
// Task tool settings
|
package/src/discovery/builtin.ts
CHANGED
|
@@ -656,7 +656,7 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
|
|
|
656
656
|
|
|
657
657
|
fileLoadPromises.push(
|
|
658
658
|
loadFilesFromDir<CustomTool>(ctx, toolsDir, PROVIDER_ID, level, {
|
|
659
|
-
extensions: ["json", "md"],
|
|
659
|
+
extensions: ["json", "md", "ts", "js", "sh", "bash", "py"],
|
|
660
660
|
transform: (name, content, path, source) => {
|
|
661
661
|
if (name.endsWith(".json")) {
|
|
662
662
|
const data = parseJSON<{ name?: string; description?: string }>(content);
|
|
@@ -668,11 +668,21 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
|
|
|
668
668
|
_source: source,
|
|
669
669
|
};
|
|
670
670
|
}
|
|
671
|
-
|
|
671
|
+
if (name.endsWith(".md")) {
|
|
672
|
+
const { frontmatter } = parseFrontmatter(content, { source: path });
|
|
673
|
+
return {
|
|
674
|
+
name: (frontmatter.name as string) || name.replace(/\.md$/, ""),
|
|
675
|
+
path,
|
|
676
|
+
description: frontmatter.description as string | undefined,
|
|
677
|
+
level,
|
|
678
|
+
_source: source,
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
// Executable tool files (.ts, .js, .sh, .bash, .py)
|
|
682
|
+
const toolName = name.replace(/\.(ts|js|sh|bash|py)$/, "");
|
|
672
683
|
return {
|
|
673
|
-
name:
|
|
684
|
+
name: toolName,
|
|
674
685
|
path,
|
|
675
|
-
description: frontmatter.description as string | undefined,
|
|
676
686
|
level,
|
|
677
687
|
_source: source,
|
|
678
688
|
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-docs-index.ts - DO NOT EDIT
|
|
2
|
+
|
|
3
|
+
import bashToolRuntimeMd from "../../../../docs/bash-tool-runtime.md" with { type: "text" };
|
|
4
|
+
import blobArtifactArchitectureMd from "../../../../docs/blob-artifact-architecture.md" with { type: "text" };
|
|
5
|
+
import compactionMd from "../../../../docs/compaction.md" with { type: "text" };
|
|
6
|
+
import configUsageMd from "../../../../docs/config-usage.md" with { type: "text" };
|
|
7
|
+
import customToolsMd from "../../../../docs/custom-tools.md" with { type: "text" };
|
|
8
|
+
import environmentVariablesMd from "../../../../docs/environment-variables.md" with { type: "text" };
|
|
9
|
+
import extensionLoadingMd from "../../../../docs/extension-loading.md" with { type: "text" };
|
|
10
|
+
import extensionsMd from "../../../../docs/extensions.md" with { type: "text" };
|
|
11
|
+
import fsScanCacheArchitectureMd from "../../../../docs/fs-scan-cache-architecture.md" with { type: "text" };
|
|
12
|
+
import geminiManifestExtensionsMd from "../../../../docs/gemini-manifest-extensions.md" with { type: "text" };
|
|
13
|
+
import handoffGenerationPipelineMd from "../../../../docs/handoff-generation-pipeline.md" with { type: "text" };
|
|
14
|
+
import hooksMd from "../../../../docs/hooks.md" with { type: "text" };
|
|
15
|
+
import mcpProtocolTransportsMd from "../../../../docs/mcp-protocol-transports.md" with { type: "text" };
|
|
16
|
+
import mcpRuntimeLifecycleMd from "../../../../docs/mcp-runtime-lifecycle.md" with { type: "text" };
|
|
17
|
+
import mcpServerToolAuthoringMd from "../../../../docs/mcp-server-tool-authoring.md" with { type: "text" };
|
|
18
|
+
import modelsMd from "../../../../docs/models.md" with { type: "text" };
|
|
19
|
+
import nativesAddonLoaderRuntimeMd from "../../../../docs/natives-addon-loader-runtime.md" with { type: "text" };
|
|
20
|
+
import nativesArchitectureMd from "../../../../docs/natives-architecture.md" with { type: "text" };
|
|
21
|
+
import nativesBindingContractMd from "../../../../docs/natives-binding-contract.md" with { type: "text" };
|
|
22
|
+
import nativesBuildReleaseDebuggingMd from "../../../../docs/natives-build-release-debugging.md" with { type: "text" };
|
|
23
|
+
import nativesMediaSystemUtilsMd from "../../../../docs/natives-media-system-utils.md" with { type: "text" };
|
|
24
|
+
import nativesRustTaskCancellationMd from "../../../../docs/natives-rust-task-cancellation.md" with { type: "text" };
|
|
25
|
+
import nativesShellPtyProcessMd from "../../../../docs/natives-shell-pty-process.md" with { type: "text" };
|
|
26
|
+
import nativesTextSearchPipelineMd from "../../../../docs/natives-text-search-pipeline.md" with { type: "text" };
|
|
27
|
+
import nonCompactionRetryPolicyMd from "../../../../docs/non-compaction-retry-policy.md" with { type: "text" };
|
|
28
|
+
import notebookToolRuntimeMd from "../../../../docs/notebook-tool-runtime.md" with { type: "text" };
|
|
29
|
+
import pluginManagerInstallerPlumbingMd from "../../../../docs/plugin-manager-installer-plumbing.md" with { type: "text" };
|
|
30
|
+
import portingFromPiMonoMd from "../../../../docs/porting-from-pi-mono.md" with { type: "text" };
|
|
31
|
+
import portingToNativesMd from "../../../../docs/porting-to-natives.md" with { type: "text" };
|
|
32
|
+
import providerStreamingInternalsMd from "../../../../docs/provider-streaming-internals.md" with { type: "text" };
|
|
33
|
+
import pythonReplMd from "../../../../docs/python-repl.md" with { type: "text" };
|
|
34
|
+
import rpcMd from "../../../../docs/rpc.md" with { type: "text" };
|
|
35
|
+
import rulebookMatchingPipelineMd from "../../../../docs/rulebook-matching-pipeline.md" with { type: "text" };
|
|
36
|
+
import sdkMd from "../../../../docs/sdk.md" with { type: "text" };
|
|
37
|
+
import secretsMd from "../../../../docs/secrets.md" with { type: "text" };
|
|
38
|
+
import sessionMd from "../../../../docs/session.md" with { type: "text" };
|
|
39
|
+
import sessionOperationsExportShareForkResumeMd from "../../../../docs/session-operations-export-share-fork-resume.md" with { type: "text" };
|
|
40
|
+
import sessionSwitchingAndRecentListingMd from "../../../../docs/session-switching-and-recent-listing.md" with { type: "text" };
|
|
41
|
+
import sessionTreePlanMd from "../../../../docs/session-tree-plan.md" with { type: "text" };
|
|
42
|
+
import skillsMd from "../../../../docs/skills.md" with { type: "text" };
|
|
43
|
+
import slashCommandInternalsMd from "../../../../docs/slash-command-internals.md" with { type: "text" };
|
|
44
|
+
import taskAgentDiscoveryMd from "../../../../docs/task-agent-discovery.md" with { type: "text" };
|
|
45
|
+
import themeMd from "../../../../docs/theme.md" with { type: "text" };
|
|
46
|
+
import treeMd from "../../../../docs/tree.md" with { type: "text" };
|
|
47
|
+
import ttsrInjectionLifecycleMd from "../../../../docs/ttsr-injection-lifecycle.md" with { type: "text" };
|
|
48
|
+
import tuiMd from "../../../../docs/tui.md" with { type: "text" };
|
|
49
|
+
import tuiRuntimeInternalsMd from "../../../../docs/tui-runtime-internals.md" with { type: "text" };
|
|
50
|
+
|
|
51
|
+
export const EMBEDDED_DOCS: Readonly<Record<string, string>> = {
|
|
52
|
+
"bash-tool-runtime.md": bashToolRuntimeMd,
|
|
53
|
+
"blob-artifact-architecture.md": blobArtifactArchitectureMd,
|
|
54
|
+
"compaction.md": compactionMd,
|
|
55
|
+
"config-usage.md": configUsageMd,
|
|
56
|
+
"custom-tools.md": customToolsMd,
|
|
57
|
+
"environment-variables.md": environmentVariablesMd,
|
|
58
|
+
"extension-loading.md": extensionLoadingMd,
|
|
59
|
+
"extensions.md": extensionsMd,
|
|
60
|
+
"fs-scan-cache-architecture.md": fsScanCacheArchitectureMd,
|
|
61
|
+
"gemini-manifest-extensions.md": geminiManifestExtensionsMd,
|
|
62
|
+
"handoff-generation-pipeline.md": handoffGenerationPipelineMd,
|
|
63
|
+
"hooks.md": hooksMd,
|
|
64
|
+
"mcp-protocol-transports.md": mcpProtocolTransportsMd,
|
|
65
|
+
"mcp-runtime-lifecycle.md": mcpRuntimeLifecycleMd,
|
|
66
|
+
"mcp-server-tool-authoring.md": mcpServerToolAuthoringMd,
|
|
67
|
+
"models.md": modelsMd,
|
|
68
|
+
"natives-addon-loader-runtime.md": nativesAddonLoaderRuntimeMd,
|
|
69
|
+
"natives-architecture.md": nativesArchitectureMd,
|
|
70
|
+
"natives-binding-contract.md": nativesBindingContractMd,
|
|
71
|
+
"natives-build-release-debugging.md": nativesBuildReleaseDebuggingMd,
|
|
72
|
+
"natives-media-system-utils.md": nativesMediaSystemUtilsMd,
|
|
73
|
+
"natives-rust-task-cancellation.md": nativesRustTaskCancellationMd,
|
|
74
|
+
"natives-shell-pty-process.md": nativesShellPtyProcessMd,
|
|
75
|
+
"natives-text-search-pipeline.md": nativesTextSearchPipelineMd,
|
|
76
|
+
"non-compaction-retry-policy.md": nonCompactionRetryPolicyMd,
|
|
77
|
+
"notebook-tool-runtime.md": notebookToolRuntimeMd,
|
|
78
|
+
"plugin-manager-installer-plumbing.md": pluginManagerInstallerPlumbingMd,
|
|
79
|
+
"porting-from-pi-mono.md": portingFromPiMonoMd,
|
|
80
|
+
"porting-to-natives.md": portingToNativesMd,
|
|
81
|
+
"provider-streaming-internals.md": providerStreamingInternalsMd,
|
|
82
|
+
"python-repl.md": pythonReplMd,
|
|
83
|
+
"rpc.md": rpcMd,
|
|
84
|
+
"rulebook-matching-pipeline.md": rulebookMatchingPipelineMd,
|
|
85
|
+
"sdk.md": sdkMd,
|
|
86
|
+
"secrets.md": secretsMd,
|
|
87
|
+
"session.md": sessionMd,
|
|
88
|
+
"session-operations-export-share-fork-resume.md": sessionOperationsExportShareForkResumeMd,
|
|
89
|
+
"session-switching-and-recent-listing.md": sessionSwitchingAndRecentListingMd,
|
|
90
|
+
"session-tree-plan.md": sessionTreePlanMd,
|
|
91
|
+
"skills.md": skillsMd,
|
|
92
|
+
"slash-command-internals.md": slashCommandInternalsMd,
|
|
93
|
+
"task-agent-discovery.md": taskAgentDiscoveryMd,
|
|
94
|
+
"theme.md": themeMd,
|
|
95
|
+
"tree.md": treeMd,
|
|
96
|
+
"ttsr-injection-lifecycle.md": ttsrInjectionLifecycleMd,
|
|
97
|
+
"tui.md": tuiMd,
|
|
98
|
+
"tui-runtime-internals.md": tuiRuntimeInternalsMd,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const EMBEDDED_DOC_FILENAMES = Object.keys(EMBEDDED_DOCS).sort();
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol handler for docs:// URLs.
|
|
3
|
+
*
|
|
4
|
+
* Serves statically embedded documentation files bundled at build time.
|
|
5
|
+
*
|
|
6
|
+
* URL forms:
|
|
7
|
+
* - docs:// - Lists all available documentation files
|
|
8
|
+
* - docs://<file>.md - Reads a specific documentation file
|
|
9
|
+
*/
|
|
10
|
+
import * as path from "node:path";
|
|
11
|
+
import { EMBEDDED_DOC_FILENAMES, EMBEDDED_DOCS } from "./docs-index.generated";
|
|
12
|
+
import type { InternalResource, InternalUrl, ProtocolHandler } from "./types";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Handler for docs:// URLs.
|
|
16
|
+
*
|
|
17
|
+
* Resolves documentation file names to their content, or lists available docs.
|
|
18
|
+
*/
|
|
19
|
+
export class DocsProtocolHandler implements ProtocolHandler {
|
|
20
|
+
readonly scheme = "docs";
|
|
21
|
+
|
|
22
|
+
async resolve(url: InternalUrl): Promise<InternalResource> {
|
|
23
|
+
// Extract filename from host + path
|
|
24
|
+
const host = url.rawHost || url.hostname;
|
|
25
|
+
const pathname = url.rawPathname ?? url.pathname;
|
|
26
|
+
const filename = host ? (pathname && pathname !== "/" ? host + pathname : host) : "";
|
|
27
|
+
|
|
28
|
+
if (!filename) {
|
|
29
|
+
return this.#listDocs(url);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return this.#readDoc(filename, url);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async #listDocs(url: InternalUrl): Promise<InternalResource> {
|
|
36
|
+
if (EMBEDDED_DOC_FILENAMES.length === 0) {
|
|
37
|
+
throw new Error("No documentation files found");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const listing = EMBEDDED_DOC_FILENAMES.map(f => `- [${f}](docs://${f})`).join("\n");
|
|
41
|
+
const content = `# Documentation\n\n${EMBEDDED_DOC_FILENAMES.length} files available:\n\n${listing}\n`;
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
url: url.href,
|
|
45
|
+
content,
|
|
46
|
+
contentType: "text/markdown",
|
|
47
|
+
size: Buffer.byteLength(content, "utf-8"),
|
|
48
|
+
sourcePath: "docs://",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async #readDoc(filename: string, url: InternalUrl): Promise<InternalResource> {
|
|
53
|
+
// Validate: no traversal, no absolute paths
|
|
54
|
+
if (path.isAbsolute(filename)) {
|
|
55
|
+
throw new Error("Absolute paths are not allowed in docs:// URLs");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const normalized = path.posix.normalize(filename.replaceAll("\\", "/"));
|
|
59
|
+
if (normalized === ".." || normalized.startsWith("../") || normalized.includes("/../")) {
|
|
60
|
+
throw new Error("Path traversal (..) is not allowed in docs:// URLs");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const content = EMBEDDED_DOCS[normalized];
|
|
64
|
+
if (content === undefined) {
|
|
65
|
+
const lookup = normalized.replace(/\.md$/, "");
|
|
66
|
+
const suggestions = EMBEDDED_DOC_FILENAMES.filter(
|
|
67
|
+
f => f.includes(lookup) || lookup.includes(f.replace(/\.md$/, "")),
|
|
68
|
+
).slice(0, 5);
|
|
69
|
+
const suffix =
|
|
70
|
+
suggestions.length > 0
|
|
71
|
+
? `\nDid you mean: ${suggestions.join(", ")}`
|
|
72
|
+
: "\nUse docs:// to list available files.";
|
|
73
|
+
throw new Error(`Documentation file not found: ${filename}${suffix}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
url: url.href,
|
|
78
|
+
content,
|
|
79
|
+
contentType: "text/markdown",
|
|
80
|
+
size: Buffer.byteLength(content, "utf-8"),
|
|
81
|
+
sourcePath: `docs://${normalized}`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
export { AgentProtocolHandler, type AgentProtocolOptions } from "./agent-protocol";
|
|
24
24
|
export { ArtifactProtocolHandler, type ArtifactProtocolOptions } from "./artifact-protocol";
|
|
25
|
+
export { DocsProtocolHandler } from "./docs-protocol";
|
|
25
26
|
export { applyQuery, parseQuery, pathToQuery } from "./json-query";
|
|
26
27
|
export { MemoryProtocolHandler, type MemoryProtocolOptions, resolveMemoryUrlToPath } from "./memory-protocol";
|
|
27
28
|
export { PlanProtocolHandler, type PlanProtocolOptions, resolvePlanUrlToPath } from "./plan-protocol";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Internal URL router for internal protocols (agent://, artifact://, plan://, memory://, skill://, rule://).
|
|
2
|
+
* Internal URL router for internal protocols (agent://, artifact://, plan://, memory://, skill://, rule://, docs://).
|
|
3
3
|
*/
|
|
4
4
|
import type { InternalResource, InternalUrl, ProtocolHandler } from "./types";
|
|
5
5
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { INTENT_FIELD } from "@oh-my-pi/pi-agent-core";
|
|
1
2
|
import { Loader, TERMINAL, Text } from "@oh-my-pi/pi-tui";
|
|
2
3
|
import { settings } from "../../config/settings";
|
|
3
4
|
import { AssistantMessageComponent } from "../../modes/components/assistant-message";
|
|
@@ -14,6 +15,7 @@ export class EventController {
|
|
|
14
15
|
#lastReadGroup: ReadToolGroupComponent | undefined = undefined;
|
|
15
16
|
#lastThinkingCount = 0;
|
|
16
17
|
#renderedCustomMessages = new Set<string>();
|
|
18
|
+
#lastIntent: string | undefined = undefined;
|
|
17
19
|
|
|
18
20
|
constructor(private ctx: InteractiveModeContext) {}
|
|
19
21
|
|
|
@@ -32,6 +34,13 @@ export class EventController {
|
|
|
32
34
|
return this.#lastReadGroup;
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
#updateWorkingMessageFromIntent(intent: string | undefined): void {
|
|
38
|
+
const trimmed = intent?.trim();
|
|
39
|
+
if (!trimmed || trimmed === this.#lastIntent) return;
|
|
40
|
+
this.#lastIntent = trimmed;
|
|
41
|
+
this.ctx.setWorkingMessage(`${trimmed} (esc to interrupt)`);
|
|
42
|
+
}
|
|
43
|
+
|
|
35
44
|
subscribeToAgent(): void {
|
|
36
45
|
this.ctx.unsubscribe = this.ctx.session.subscribe(async (event: AgentSessionEvent) => {
|
|
37
46
|
await this.handleEvent(event);
|
|
@@ -48,6 +57,7 @@ export class EventController {
|
|
|
48
57
|
|
|
49
58
|
switch (event.type) {
|
|
50
59
|
case "agent_start":
|
|
60
|
+
this.#lastIntent = undefined;
|
|
51
61
|
if (this.ctx.retryEscapeHandler) {
|
|
52
62
|
this.ctx.editor.onEscape = this.ctx.retryEscapeHandler;
|
|
53
63
|
this.ctx.retryEscapeHandler = undefined;
|
|
@@ -155,6 +165,15 @@ export class EventController {
|
|
|
155
165
|
}
|
|
156
166
|
}
|
|
157
167
|
}
|
|
168
|
+
|
|
169
|
+
// Update working message with intent from streamed tool arguments
|
|
170
|
+
for (const content of this.ctx.streamingMessage.content) {
|
|
171
|
+
if (content.type !== "toolCall") continue;
|
|
172
|
+
const args = content.arguments;
|
|
173
|
+
if (!args || typeof args !== "object" || !(INTENT_FIELD in args)) continue;
|
|
174
|
+
this.#updateWorkingMessageFromIntent(args[INTENT_FIELD] as string | undefined);
|
|
175
|
+
}
|
|
176
|
+
|
|
158
177
|
this.ctx.ui.requestRender();
|
|
159
178
|
}
|
|
160
179
|
break;
|
|
@@ -196,6 +215,7 @@ export class EventController {
|
|
|
196
215
|
break;
|
|
197
216
|
|
|
198
217
|
case "tool_execution_start": {
|
|
218
|
+
this.#updateWorkingMessageFromIntent(event.intent);
|
|
199
219
|
if (!this.ctx.pendingTools.has(event.toolCallId)) {
|
|
200
220
|
if (event.toolName === "read") {
|
|
201
221
|
const group = this.#getReadGroup();
|
|
@@ -200,7 +200,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
200
200
|
this.ui.requestRender(true);
|
|
201
201
|
};
|
|
202
202
|
this.editor.onAutocompleteUpdate = () => {
|
|
203
|
-
this.ui.requestRender(
|
|
203
|
+
this.ui.requestRender();
|
|
204
204
|
};
|
|
205
205
|
this.#syncEditorMaxHeight();
|
|
206
206
|
this.#resizeHandler = () => {
|