@oh-my-pi/pi-coding-agent 13.3.6 → 13.3.8
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 +115 -0
- package/package.json +9 -18
- package/scripts/format-prompts.ts +7 -172
- package/src/capability/mcp.ts +5 -0
- package/src/cli/args.ts +1 -0
- package/src/config/prompt-templates.ts +9 -55
- package/src/config/settings-schema.ts +24 -0
- package/src/discovery/builtin.ts +1 -0
- package/src/discovery/codex.ts +1 -2
- package/src/discovery/helpers.ts +0 -5
- package/src/discovery/mcp-json.ts +2 -0
- package/src/internal-urls/docs-index.generated.ts +1 -1
- package/src/lsp/client.ts +8 -0
- package/src/lsp/config.ts +2 -3
- package/src/lsp/index.ts +379 -99
- package/src/lsp/render.ts +21 -31
- package/src/lsp/types.ts +21 -8
- package/src/lsp/utils.ts +193 -1
- package/src/mcp/config-writer.ts +3 -0
- package/src/mcp/config.ts +1 -0
- package/src/mcp/oauth-flow.ts +3 -1
- package/src/mcp/types.ts +5 -0
- package/src/modes/components/settings-defs.ts +9 -0
- package/src/modes/components/status-line.ts +1 -1
- package/src/modes/controllers/mcp-command-controller.ts +6 -2
- package/src/modes/interactive-mode.ts +8 -1
- package/src/modes/theme/mermaid-cache.ts +4 -4
- package/src/modes/theme/theme.ts +33 -0
- package/src/prompts/system/custom-system-prompt.md +0 -10
- package/src/prompts/system/subagent-user-prompt.md +2 -0
- package/src/prompts/system/system-prompt.md +12 -9
- package/src/prompts/tools/ast-find.md +20 -0
- package/src/prompts/tools/ast-replace.md +21 -0
- package/src/prompts/tools/bash.md +2 -0
- package/src/prompts/tools/hashline.md +26 -8
- package/src/prompts/tools/lsp.md +22 -5
- package/src/prompts/tools/task.md +0 -1
- package/src/sdk.ts +11 -5
- package/src/session/agent-session.ts +293 -83
- package/src/system-prompt.ts +3 -34
- package/src/task/executor.ts +8 -7
- package/src/task/index.ts +8 -55
- package/src/task/template.ts +2 -4
- package/src/task/types.ts +0 -5
- package/src/task/worktree.ts +6 -2
- package/src/tools/ast-find.ts +316 -0
- package/src/tools/ast-replace.ts +294 -0
- package/src/tools/bash.ts +2 -1
- package/src/tools/browser.ts +2 -8
- package/src/tools/fetch.ts +55 -18
- package/src/tools/index.ts +8 -0
- package/src/tools/jtd-to-json-schema.ts +29 -13
- package/src/tools/path-utils.ts +34 -0
- package/src/tools/python.ts +2 -1
- package/src/tools/renderers.ts +4 -0
- package/src/tools/ssh.ts +2 -1
- package/src/tools/submit-result.ts +143 -44
- package/src/tools/todo-write.ts +34 -0
- package/src/tools/tool-timeouts.ts +29 -0
- package/src/utils/mime.ts +37 -14
- package/src/utils/prompt-format.ts +172 -0
- package/src/web/scrapers/arxiv.ts +12 -12
- package/src/web/scrapers/go-pkg.ts +2 -2
- package/src/web/scrapers/iacr.ts +17 -9
- package/src/web/scrapers/readthedocs.ts +3 -3
- package/src/web/scrapers/twitter.ts +11 -11
- package/src/web/scrapers/wikipedia.ts +4 -5
- package/src/utils/ignore-files.ts +0 -119
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,121 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [13.3.8] - 2026-02-28
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `ast_find` tool for structural code search using AST matching via ast-grep, enabling syntax-aware pattern discovery across codebases
|
|
10
|
+
- Added `ast_replace` tool for structural AST-aware rewrites via ast-grep, enabling safe syntax-level codemods without text-based fragility
|
|
11
|
+
- Added `astFind.enabled` and `astReplace.enabled` settings to control availability of AST tools
|
|
12
|
+
- Added system prompt guidance to prefer AST tools over bash text manipulation (grep/sed/awk/perl) for syntax-aware operations
|
|
13
|
+
- Extracted prompt formatting logic into reusable `formatPromptContent()` utility with configurable render phases and formatting options
|
|
14
|
+
- Added `type_definition` action to navigate to symbol type definitions with source context
|
|
15
|
+
- Added `implementation` action to find concrete implementations of symbols with source context
|
|
16
|
+
- Added `code_actions` action to list and apply language server code fixes, refactors, and import suggestions
|
|
17
|
+
- Added `symbol` parameter to automatically resolve column position by searching for substring on target line
|
|
18
|
+
- Added `occurrence` parameter to disambiguate repeated `symbol` matches on the same line
|
|
19
|
+
- Added source code context display (3 lines) for definition, type definition, and implementation results
|
|
20
|
+
- Added context display for first 50 references with remaining references shown location-only to balance detail and performance
|
|
21
|
+
- Added support for glob patterns in `file` parameter for diagnostics action (e.g., `src/**/*.ts`)
|
|
22
|
+
- Added `waitForIdle()` method to ensure prompt completion waits for all deferred recovery work (TTSR continuations, context promotions, compaction retries) to fully settle
|
|
23
|
+
- Added `getLastAssistantMessage()` method to retrieve the most recent assistant message from session state without manual array indexing
|
|
24
|
+
- Implemented TTSR resume gate to ensure `prompt()` blocks until TTSR interrupt continuations complete, preventing race conditions between TTSR injections and subsequent prompts
|
|
25
|
+
- Added `tools.maxTimeout` setting to enforce a global timeout ceiling across all tool calls
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- Replaced `globSync` from `glob` package with native `Bun.Glob` API for glob pattern matching
|
|
30
|
+
- Replaced `fileTypeFromBuffer` from `file-type` package with inline MIME type detection for JPEG, PNG, GIF, and WebP formats
|
|
31
|
+
- Reduced MIME type sniffing buffer size from 4100 bytes to 12 bytes for improved performance
|
|
32
|
+
- Changed mermaid cache key type from `string` to `bigint` for more efficient hashing
|
|
33
|
+
- Replaced `smol-toml` dependency with native `Bun.TOML.parse()` for TOML parsing, reducing external dependencies
|
|
34
|
+
- Replaced `node-html-parser` dependency with `linkedom` for HTML parsing, improving performance and reducing bundle size
|
|
35
|
+
- Updated HTML parsing API calls from `node-html-parser` to `linkedom` across all web scrapers (arXiv, IACR, Go pkg, Read the Docs, Twitter, Wikipedia)
|
|
36
|
+
- Changed element text extraction from `.text` property to `.textContent` property for compatibility with linkedom DOM API
|
|
37
|
+
- Optimized document link extraction to use regex-based parsing with deduplication and a 20-link limit instead of full DOM traversal
|
|
38
|
+
- Unified `path` parameter in ast_find and ast_replace tools to accept files, directories, or glob patterns directly, eliminating the separate `glob` parameter
|
|
39
|
+
- Removed `strictness` parameter from ast_find and ast_replace tools
|
|
40
|
+
- Removed `fail_on_parse_error` parameter from ast_replace tool (now always false)
|
|
41
|
+
- Updated ast_find and ast_replace prompt guidance to clarify that `path` accepts glob patterns and no longer requires separate glob specification
|
|
42
|
+
- Refactored prompt template rendering to use unified `formatPromptContent()` function with phase-aware formatting (pre-render vs post-render)
|
|
43
|
+
- Updated `format-prompts.ts` script to use centralized prompt formatting utility instead of inline implementation
|
|
44
|
+
- Replaced `column` parameter with `symbol` parameter for more intuitive position specification
|
|
45
|
+
- Removed `files` parameter; use glob patterns in `file` parameter instead
|
|
46
|
+
- Removed `end_line` and `end_character` parameters; range operations now use single position
|
|
47
|
+
- Changed `include_declaration` parameter to always be true for references (removed from API)
|
|
48
|
+
- Updated LSP client capabilities to advertise support for `typeDefinition` and `implementation` requests
|
|
49
|
+
- Improved definition results to include source context alongside location information
|
|
50
|
+
- Refactored deferred continuation scheduling to use centralized post-prompt task tracking instead of raw `setTimeout()` calls, improving reliability of concurrent recovery operations
|
|
51
|
+
- Updated subagent executor to explicitly await `waitForIdle()` after each prompt and reminder, ensuring terminal assistant state is determined only after all background work completes
|
|
52
|
+
- Replaced `#waitForRetry()` with `#waitForPostPromptRecovery()` to handle both retry and TTSR resume gates, ensuring prompt completion waits for all post-prompt recovery operations
|
|
53
|
+
- Introduced structured post-prompt recovery task tracking in `AgentSession` and added explicit session completion APIs (`waitForIdle()`, `getLastAssistantMessage()`) for callers that need deterministic turn finalization
|
|
54
|
+
- Updated intent field parameter name from `agent__intent` to `_i` for cleaner tool call contracts
|
|
55
|
+
- Refined intent parameter guidance to require concise 2-6 word sentences in present participle form
|
|
56
|
+
- Centralized per-tool timeout constants and clamping into `tool-timeouts.ts`
|
|
57
|
+
|
|
58
|
+
### Removed
|
|
59
|
+
|
|
60
|
+
- Removed `file-type` dependency, reducing external dependencies
|
|
61
|
+
- Removed `glob` dependency in favor of native `Bun.Glob` API
|
|
62
|
+
- Removed `ignore` dependency and ignore file handling utilities
|
|
63
|
+
- Removed `marked` dependency
|
|
64
|
+
- Removed `zod` dependency
|
|
65
|
+
- Removed `ms` and `@types/ms` dev dependencies
|
|
66
|
+
- Removed `rootDir` and `ignoreMatcher` parameters from `loadFilesFromDir()` (kept for API compatibility)
|
|
67
|
+
- Removed `smol-toml` dependency from package.json
|
|
68
|
+
- Removed `node-html-parser` dependency from package.json
|
|
69
|
+
- Removed `files` array parameter for batch file operations
|
|
70
|
+
- Removed `column`, `end_line`, and `end_character` parameters in favor of symbol-based positioning
|
|
71
|
+
- Removed `include_declaration` parameter from references action
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- Fixed TTSR violations during subagent execution aborting the entire subagent run; `#waitForPostPromptRecovery()` now also awaits agent idle after TTSR/retry gates resolve, preventing `prompt()` from returning while a fire-and-forget `agent.continue()` is still streaming
|
|
76
|
+
- Fixed deferred TTSR/context-promotion continuations still racing `prompt()` completion by tracking compaction checks and deferred `agent.continue()` tasks under a shared post-prompt recovery orchestrator
|
|
77
|
+
- Fixed subagent reminder/finalization sequencing to await session-level idle recovery between prompts before determining terminal assistant stop state
|
|
78
|
+
- Fixed `code_actions` apply mode to execute command-based actions via `workspace/executeCommand`
|
|
79
|
+
- Fixed diagnostics glob detection to recognize bracket character class patterns (e.g., `src/[ab].ts`)
|
|
80
|
+
- Fixed LSP render metadata sanitization for `symbol` values to prevent tab/newline layout breakage
|
|
81
|
+
- Fixed LSP diagnostics glob requests that appeared stuck by capping glob expansion and shortening per-file diagnostic waits in batch mode
|
|
82
|
+
- Fixed workspace symbol search to query all configured LSP servers and filter out non-matching results
|
|
83
|
+
- Fixed `references`/`rename`/`hover` symbol targeting to error when `symbol` is missing on the line or `occurrence` is out of bounds
|
|
84
|
+
- Fixed `reload` without a file to reload all active configured language servers instead of only the first server
|
|
85
|
+
- Fixed `todo_write` task normalization to auto-activate the first remaining task and include explicit remaining-items output in tool results, removing the need for an immediate follow-up start update
|
|
86
|
+
|
|
87
|
+
## [13.3.7] - 2026-02-27
|
|
88
|
+
### Breaking Changes
|
|
89
|
+
|
|
90
|
+
- Removed `preloadedSkills` option from `CreateAgentSessionOptions`; skills are no longer inlined into system prompts
|
|
91
|
+
- Removed `skills` field from Task schema; subagents now always inherit the session skill set instead of per-task skill selection
|
|
92
|
+
- Removed Task tool per-task `tasks[].skills` support; subagents now always inherit the session skill set
|
|
93
|
+
- Removed `preloadedSkills` system prompt plumbing and template sections; skills are no longer inlined as a separate preloaded block
|
|
94
|
+
|
|
95
|
+
### Changed
|
|
96
|
+
|
|
97
|
+
- Refactored schema reference resolution to inline all `$ref` definitions instead of preserving them at the root level, eliminating unresolved references in tool parameters
|
|
98
|
+
- Added `lenientArgValidation` flag to SubmitResultTool to allow the agent loop to bypass strict argument validation errors
|
|
99
|
+
- Modified schema validation to allow non-conforming output on second validation failure, enabling recovery from strict schema constraints after initial rejection
|
|
100
|
+
- Updated JTD-to-TypeScript conversion to gracefully fall back to 'unknown' type when conversion fails, preventing template rendering errors
|
|
101
|
+
- Changed JTD-to-JSON Schema conversion to normalize nested JTD fragments within JSON Schema nodes, enabling mixed schema definitions
|
|
102
|
+
- Changed output schema validation to gracefully fall back to unconstrained object when schema is invalid, instead of rejecting submissions
|
|
103
|
+
- Changed schema sanitization to remove strict-mode incompatible constraints (minLength, pattern, etc.) from tool parameters while preserving them for runtime validation
|
|
104
|
+
- Simplified task execution to always pass available session skills to subagents instead of resolving per-task skill lists
|
|
105
|
+
- Added `KILO_API_KEY` to CLI environment variable help text for Kilo Gateway provider setup ([#193](https://github.com/can1357/oh-my-pi/issues/193))
|
|
106
|
+
|
|
107
|
+
### Removed
|
|
108
|
+
|
|
109
|
+
- Removed preloaded skills section from system prompt templates; skills are now referenced only as available resources
|
|
110
|
+
|
|
111
|
+
### Fixed
|
|
112
|
+
|
|
113
|
+
- Fixed schema compilation validation by adding explicit AJV compilation check to catch unresolved `$ref` references and other schema errors before tool execution
|
|
114
|
+
- Fixed handling of circular and deeply nested output schemas to prevent stack overflow and enable successful result submission with fallback unconstrained schema
|
|
115
|
+
- Fixed processing of non-object output schemas (arrays, primitives, booleans) to accept valid result submissions without blocking
|
|
116
|
+
- Fixed handling of mixed JTD and JSON Schema output definitions to properly convert all nested JTD elements (e.g., `elements` → `items`, `int32` → `integer`)
|
|
117
|
+
- Fixed strict schema generation for output schemas with only required fields, enabling proper Claude API compatibility
|
|
118
|
+
- Fixed handling of union type schemas (e.g., object|null) to normalize them into strict-mode compatible variants
|
|
119
|
+
|
|
5
120
|
## [13.3.6] - 2026-02-26
|
|
6
121
|
### Breaking Changes
|
|
7
122
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "13.3.
|
|
4
|
+
"version": "13.3.8",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/can1357/oh-my-pi",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -41,32 +41,23 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@mozilla/readability": "^0.6",
|
|
44
|
-
"@oh-my-pi/omp-stats": "13.3.
|
|
45
|
-
"@oh-my-pi/pi-agent-core": "13.3.
|
|
46
|
-
"@oh-my-pi/pi-ai": "13.3.
|
|
47
|
-
"@oh-my-pi/pi-natives": "13.3.
|
|
48
|
-
"@oh-my-pi/pi-tui": "13.3.
|
|
49
|
-
"@oh-my-pi/pi-utils": "13.3.
|
|
44
|
+
"@oh-my-pi/omp-stats": "13.3.8",
|
|
45
|
+
"@oh-my-pi/pi-agent-core": "13.3.8",
|
|
46
|
+
"@oh-my-pi/pi-ai": "13.3.8",
|
|
47
|
+
"@oh-my-pi/pi-natives": "13.3.8",
|
|
48
|
+
"@oh-my-pi/pi-tui": "13.3.8",
|
|
49
|
+
"@oh-my-pi/pi-utils": "13.3.8",
|
|
50
50
|
"@sinclair/typebox": "^0.34",
|
|
51
51
|
"@xterm/headless": "^6.0",
|
|
52
52
|
"ajv": "^8.18",
|
|
53
53
|
"chalk": "^5.6",
|
|
54
54
|
"diff": "^8.0",
|
|
55
|
-
"file-type": "^21.3",
|
|
56
|
-
"glob": "^13.0",
|
|
57
55
|
"handlebars": "^4.7",
|
|
58
|
-
"ignore": "^7.0",
|
|
59
56
|
"linkedom": "^0.18",
|
|
60
|
-
"
|
|
61
|
-
"node-html-parser": "^7.0",
|
|
62
|
-
"puppeteer": "^24.37",
|
|
63
|
-
"smol-toml": "^1.6",
|
|
64
|
-
"zod": "^4.3"
|
|
57
|
+
"puppeteer": "^24.37"
|
|
65
58
|
},
|
|
66
59
|
"devDependencies": {
|
|
67
|
-
"@types/bun": "^1.3"
|
|
68
|
-
"@types/ms": "^2.1",
|
|
69
|
-
"ms": "^2.1"
|
|
60
|
+
"@types/bun": "^1.3"
|
|
70
61
|
},
|
|
71
62
|
"engines": {
|
|
72
63
|
"bun": ">=1.3.7"
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* 9. Bold RFC 2119 keywords (MUST, SHOULD, MAY, etc.) in prompt content
|
|
15
15
|
*/
|
|
16
16
|
import { Glob } from "bun";
|
|
17
|
+
import { formatPromptContent } from "../src/utils/prompt-format";
|
|
17
18
|
|
|
18
19
|
const PROMPTS_DIR = new URL("../src/prompts/", import.meta.url).pathname;
|
|
19
20
|
const COMMIT_PROMPTS_DIR = new URL("../src/commit/prompts/", import.meta.url).pathname;
|
|
@@ -21,177 +22,11 @@ const AGENTIC_PROMPTS_DIR = new URL("../src/commit/agentic/prompts/", import.met
|
|
|
21
22
|
|
|
22
23
|
const PROMPT_DIRS = [PROMPTS_DIR, COMMIT_PROMPTS_DIR, AGENTIC_PROMPTS_DIR];
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const OPENING_HBS = /^\{\{#/;
|
|
30
|
-
// Handlebars block end: {{/if}}, {{/has}}, {{/list}}, etc.
|
|
31
|
-
const CLOSING_HBS = /^\{\{\//;
|
|
32
|
-
// List item (- or * or 1.)
|
|
33
|
-
const LIST_ITEM = /^[-*]|\d+\.\s/;
|
|
34
|
-
// Code fence
|
|
35
|
-
const CODE_FENCE = /^```/;
|
|
36
|
-
// Table row
|
|
37
|
-
const TABLE_ROW = /^\|.*\|$/;
|
|
38
|
-
// Table separator (|---|---|)
|
|
39
|
-
const TABLE_SEP = /^\|[-:\s|]+\|$/;
|
|
40
|
-
|
|
41
|
-
/** RFC 2119 keywords used in prompts. */
|
|
42
|
-
const RFC2119_KEYWORDS = /\b(?:MUST NOT|SHOULD NOT|SHALL NOT|RECOMMENDED|REQUIRED|OPTIONAL|SHOULD|SHALL|MUST|MAY)\b/g;
|
|
43
|
-
|
|
44
|
-
function boldRfc2119Keywords(line: string): string {
|
|
45
|
-
return line.replace(RFC2119_KEYWORDS, (match, offset, source) => {
|
|
46
|
-
const isAlreadyBold =
|
|
47
|
-
source[offset - 2] === "*" &&
|
|
48
|
-
source[offset - 1] === "*" &&
|
|
49
|
-
source[offset + match.length] === "*" &&
|
|
50
|
-
source[offset + match.length + 1] === "*";
|
|
51
|
-
if (isAlreadyBold) {
|
|
52
|
-
return match;
|
|
53
|
-
}
|
|
54
|
-
return `**${match}**`;
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Compact a table row by trimming cell padding */
|
|
59
|
-
function compactTableRow(line: string): string {
|
|
60
|
-
// Split by |, trim each cell, rejoin
|
|
61
|
-
const cells = line.split("|");
|
|
62
|
-
return cells.map((c) => c.trim()).join("|");
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Compact a table separator row */
|
|
66
|
-
function compactTableSep(line: string): string {
|
|
67
|
-
// Normalize to minimal |---|---|
|
|
68
|
-
const cells = line.split("|").filter((c) => c.trim());
|
|
69
|
-
const normalized = cells.map((c) => {
|
|
70
|
-
const trimmed = c.trim();
|
|
71
|
-
// Preserve alignment markers
|
|
72
|
-
const left = trimmed.startsWith(":");
|
|
73
|
-
const right = trimmed.endsWith(":");
|
|
74
|
-
if (left && right) return ":---:";
|
|
75
|
-
if (left) return ":---";
|
|
76
|
-
if (right) return "---:";
|
|
77
|
-
return "---";
|
|
78
|
-
});
|
|
79
|
-
return "|" + normalized.join("|") + "|";
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function formatPrompt(content: string): string {
|
|
83
|
-
const lines = content.split("\n");
|
|
84
|
-
const result: string[] = [];
|
|
85
|
-
let inCodeBlock = false;
|
|
86
|
-
// Stack of tag names whose opening tag was at column 0 (top-level)
|
|
87
|
-
const topLevelTags: string[] = [];
|
|
88
|
-
|
|
89
|
-
for (let i = 0; i < lines.length; i++) {
|
|
90
|
-
let line = lines[i].trimEnd();
|
|
91
|
-
|
|
92
|
-
const trimmed = line.trimStart();
|
|
93
|
-
|
|
94
|
-
// Track code blocks - don't modify inside them
|
|
95
|
-
if (CODE_FENCE.test(trimmed)) {
|
|
96
|
-
inCodeBlock = !inCodeBlock;
|
|
97
|
-
result.push(line);
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (inCodeBlock) {
|
|
102
|
-
result.push(line);
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Replace common ascii ellipsis and arrow patterns with their unicode equivalents
|
|
107
|
-
line = line
|
|
108
|
-
.replace(/\.{3}/g, "…")
|
|
109
|
-
.replace(/->/g, "→")
|
|
110
|
-
.replace(/<-/g, "←")
|
|
111
|
-
.replace(/<->/g, "↔")
|
|
112
|
-
.replace(/!=/g, "≠")
|
|
113
|
-
.replace(/<=/g, "≤")
|
|
114
|
-
.replace(/>=/g, "≥");
|
|
115
|
-
|
|
116
|
-
// Track top-level XML opening tags for depth-aware indent stripping
|
|
117
|
-
const isOpeningXml = OPENING_XML.test(trimmed) && !trimmed.endsWith("/>");
|
|
118
|
-
if (isOpeningXml && line.length === trimmed.length) {
|
|
119
|
-
// Opening tag at column 0 — track as top-level
|
|
120
|
-
const match = OPENING_XML.exec(trimmed);
|
|
121
|
-
if (match) topLevelTags.push(match[1]);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Strip leading whitespace from top-level closing XML tags and Handlebars
|
|
125
|
-
const closingMatch = CLOSING_XML.exec(trimmed);
|
|
126
|
-
if (closingMatch) {
|
|
127
|
-
const tagName = closingMatch[1];
|
|
128
|
-
if (topLevelTags.length > 0 && topLevelTags[topLevelTags.length - 1] === tagName) {
|
|
129
|
-
// Closing tag matches a top-level opener — strip indent
|
|
130
|
-
line = trimmed;
|
|
131
|
-
topLevelTags.pop();
|
|
132
|
-
} else {
|
|
133
|
-
line = line.trimEnd();
|
|
134
|
-
}
|
|
135
|
-
} else if (trimmed.startsWith("{{")) {
|
|
136
|
-
line = trimmed;
|
|
137
|
-
} else if (TABLE_SEP.test(trimmed)) {
|
|
138
|
-
// Compact table separator
|
|
139
|
-
line = compactTableSep(trimmed);
|
|
140
|
-
} else if (TABLE_ROW.test(trimmed)) {
|
|
141
|
-
// Compact table row
|
|
142
|
-
line = compactTableRow(trimmed);
|
|
143
|
-
} else {
|
|
144
|
-
// Trim trailing whitespace (preserve leading for non-closing-tags)
|
|
145
|
-
line = line.trimEnd();
|
|
146
|
-
}
|
|
147
|
-
line = boldRfc2119Keywords(line);
|
|
148
|
-
|
|
149
|
-
const isBlank = trimmed === "";
|
|
150
|
-
|
|
151
|
-
// Skip blank lines that violate our rules
|
|
152
|
-
if (isBlank) {
|
|
153
|
-
const prevLine = result[result.length - 1]?.trim() ?? "";
|
|
154
|
-
const nextLine = lines[i + 1]?.trim() ?? "";
|
|
155
|
-
|
|
156
|
-
// Rule 1: No blank line before list items
|
|
157
|
-
if (LIST_ITEM.test(nextLine)) {
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Rule 2: No blank after opening XML tag or Handlebars block
|
|
162
|
-
if (OPENING_XML.test(prevLine) || OPENING_HBS.test(prevLine)) {
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Rule 3: No blank before closing XML tag or Handlebars block
|
|
167
|
-
if (CLOSING_XML.test(nextLine) || CLOSING_HBS.test(nextLine)) {
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Rule 4: Collapse multiple blank lines
|
|
172
|
-
const prevIsBlank = prevLine === "";
|
|
173
|
-
if (prevIsBlank) {
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Rule 3 (cleanup): Remove trailing blanks before closing tag
|
|
179
|
-
if (CLOSING_XML.test(trimmed) || CLOSING_HBS.test(trimmed)) {
|
|
180
|
-
while (result.length > 0 && result[result.length - 1].trim() === "") {
|
|
181
|
-
result.pop();
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
result.push(line);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Rule 8: No trailing newline at EOF
|
|
189
|
-
while (result.length > 0 && result[result.length - 1].trim() === "") {
|
|
190
|
-
result.pop();
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return result.join("\n");
|
|
194
|
-
}
|
|
25
|
+
const PROMPT_FORMAT_OPTIONS = {
|
|
26
|
+
renderPhase: "pre-render",
|
|
27
|
+
replaceAsciiSymbols: true,
|
|
28
|
+
boldRfc2119Keywords: true,
|
|
29
|
+
} as const;
|
|
195
30
|
|
|
196
31
|
async function main() {
|
|
197
32
|
const glob = new Glob("**/*.md");
|
|
@@ -207,7 +42,7 @@ async function main() {
|
|
|
207
42
|
|
|
208
43
|
for (const fullPath of files) {
|
|
209
44
|
const original = await Bun.file(fullPath).text();
|
|
210
|
-
const formatted =
|
|
45
|
+
const formatted = formatPromptContent(original, PROMPT_FORMAT_OPTIONS);
|
|
211
46
|
|
|
212
47
|
if (original !== formatted) {
|
|
213
48
|
if (check) {
|
package/src/capability/mcp.ts
CHANGED
|
@@ -32,6 +32,11 @@ export interface MCPServer {
|
|
|
32
32
|
type: "oauth" | "apikey";
|
|
33
33
|
credentialId?: string;
|
|
34
34
|
};
|
|
35
|
+
/** OAuth configuration (clientId, callbackPort) for servers requiring explicit client credentials */
|
|
36
|
+
oauth?: {
|
|
37
|
+
clientId?: string;
|
|
38
|
+
callbackPort?: number;
|
|
39
|
+
};
|
|
35
40
|
/** Transport type */
|
|
36
41
|
transport?: "stdio" | "sse" | "http";
|
|
37
42
|
/** Source metadata (added by loader) */
|
package/src/cli/args.ts
CHANGED
|
@@ -201,6 +201,7 @@ export function getExtraHelpText(): string {
|
|
|
201
201
|
CEREBRAS_API_KEY - Cerebras models
|
|
202
202
|
XAI_API_KEY - xAI Grok models
|
|
203
203
|
OPENROUTER_API_KEY - OpenRouter aggregated models
|
|
204
|
+
KILO_API_KEY - Kilo Gateway models
|
|
204
205
|
MISTRAL_API_KEY - Mistral models
|
|
205
206
|
ZAI_API_KEY - z.ai models (ZhipuAI/GLM)
|
|
206
207
|
MINIMAX_API_KEY - MiniMax models
|
|
@@ -6,6 +6,7 @@ import { computeLineHash } from "../patch/hashline";
|
|
|
6
6
|
import { jtdToTypeScript } from "../tools/jtd-to-typescript";
|
|
7
7
|
import { parseCommandArgs, substituteArgs } from "../utils/command-args";
|
|
8
8
|
import { parseFrontmatter } from "../utils/frontmatter";
|
|
9
|
+
import { formatPromptContent } from "../utils/prompt-format";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Represents a prompt template loaded from a markdown file
|
|
@@ -225,7 +226,13 @@ handlebars.registerHelper("includes", (collection: unknown, item: unknown): bool
|
|
|
225
226
|
*/
|
|
226
227
|
handlebars.registerHelper("not", (value: unknown): boolean => !value);
|
|
227
228
|
|
|
228
|
-
handlebars.registerHelper("jtdToTypeScript", (schema: unknown): string =>
|
|
229
|
+
handlebars.registerHelper("jtdToTypeScript", (schema: unknown): string => {
|
|
230
|
+
try {
|
|
231
|
+
return jtdToTypeScript(schema);
|
|
232
|
+
} catch {
|
|
233
|
+
return "unknown";
|
|
234
|
+
}
|
|
235
|
+
});
|
|
229
236
|
|
|
230
237
|
handlebars.registerHelper("jsonStringify", (value: unknown): string => JSON.stringify(value));
|
|
231
238
|
|
|
@@ -270,60 +277,7 @@ handlebars.registerHelper("hlinefull", (lineNum: unknown, content: unknown): str
|
|
|
270
277
|
export function renderPromptTemplate(template: string, context: TemplateContext = {}): string {
|
|
271
278
|
const compiled = handlebars.compile(template, { noEscape: true, strict: false });
|
|
272
279
|
const rendered = compiled(context ?? {});
|
|
273
|
-
return
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function optimizePromptLayout(input: string): string {
|
|
277
|
-
// 1) strip CR / normalize line endings
|
|
278
|
-
let s = input.replace(/\r\n?/g, "\n");
|
|
279
|
-
|
|
280
|
-
// normalize NBSP -> space
|
|
281
|
-
s = s.replace(/\u00A0/g, " ");
|
|
282
|
-
|
|
283
|
-
const lines = s.split("\n").map(line => {
|
|
284
|
-
// 2) remove trailing whitespace (spaces/tabs) per line
|
|
285
|
-
let l = line.replace(/[ \t]+$/g, "");
|
|
286
|
-
|
|
287
|
-
// 3) lines with only whitespace -> empty line
|
|
288
|
-
if (/^[ \t]*$/.test(l)) return "";
|
|
289
|
-
|
|
290
|
-
// 4) normalize leading indentation: every 2 spaces -> \t (preserve leftover 1 space)
|
|
291
|
-
// NOTE: This is intentionally *only* leading indentation to avoid mangling prose.
|
|
292
|
-
const m = l.match(/^[ \t]+/);
|
|
293
|
-
if (m) {
|
|
294
|
-
const indent = m[0];
|
|
295
|
-
const rest = l.slice(indent.length);
|
|
296
|
-
|
|
297
|
-
let out = "";
|
|
298
|
-
let spaces = 0;
|
|
299
|
-
|
|
300
|
-
for (const ch of indent) {
|
|
301
|
-
if (ch === "\t") {
|
|
302
|
-
// flush pending spaces before existing tab
|
|
303
|
-
out += "\t".repeat(Math.floor(spaces / 2));
|
|
304
|
-
if (spaces % 2) out += " ";
|
|
305
|
-
spaces = 0;
|
|
306
|
-
out += "\t";
|
|
307
|
-
} else {
|
|
308
|
-
spaces++;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
out += "\t".repeat(Math.floor(spaces / 2));
|
|
313
|
-
if (spaces % 2) out += " ";
|
|
314
|
-
|
|
315
|
-
l = out + rest;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
return l;
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
s = lines.join("\n");
|
|
322
|
-
|
|
323
|
-
// 5) collapse excessive blank lines
|
|
324
|
-
s = s.replace(/\n{3,}/g, "\n\n");
|
|
325
|
-
|
|
326
|
-
return s.trim();
|
|
280
|
+
return formatPromptContent(rendered, { renderPhase: "post-render" });
|
|
327
281
|
}
|
|
328
282
|
|
|
329
283
|
/**
|
|
@@ -455,6 +455,20 @@ export const SETTINGS_SCHEMA = {
|
|
|
455
455
|
submenu: true,
|
|
456
456
|
},
|
|
457
457
|
},
|
|
458
|
+
"astFind.enabled": {
|
|
459
|
+
type: "boolean",
|
|
460
|
+
default: true,
|
|
461
|
+
ui: { tab: "tools", label: "Enable AST Find", description: "Enable the ast_find tool for structural AST search" },
|
|
462
|
+
},
|
|
463
|
+
"astReplace.enabled": {
|
|
464
|
+
type: "boolean",
|
|
465
|
+
default: true,
|
|
466
|
+
ui: {
|
|
467
|
+
tab: "tools",
|
|
468
|
+
label: "Enable AST Replace",
|
|
469
|
+
description: "Enable the ast_replace tool for structural AST rewrites",
|
|
470
|
+
},
|
|
471
|
+
},
|
|
458
472
|
"notebook.enabled": {
|
|
459
473
|
type: "boolean",
|
|
460
474
|
default: true,
|
|
@@ -511,6 +525,16 @@ export const SETTINGS_SCHEMA = {
|
|
|
511
525
|
description: "Ask the agent to describe the intent of each tool call before executing it",
|
|
512
526
|
},
|
|
513
527
|
},
|
|
528
|
+
"tools.maxTimeout": {
|
|
529
|
+
type: "number",
|
|
530
|
+
default: 0,
|
|
531
|
+
ui: {
|
|
532
|
+
tab: "tools",
|
|
533
|
+
label: "Max tool timeout",
|
|
534
|
+
description: "Maximum timeout in seconds the agent can set for any tool (0 = no limit)",
|
|
535
|
+
submenu: true,
|
|
536
|
+
},
|
|
537
|
+
},
|
|
514
538
|
"async.enabled": {
|
|
515
539
|
type: "boolean",
|
|
516
540
|
default: false,
|
package/src/discovery/builtin.ts
CHANGED
|
@@ -157,6 +157,7 @@ async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>>
|
|
|
157
157
|
url: serverConfig.url as string | undefined,
|
|
158
158
|
headers: serverConfig.headers as Record<string, string> | undefined,
|
|
159
159
|
auth: serverConfig.auth as { type: "oauth" | "apikey"; credentialId?: string } | undefined,
|
|
160
|
+
oauth: serverConfig.oauth as { clientId?: string; callbackPort?: number } | undefined,
|
|
160
161
|
transport: serverConfig.type as "stdio" | "sse" | "http" | undefined,
|
|
161
162
|
_source: createSourceMeta(PROVIDER_ID, path, level),
|
|
162
163
|
});
|
package/src/discovery/codex.ts
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import * as path from "node:path";
|
|
10
10
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
11
|
-
import { parse as parseToml } from "smol-toml";
|
|
12
11
|
import { registerProvider } from "../capability";
|
|
13
12
|
import type { ContextFile } from "../capability/context-file";
|
|
14
13
|
import { contextFileCapability } from "../capability/context-file";
|
|
@@ -116,7 +115,7 @@ async function loadTomlConfig(_ctx: LoadContext, path: string): Promise<Record<s
|
|
|
116
115
|
if (!content) return null;
|
|
117
116
|
|
|
118
117
|
try {
|
|
119
|
-
return
|
|
118
|
+
return Bun.TOML.parse(content) as Record<string, unknown>;
|
|
120
119
|
} catch (error) {
|
|
121
120
|
logger.warn("Failed to parse TOML config", { path, error: String(error) });
|
|
122
121
|
return null;
|
package/src/discovery/helpers.ts
CHANGED
|
@@ -8,7 +8,6 @@ import { parseRuleConditionAndScope, type Rule, type RuleFrontmatter } from "../
|
|
|
8
8
|
import type { Skill, SkillFrontmatter } from "../capability/skill";
|
|
9
9
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
|
|
10
10
|
import { parseFrontmatter } from "../utils/frontmatter";
|
|
11
|
-
import type { IgnoreMatcher } from "../utils/ignore-files";
|
|
12
11
|
|
|
13
12
|
const VALID_THINKING_LEVELS: readonly string[] = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
14
13
|
|
|
@@ -378,10 +377,6 @@ export async function loadFilesFromDir<T>(
|
|
|
378
377
|
transform: (name: string, content: string, path: string, source: SourceMeta) => T | null;
|
|
379
378
|
/** Whether to recurse into subdirectories (default: false) */
|
|
380
379
|
recursive?: boolean;
|
|
381
|
-
/** Root directory for ignore file handling (unused, kept for API compat) */
|
|
382
|
-
rootDir?: string;
|
|
383
|
-
/** Ignore matcher (unused, kept for API compat) */
|
|
384
|
-
ignoreMatcher?: IgnoreMatcher;
|
|
385
380
|
},
|
|
386
381
|
): Promise<LoadResult<T>> {
|
|
387
382
|
const items: T[] = [];
|
|
@@ -36,6 +36,7 @@ interface MCPConfigFile {
|
|
|
36
36
|
credentialId?: string;
|
|
37
37
|
};
|
|
38
38
|
type?: "stdio" | "sse" | "http";
|
|
39
|
+
oauth?: { clientId?: string; callbackPort?: number };
|
|
39
40
|
}
|
|
40
41
|
>;
|
|
41
42
|
}
|
|
@@ -81,6 +82,7 @@ function transformMCPConfig(config: MCPConfigFile, source: SourceMeta): MCPServe
|
|
|
81
82
|
url: serverConfig.url,
|
|
82
83
|
headers: serverConfig.headers,
|
|
83
84
|
auth: serverConfig.auth,
|
|
85
|
+
oauth: serverConfig.oauth,
|
|
84
86
|
transport: serverConfig.type,
|
|
85
87
|
_source: source,
|
|
86
88
|
};
|