@oh-my-pi/pi-coding-agent 12.12.3 → 12.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +92 -0
- package/package.json +8 -7
- package/scripts/generate-docs-index.ts +56 -0
- package/src/cli/ssh-cli.ts +179 -0
- package/src/cli.ts +1 -0
- package/src/commands/ssh.ts +60 -0
- package/src/commit/prompts/analysis-system.md +1 -3
- package/src/config/prompt-templates.ts +20 -5
- package/src/config/settings-schema.ts +10 -1
- package/src/discovery/builtin.ts +14 -4
- package/src/discovery/ssh.ts +26 -19
- 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/controllers/ssh-command-controller.ts +452 -0
- package/src/modes/interactive-mode.ts +6 -0
- package/src/modes/types.ts +1 -0
- package/src/patch/diff.ts +1 -1
- package/src/patch/hashline.ts +274 -303
- package/src/patch/index.ts +324 -103
- package/src/patch/shared.ts +25 -28
- package/src/prompts/system/system-prompt.md +14 -2
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/grep.md +12 -8
- package/src/prompts/tools/hashline.md +207 -60
- package/src/prompts/tools/read.md +3 -3
- package/src/sdk.ts +17 -0
- package/src/session/agent-session.ts +1 -0
- package/src/session/auth-storage.ts +6 -0
- package/src/slash-commands/builtin-registry.ts +20 -0
- package/src/ssh/config-writer.ts +183 -0
- package/src/tools/bash-interactive.ts +47 -7
- package/src/tools/fetch.ts +4 -3
- package/src/tools/grep.ts +14 -4
- package/src/tools/read.ts +2 -2
- package/src/tools/ssh.ts +1 -1
- package/src/web/search/render.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,74 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [12.14.0] - 2026-02-19
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Support for `docs://` internal URL protocol to access embedded documentation files (e.g., `docs://sdk.md`)
|
|
10
|
+
- Added `generate-docs-index` npm script to automatically index and embed documentation files at build time
|
|
11
|
+
- Support for executable tool files (.ts, .js, .sh, .bash, .py) in custom tools discovery alongside markdown files
|
|
12
|
+
- Display streamed tool intent in working message during agent execution
|
|
13
|
+
- Added `tools.intentTracing` setting to enable intent tracing, which asks the agent to describe the intent of each tool call before executing it
|
|
14
|
+
- Support for file deletion in hashline edit mode via `delete: true` parameter
|
|
15
|
+
- Support for file renaming/moving in hashline edit mode via `rename` parameter
|
|
16
|
+
- Optional content-replace edit variant in hashline mode (enabled via `PI_HL_REPLACETXT=1` environment variable)
|
|
17
|
+
- Support for grepping internal URLs (artifact://) by resolving them to their backing files
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- System prompt now identifies agent as operating inside Oh My Pi harness and instructs reading docs:// URLs for omp/pi topics
|
|
22
|
+
- Tool discovery now accepts executable script extensions (.ts, .js, .sh, .bash, .py) in addition to .json and .md files
|
|
23
|
+
- Updated bash and read tool documentation to reference `docs://` URL support
|
|
24
|
+
- Hashline format separator changed from pipe (`|`) to colon (`:`) for improved readability (e.g., `LINE#ID:content` instead of `LINE#ID|content`)
|
|
25
|
+
- Hashline hash representation changed from 4-character base36 to 2-character hexadecimal for more compact line references
|
|
26
|
+
- Hashline edit API: renamed `delete` parameter to `rm` for consistency with standard file operations
|
|
27
|
+
- Hashline edit API: renamed `rename` parameter to `mv` for consistency with standard file operations
|
|
28
|
+
- Hashline edit API: content-replace operations now require explicit `op: "replaceText"` field to distinguish from other edit types
|
|
29
|
+
- Hashline documentation terminology updated: references to 'anchors' replaced with 'tags' for clearer semantics
|
|
30
|
+
- Intent tracing now uses `_intent` field name in tool schemas
|
|
31
|
+
- Hashline edit API: renamed `set` operation to `target`/`new_content` for clearer semantics
|
|
32
|
+
- Hashline edit API: renamed `set_range` operation to `first`/`last`/`new_content`
|
|
33
|
+
- Hashline edit API: renamed `insert` operation fields from `body` to `inserted_lines` and made `inserted_lines` required non-empty
|
|
34
|
+
- Hashline edit API: flattened `replace` operation to top-level fields (`old_text`, `new_text`, `all`) when enabled
|
|
35
|
+
- Hashline edit validation now provides more specific error messages indicating which variant is expected
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Grep tool now properly handles internal URL resolution when searching artifact paths
|
|
40
|
+
- Working message intent updates now fall back to tool execution events when streamed tool arguments omit the intent field
|
|
41
|
+
|
|
42
|
+
## [12.13.0] - 2026-02-19
|
|
43
|
+
|
|
44
|
+
### Breaking Changes
|
|
45
|
+
|
|
46
|
+
- 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
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- Added `ssh` command for managing SSH host configurations (add, list, remove)
|
|
51
|
+
- Added `/ssh` slash command in interactive mode to manage SSH hosts with subcommands
|
|
52
|
+
- Added support for SSH host configuration at project and user scopes (.omp/ssh.json and ~/.omp/agent/ssh.json)
|
|
53
|
+
- Added `--host`, `--user`, `--port`, `--key`, `--desc`, `--compat`, and `--scope` flags for SSH host configuration
|
|
54
|
+
- Added discovery of SSH hosts from project configuration files alongside manually configured hosts
|
|
55
|
+
- Added NanoGPT as a login provider (`/login nanogpt`) with API key prompt flow linking to `https://nano-gpt.com/api` ([#111](https://github.com/can1357/oh-my-pi/issues/111))
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- Updated hashline reference format from `LINE:HASH` to `LINE#ID` throughout the codebase for improved clarity
|
|
60
|
+
- Renamed hashline edit operations: `set_line` → `set`, `replace_lines` → `set_range`, `insert_after` → `insert` with support for `before` and `between` anchors
|
|
61
|
+
- Changed hashline edit `body` field from string to array of strings for clearer multiline handling
|
|
62
|
+
- Updated handlebars helpers: renamed `hashline` to `hlineref` and added `hlinefull` for formatted line output
|
|
63
|
+
- Improved insert operation to support `before`, `after`, and `between` (both anchors) positioning modes
|
|
64
|
+
- Made autocorrect heuristics (boundary echo stripping, indent restoration) conditional on `PI_HL_AUTOCORRECT` environment variable
|
|
65
|
+
- Updated SSH host discovery to load from managed omp config paths (.omp/ssh.json and ~/.omp/agent/ssh.json) in addition to legacy root-level ssh.json and .ssh.json files
|
|
66
|
+
- Improved terminal output handling in interactive bash sessions to ensure all queued writes complete before returning results
|
|
67
|
+
|
|
68
|
+
### Fixed
|
|
69
|
+
|
|
70
|
+
- Fixed insert-between operation to properly validate adjacent anchor lines and strip boundary echoes from both sides
|
|
71
|
+
- Fixed terminal output handling to properly queue and serialize writes, preventing dropped or corrupted output in interactive bash sessions
|
|
72
|
+
|
|
5
73
|
## [12.12.1] - 2026-02-19
|
|
6
74
|
|
|
7
75
|
### Added
|
|
@@ -141,6 +209,7 @@
|
|
|
141
209
|
- 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
|
|
142
210
|
|
|
143
211
|
## [12.8.2] - 2026-02-17
|
|
212
|
+
|
|
144
213
|
### Changed
|
|
145
214
|
|
|
146
215
|
- Changed system environment context to use built-in `os` values for distro, kernel, and CPU model instead of native system-info data
|
|
@@ -153,11 +222,14 @@
|
|
|
153
222
|
## [12.8.0] - 2026-02-16
|
|
154
223
|
|
|
155
224
|
### Changed
|
|
225
|
+
|
|
156
226
|
- 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))
|
|
157
227
|
- Centralized builtin slash command definitions and handlers into a shared registry, replacing the large input-controller if-chain dispatch
|
|
158
228
|
|
|
159
229
|
## [12.7.0] - 2026-02-16
|
|
230
|
+
|
|
160
231
|
### Added
|
|
232
|
+
|
|
161
233
|
- Added abort signal support to LSP file operations (`ensureFileOpen`, `refreshFile`) for cancellable file synchronization
|
|
162
234
|
- Added abort signal propagation through LSP request handlers (definition, references, hover, symbols, rename) enabling operation cancellation
|
|
163
235
|
- Added `shouldBypassAutocompleteOnEscape` callback to custom editor for context-aware escape key handling during active operations
|
|
@@ -172,7 +244,9 @@
|
|
|
172
244
|
- 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
|
|
173
245
|
- Added `secrets.enabled` setting to toggle secret obfuscation
|
|
174
246
|
- Added full regex literal support for `secrets.json` entries (`"/pattern/flags"` syntax with escaped `/` handling, automatic `g` flag enforcement)
|
|
247
|
+
|
|
175
248
|
### Changed
|
|
249
|
+
|
|
176
250
|
- Changed context promotion to trigger on context overflow instead of a configurable threshold, promoting to a larger model before attempting compaction
|
|
177
251
|
- Changed context promotion behavior to retry immediately on the promoted model without compacting, providing faster recovery from context limits
|
|
178
252
|
- Changed default grep context lines from 1 before/3 after to 0 before/0 after for more focused search results
|
|
@@ -187,20 +261,25 @@
|
|
|
187
261
|
- Updated web search provider priority order to include Brave (Exa → Brave → Jina → Perplexity → Anthropic → Gemini → Codex → Z.AI)
|
|
188
262
|
- Extended recency filter support to Brave provider alongside Perplexity
|
|
189
263
|
- Changed GitHub issue comment fetching to use paginated API requests with 100 comments per page instead of single request with 50-comment limit
|
|
264
|
+
|
|
190
265
|
### Removed
|
|
191
266
|
|
|
192
267
|
- Removed `contextPromotion.thresholdPercent` setting as context promotion now triggers only on overflow
|
|
193
268
|
|
|
194
269
|
### Fixed
|
|
270
|
+
|
|
195
271
|
- Fixed LSP operations to properly respect abort signals and throw `ToolAbortError` when cancelled
|
|
196
272
|
- Fixed workspace diagnostics process cleanup to remove abort event listeners in finally block
|
|
197
273
|
- 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))
|
|
274
|
+
|
|
198
275
|
## [12.5.1] - 2026-02-15
|
|
276
|
+
|
|
199
277
|
### Added
|
|
200
278
|
|
|
201
279
|
- Added `repeatToolDescriptions` setting to render full tool descriptions in the system prompt instead of a tool name list
|
|
202
280
|
|
|
203
281
|
## [12.5.0] - 2026-02-15
|
|
282
|
+
|
|
204
283
|
### Breaking Changes
|
|
205
284
|
|
|
206
285
|
- Replaced `theme` setting with `theme.dark` and `theme.light` (auto-migrated)
|
|
@@ -251,6 +330,7 @@
|
|
|
251
330
|
- Sanitized debug log display to strip control codes, normalize tabs, and trim width
|
|
252
331
|
|
|
253
332
|
## [12.4.0] - 2026-02-14
|
|
333
|
+
|
|
254
334
|
### Changed
|
|
255
335
|
|
|
256
336
|
- Moved `sanitizeText` function from `@oh-my-pi/pi-utils` to `@oh-my-pi/pi-natives` for better code organization
|
|
@@ -266,6 +346,7 @@
|
|
|
266
346
|
- Fixed Cloudflare returning corrupted bytes when compression is negotiated in web scraper requests
|
|
267
347
|
|
|
268
348
|
## [12.3.0] - 2026-02-14
|
|
349
|
+
|
|
269
350
|
### Added
|
|
270
351
|
|
|
271
352
|
- Added autonomous memory extraction and consolidation system with configurable settings
|
|
@@ -311,6 +392,7 @@
|
|
|
311
392
|
- Fixed fetch tool to preserve actual response metadata (finalUrl, contentType) instead of defaults when requests fail
|
|
312
393
|
|
|
313
394
|
||||||| parent of a70a34c8b (fix(coding-agent/debug): Sanitized debug log rendering)
|
|
395
|
+
|
|
314
396
|
## [12.1.0] - 2026-02-13
|
|
315
397
|
|
|
316
398
|
### Added
|
|
@@ -362,6 +444,7 @@
|
|
|
362
444
|
- Removed @types/jsdom dependency
|
|
363
445
|
|
|
364
446
|
## [11.14.1] - 2026-02-12
|
|
447
|
+
|
|
365
448
|
### Changed
|
|
366
449
|
|
|
367
450
|
- Improved Bun binary detection to check `Bun.env.PI_COMPILED` environment variable
|
|
@@ -373,6 +456,7 @@
|
|
|
373
456
|
- Fixed Bun update process to properly handle version pinning and report installation mismatches
|
|
374
457
|
|
|
375
458
|
## [11.14.0] - 2026-02-12
|
|
459
|
+
|
|
376
460
|
### Added
|
|
377
461
|
|
|
378
462
|
- Added SwiftLint linter client with JSON reporter support for Swift file linting
|
|
@@ -425,6 +509,7 @@
|
|
|
425
509
|
- Refactored browser/file opening across multiple modules to use unified `openPath` utility for improved maintainability
|
|
426
510
|
|
|
427
511
|
## [11.12.0] - 2026-02-11
|
|
512
|
+
|
|
428
513
|
### Added
|
|
429
514
|
|
|
430
515
|
- Added `resolveFileDisplayMode` utility to centralize file display mode resolution across tools (read, grep, file mentions)
|
|
@@ -513,6 +598,7 @@
|
|
|
513
598
|
- Refactored hash line formatting to use async `streamHashLinesFromLines` for better performance
|
|
514
599
|
|
|
515
600
|
## [11.10.3] - 2026-02-10
|
|
601
|
+
|
|
516
602
|
### Added
|
|
517
603
|
|
|
518
604
|
- Exported `./patch/*` subpath for direct access to patch utilities
|
|
@@ -538,6 +624,7 @@
|
|
|
538
624
|
- Removed AggregateError unwrapping from console.warn in CLI initialization
|
|
539
625
|
|
|
540
626
|
## [11.10.1] - 2026-02-10
|
|
627
|
+
|
|
541
628
|
### Changed
|
|
542
629
|
|
|
543
630
|
- Migrated CLI framework from oclif to lightweight pi-utils CLI runner
|
|
@@ -552,6 +639,7 @@
|
|
|
552
639
|
- Removed custom oclif help renderer (oclif-help.ts)
|
|
553
640
|
|
|
554
641
|
## [11.10.0] - 2026-02-10
|
|
642
|
+
|
|
555
643
|
### Breaking Changes
|
|
556
644
|
|
|
557
645
|
- 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.)
|
|
@@ -702,6 +790,7 @@
|
|
|
702
790
|
- Improved bash tool output draining after foreground completion to reduce tail output truncation
|
|
703
791
|
|
|
704
792
|
## [11.8.0] - 2026-02-10
|
|
793
|
+
|
|
705
794
|
### Added
|
|
706
795
|
|
|
707
796
|
- Added `ctx.reload()` method to extension command context to reload extensions, skills, prompts, and themes from disk
|
|
@@ -724,6 +813,7 @@
|
|
|
724
813
|
- Fixed archive extraction error handling to provide clear error messages on failure
|
|
725
814
|
|
|
726
815
|
## [11.7.0] - 2026-02-07
|
|
816
|
+
|
|
727
817
|
### Changed
|
|
728
818
|
|
|
729
819
|
- Enhanced error messages for failed Python cells to include full combined output context instead of just the error message
|
|
@@ -735,6 +825,7 @@
|
|
|
735
825
|
- Fixed tab character rendering in Python tool output display to properly format whitespace in cell output and status events
|
|
736
826
|
|
|
737
827
|
## [11.6.1] - 2026-02-07
|
|
828
|
+
|
|
738
829
|
### Fixed
|
|
739
830
|
|
|
740
831
|
- Fixed potential crash when rendering results with undefined details.results
|
|
@@ -783,6 +874,7 @@
|
|
|
783
874
|
- Removed ability to save screenshots to custom paths or artifacts directory
|
|
784
875
|
|
|
785
876
|
## [11.4.1] - 2026-02-06
|
|
877
|
+
|
|
786
878
|
### Fixed
|
|
787
879
|
|
|
788
880
|
- Fixed tab character display in error messages and bash tool output by properly replacing tabs with spaces
|
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.0",
|
|
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.0",
|
|
89
|
+
"@oh-my-pi/pi-agent-core": "12.14.0",
|
|
90
|
+
"@oh-my-pi/pi-ai": "12.14.0",
|
|
91
|
+
"@oh-my-pi/pi-natives": "12.14.0",
|
|
92
|
+
"@oh-my-pi/pi-tui": "12.14.0",
|
|
93
|
+
"@oh-my-pi/pi-utils": "12.14.0",
|
|
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)`);
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH CLI command handlers.
|
|
3
|
+
*
|
|
4
|
+
* Handles `omp ssh <command>` subcommands for SSH host configuration management.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { getSSHConfigPath } from "@oh-my-pi/pi-utils/dirs";
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import { addSSHHost, readSSHConfigFile, removeSSHHost, type SSHHostConfig } from "../ssh/config-writer";
|
|
10
|
+
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Types
|
|
13
|
+
// =============================================================================
|
|
14
|
+
|
|
15
|
+
export type SSHAction = "add" | "remove" | "list";
|
|
16
|
+
|
|
17
|
+
export interface SSHCommandArgs {
|
|
18
|
+
action: SSHAction;
|
|
19
|
+
args: string[];
|
|
20
|
+
flags: {
|
|
21
|
+
json?: boolean;
|
|
22
|
+
host?: string;
|
|
23
|
+
user?: string;
|
|
24
|
+
port?: string;
|
|
25
|
+
key?: string;
|
|
26
|
+
desc?: string;
|
|
27
|
+
compat?: boolean;
|
|
28
|
+
scope?: "project" | "user";
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// =============================================================================
|
|
33
|
+
// Main dispatcher
|
|
34
|
+
// =============================================================================
|
|
35
|
+
|
|
36
|
+
export async function runSSHCommand(cmd: SSHCommandArgs): Promise<void> {
|
|
37
|
+
switch (cmd.action) {
|
|
38
|
+
case "add":
|
|
39
|
+
await handleAdd(cmd);
|
|
40
|
+
break;
|
|
41
|
+
case "remove":
|
|
42
|
+
await handleRemove(cmd);
|
|
43
|
+
break;
|
|
44
|
+
case "list":
|
|
45
|
+
await handleList(cmd);
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
process.stdout.write(chalk.red(`Unknown action: ${cmd.action}\n`));
|
|
49
|
+
process.stdout.write(`Valid actions: add, remove, list\n`);
|
|
50
|
+
process.exitCode = 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// =============================================================================
|
|
55
|
+
// Handlers
|
|
56
|
+
// =============================================================================
|
|
57
|
+
|
|
58
|
+
async function handleAdd(cmd: SSHCommandArgs): Promise<void> {
|
|
59
|
+
const name = cmd.args[0];
|
|
60
|
+
if (!name) {
|
|
61
|
+
process.stdout.write(chalk.red("Error: Host name required\n"));
|
|
62
|
+
process.stdout.write(
|
|
63
|
+
chalk.dim("Usage: omp ssh add <name> --host <address> [--user <user>] [--port <port>] [--key <path>]\n"),
|
|
64
|
+
);
|
|
65
|
+
process.exitCode = 1;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const host = cmd.flags.host;
|
|
70
|
+
if (!host) {
|
|
71
|
+
process.stdout.write(chalk.red("Error: --host is required\n"));
|
|
72
|
+
process.stdout.write(chalk.dim("Usage: omp ssh add <name> --host <address>\n"));
|
|
73
|
+
process.exitCode = 1;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Validate port if provided
|
|
78
|
+
if (cmd.flags.port !== undefined) {
|
|
79
|
+
const port = Number.parseInt(cmd.flags.port, 10);
|
|
80
|
+
if (Number.isNaN(port) || port < 1 || port > 65535) {
|
|
81
|
+
process.stdout.write(chalk.red("Error: Port must be an integer between 1 and 65535\n"));
|
|
82
|
+
process.exitCode = 1;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const hostConfig: SSHHostConfig = { host };
|
|
88
|
+
if (cmd.flags.user) hostConfig.username = cmd.flags.user;
|
|
89
|
+
if (cmd.flags.port) hostConfig.port = Number.parseInt(cmd.flags.port, 10);
|
|
90
|
+
if (cmd.flags.key) hostConfig.keyPath = cmd.flags.key;
|
|
91
|
+
if (cmd.flags.desc) hostConfig.description = cmd.flags.desc;
|
|
92
|
+
if (cmd.flags.compat) hostConfig.compat = true;
|
|
93
|
+
|
|
94
|
+
const scope = cmd.flags.scope ?? "project";
|
|
95
|
+
const filePath = getSSHConfigPath(scope);
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
await addSSHHost(filePath, name, hostConfig);
|
|
99
|
+
process.stdout.write(chalk.green(`Added SSH host "${name}" to ${scope} config\n`));
|
|
100
|
+
} catch (err) {
|
|
101
|
+
process.stdout.write(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}\n`));
|
|
102
|
+
process.exitCode = 1;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function handleRemove(cmd: SSHCommandArgs): Promise<void> {
|
|
107
|
+
const name = cmd.args[0];
|
|
108
|
+
if (!name) {
|
|
109
|
+
process.stdout.write(chalk.red("Error: Host name required\n"));
|
|
110
|
+
process.stdout.write(chalk.dim("Usage: omp ssh remove <name> [--scope project|user]\n"));
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const scope = cmd.flags.scope ?? "project";
|
|
116
|
+
const filePath = getSSHConfigPath(scope);
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
await removeSSHHost(filePath, name);
|
|
120
|
+
process.stdout.write(chalk.green(`Removed SSH host "${name}" from ${scope} config\n`));
|
|
121
|
+
} catch (err) {
|
|
122
|
+
process.stdout.write(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}\n`));
|
|
123
|
+
process.exitCode = 1;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function handleList(cmd: SSHCommandArgs): Promise<void> {
|
|
128
|
+
const projectPath = getSSHConfigPath("project");
|
|
129
|
+
const userPath = getSSHConfigPath("user");
|
|
130
|
+
|
|
131
|
+
const [projectConfig, userConfig] = await Promise.all([readSSHConfigFile(projectPath), readSSHConfigFile(userPath)]);
|
|
132
|
+
|
|
133
|
+
const projectHosts = projectConfig.hosts ?? {};
|
|
134
|
+
const userHosts = userConfig.hosts ?? {};
|
|
135
|
+
|
|
136
|
+
if (cmd.flags.json) {
|
|
137
|
+
process.stdout.write(JSON.stringify({ project: projectHosts, user: userHosts }, null, 2));
|
|
138
|
+
process.stdout.write("\n");
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const hasProject = Object.keys(projectHosts).length > 0;
|
|
143
|
+
const hasUser = Object.keys(userHosts).length > 0;
|
|
144
|
+
|
|
145
|
+
if (!hasProject && !hasUser) {
|
|
146
|
+
process.stdout.write(chalk.dim("No SSH hosts configured\n"));
|
|
147
|
+
process.stdout.write(chalk.dim("Add one with: omp ssh add <name> --host <address>\n"));
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (hasProject) {
|
|
152
|
+
process.stdout.write(chalk.bold("Project SSH Hosts (.omp/ssh.json):\n"));
|
|
153
|
+
printHosts(projectHosts);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (hasProject && hasUser) {
|
|
157
|
+
process.stdout.write("\n");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (hasUser) {
|
|
161
|
+
process.stdout.write(chalk.bold("User SSH Hosts (~/.omp/agent/ssh.json):\n"));
|
|
162
|
+
printHosts(userHosts);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// =============================================================================
|
|
167
|
+
// Helpers
|
|
168
|
+
// =============================================================================
|
|
169
|
+
|
|
170
|
+
function printHosts(hosts: Record<string, SSHHostConfig>): void {
|
|
171
|
+
for (const [name, config] of Object.entries(hosts)) {
|
|
172
|
+
const parts = [chalk.cyan(name), config.host];
|
|
173
|
+
if (config.username) parts.push(chalk.dim(config.username));
|
|
174
|
+
if (config.port && config.port !== 22) parts.push(chalk.dim(`port:${config.port}`));
|
|
175
|
+
if (config.keyPath) parts.push(chalk.dim(config.keyPath));
|
|
176
|
+
if (config.description) parts.push(chalk.dim(`- ${config.description}`));
|
|
177
|
+
process.stdout.write(` ${parts.join(" ")}\n`);
|
|
178
|
+
}
|
|
179
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -23,6 +23,7 @@ const commands: CommandEntry[] = [
|
|
|
23
23
|
{ name: "plugin", load: () => import("./commands/plugin").then(m => m.default) },
|
|
24
24
|
{ name: "setup", load: () => import("./commands/setup").then(m => m.default) },
|
|
25
25
|
{ name: "shell", load: () => import("./commands/shell").then(m => m.default) },
|
|
26
|
+
{ name: "ssh", load: () => import("./commands/ssh").then(m => m.default) },
|
|
26
27
|
{ name: "stats", load: () => import("./commands/stats").then(m => m.default) },
|
|
27
28
|
{ name: "update", load: () => import("./commands/update").then(m => m.default) },
|
|
28
29
|
{ name: "search", load: () => import("./commands/web-search").then(m => m.default), aliases: ["q"] },
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manage SSH host configurations.
|
|
3
|
+
*/
|
|
4
|
+
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
|
|
5
|
+
import { runSSHCommand, type SSHAction, type SSHCommandArgs } from "../cli/ssh-cli";
|
|
6
|
+
import { initTheme } from "../modes/theme/theme";
|
|
7
|
+
|
|
8
|
+
const ACTIONS: SSHAction[] = ["add", "remove", "list"];
|
|
9
|
+
|
|
10
|
+
export default class SSH extends Command {
|
|
11
|
+
static description = "Manage SSH host configurations";
|
|
12
|
+
|
|
13
|
+
static args = {
|
|
14
|
+
action: Args.string({
|
|
15
|
+
description: "SSH action",
|
|
16
|
+
required: false,
|
|
17
|
+
options: ACTIONS,
|
|
18
|
+
}),
|
|
19
|
+
targets: Args.string({
|
|
20
|
+
description: "Host name or arguments",
|
|
21
|
+
required: false,
|
|
22
|
+
multiple: true,
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
static flags = {
|
|
27
|
+
json: Flags.boolean({ description: "Output JSON" }),
|
|
28
|
+
host: Flags.string({ description: "Host address" }),
|
|
29
|
+
user: Flags.string({ description: "Username" }),
|
|
30
|
+
port: Flags.string({ description: "Port number" }),
|
|
31
|
+
key: Flags.string({ description: "Identity key path" }),
|
|
32
|
+
desc: Flags.string({ description: "Host description" }),
|
|
33
|
+
compat: Flags.boolean({ description: "Enable compatibility mode" }),
|
|
34
|
+
scope: Flags.string({ description: "Config scope (project|user)", options: ["project", "user"] }),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
async run(): Promise<void> {
|
|
38
|
+
const { args, flags } = await this.parse(SSH);
|
|
39
|
+
const action = (args.action ?? "list") as SSHAction;
|
|
40
|
+
const targets = Array.isArray(args.targets) ? args.targets : args.targets ? [args.targets] : [];
|
|
41
|
+
|
|
42
|
+
const cmd: SSHCommandArgs = {
|
|
43
|
+
action,
|
|
44
|
+
args: targets,
|
|
45
|
+
flags: {
|
|
46
|
+
json: flags.json,
|
|
47
|
+
host: flags.host,
|
|
48
|
+
user: flags.user,
|
|
49
|
+
port: flags.port,
|
|
50
|
+
key: flags.key,
|
|
51
|
+
desc: flags.desc,
|
|
52
|
+
compat: flags.compat,
|
|
53
|
+
scope: flags.scope as "project" | "user" | undefined,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
await initTheme();
|
|
58
|
+
await runSSHCommand(cmd);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -76,7 +76,6 @@ Call create_conventional_analysis with:
|
|
|
76
76
|
}
|
|
77
77
|
</output_format>
|
|
78
78
|
|
|
79
|
-
<examples>
|
|
80
79
|
<example name="feature-with-api">
|
|
81
80
|
{
|
|
82
81
|
"type": "feat",
|
|
@@ -146,5 +145,4 @@ Call create_conventional_analysis with:
|
|
|
146
145
|
"details": [],
|
|
147
146
|
"issue_refs": []
|
|
148
147
|
}
|
|
149
|
-
</example>
|
|
150
|
-
</examples>
|
|
148
|
+
</example>
|
|
@@ -230,13 +230,28 @@ handlebars.registerHelper("jtdToTypeScript", (schema: unknown): string => jtdToT
|
|
|
230
230
|
handlebars.registerHelper("jsonStringify", (value: unknown): string => JSON.stringify(value));
|
|
231
231
|
|
|
232
232
|
/**
|
|
233
|
-
* {{
|
|
234
|
-
* Returns `"lineNum
|
|
233
|
+
* {{hlineref lineNum "content"}} — compute a real hashline ref for prompt examples.
|
|
234
|
+
* Returns `"lineNum#hash"` using the actual hash algorithm.
|
|
235
235
|
*/
|
|
236
|
-
|
|
236
|
+
function formatHashlineRef(lineNum: unknown, content: unknown): { num: number; text: string; ref: string } {
|
|
237
237
|
const num = typeof lineNum === "number" ? lineNum : Number.parseInt(String(lineNum), 10);
|
|
238
|
-
const
|
|
239
|
-
|
|
238
|
+
const text = typeof content === "string" ? content : String(content ?? "");
|
|
239
|
+
const ref = `${num}#${computeLineHash(num, text)}`;
|
|
240
|
+
return { num, text, ref };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
handlebars.registerHelper("hlineref", (lineNum: unknown, content: unknown): string => {
|
|
244
|
+
const { ref } = formatHashlineRef(lineNum, content);
|
|
245
|
+
return ref;
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* {{hlinefull lineNum "content"}} — format a full read-style line with prefix.
|
|
250
|
+
* Returns `"lineNum#hash:content"`.
|
|
251
|
+
*/
|
|
252
|
+
handlebars.registerHelper("hlinefull", (lineNum: unknown, content: unknown): string => {
|
|
253
|
+
const { ref, text } = formatHashlineRef(lineNum, content);
|
|
254
|
+
return `${ref}:${text}`;
|
|
240
255
|
});
|
|
241
256
|
|
|
242
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:
|
|
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
|