@oh-my-pi/pi-coding-agent 16.1.21 → 16.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/dist/cli.js +3659 -3517
  3. package/dist/types/cli/gc-cli.d.ts +58 -0
  4. package/dist/types/commands/gc.d.ts +37 -0
  5. package/dist/types/config/settings-schema.d.ts +54 -0
  6. package/dist/types/config/settings.d.ts +11 -0
  7. package/dist/types/mcp/transports/stdio.d.ts +25 -1
  8. package/dist/types/mcp/transports/stdio.test.d.ts +1 -0
  9. package/dist/types/modes/theme/mermaid-rendering.test.d.ts +1 -0
  10. package/dist/types/modes/theme/theme.d.ts +1 -0
  11. package/dist/types/session/session-listing.d.ts +10 -1
  12. package/dist/types/system-prompt.d.ts +2 -0
  13. package/dist/types/tools/plan-mode-guard.d.ts +7 -0
  14. package/package.json +12 -12
  15. package/scripts/bench-guard.ts +1 -1
  16. package/src/cli/gc-cli.ts +939 -0
  17. package/src/cli-commands.ts +1 -0
  18. package/src/commands/gc.ts +46 -0
  19. package/src/config/settings-schema.ts +45 -0
  20. package/src/config/settings.ts +44 -6
  21. package/src/edit/hashline/filesystem.ts +11 -6
  22. package/src/eval/__tests__/julia-prelude.test.ts +18 -0
  23. package/src/eval/jl/runner.jl +7 -1
  24. package/src/extensibility/plugins/legacy-pi-bundled-keys.ts +2 -0
  25. package/src/extensibility/plugins/legacy-pi-bundled-registry.ts +6 -0
  26. package/src/internal-urls/docs-index.generated.txt +1 -1
  27. package/src/lsp/index.ts +8 -1
  28. package/src/mcp/oauth-discovery.ts +62 -15
  29. package/src/mcp/transports/stdio.test.ts +45 -0
  30. package/src/mcp/transports/stdio.ts +46 -12
  31. package/src/modes/controllers/input-controller.ts +2 -2
  32. package/src/modes/controllers/selector-controller.ts +10 -0
  33. package/src/modes/interactive-mode.ts +26 -9
  34. package/src/modes/theme/mermaid-rendering.test.ts +53 -0
  35. package/src/modes/theme/theme.ts +33 -14
  36. package/src/prompts/system/plan-mode-active.md +9 -0
  37. package/src/prompts/system/system-prompt.md +2 -0
  38. package/src/sdk.ts +43 -4
  39. package/src/session/agent-session.ts +323 -62
  40. package/src/session/session-listing.ts +35 -2
  41. package/src/slash-commands/builtin-registry.ts +20 -2
  42. package/src/system-prompt.ts +4 -0
  43. package/src/tools/acp-bridge.ts +6 -1
  44. package/src/tools/plan-mode-guard.ts +26 -13
  45. package/src/utils/edit-mode.ts +19 -2
  46. package/src/utils/shell-snapshot.ts +1 -1
@@ -0,0 +1,58 @@
1
+ export interface GcCommandFlags {
2
+ apply?: boolean;
3
+ json?: boolean;
4
+ agentDir?: string;
5
+ blobs?: boolean;
6
+ archive?: boolean;
7
+ wal?: boolean;
8
+ coldArchiveAfterDays?: number;
9
+ retainNewestGlobal?: number;
10
+ retainNewestPerCwd?: number;
11
+ }
12
+ export interface GcCommandArgs {
13
+ flags: GcCommandFlags;
14
+ }
15
+ export interface BlobGcResult {
16
+ referenced: number;
17
+ candidates: number;
18
+ wouldDelete: number;
19
+ deleted: number;
20
+ bytes: number;
21
+ errors: string[];
22
+ }
23
+ export interface ArchiveGcResult {
24
+ scanned: number;
25
+ skippedActive: number;
26
+ keptNewestGlobal: number;
27
+ keptNewestPerCwd: number;
28
+ wouldArchive: number;
29
+ archived: number;
30
+ historyRowsDeleted: number;
31
+ ftsRebuilt: boolean;
32
+ errors: string[];
33
+ }
34
+ export interface WalCheckpointResult {
35
+ dbPath: string;
36
+ walBytes: number;
37
+ wouldCheckpoint: boolean;
38
+ checkpointed: boolean;
39
+ busy: number;
40
+ log: number;
41
+ checkpointedFrames: number;
42
+ }
43
+ export interface WalGcResult {
44
+ databases: WalCheckpointResult[];
45
+ walBytes: number;
46
+ wouldCheckpoint: boolean;
47
+ checkpointed: boolean;
48
+ }
49
+ export interface GcResult {
50
+ agentDir: string;
51
+ apply: boolean;
52
+ blobs?: BlobGcResult;
53
+ archive?: ArchiveGcResult;
54
+ wal?: WalGcResult;
55
+ lockPath: string;
56
+ }
57
+ export declare function collectGcErrors(result: GcResult): string[];
58
+ export declare function runGcCommand(args: GcCommandArgs): Promise<GcResult>;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Run on-disk storage maintenance.
3
+ */
4
+ import { Command } from "@oh-my-pi/pi-utils/cli";
5
+ export default class Gc extends Command {
6
+ static description: string;
7
+ static flags: {
8
+ apply: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
9
+ description: string;
10
+ };
11
+ json: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
12
+ description: string;
13
+ };
14
+ "agent-dir": import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"string"> & {
15
+ description: string;
16
+ };
17
+ blobs: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
18
+ description: string;
19
+ };
20
+ archive: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
21
+ description: string;
22
+ };
23
+ wal: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
24
+ description: string;
25
+ };
26
+ "cold-archive-after-days": import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"integer"> & {
27
+ description: string;
28
+ };
29
+ "retain-newest-global": import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"integer"> & {
30
+ description: string;
31
+ };
32
+ "retain-newest-per-cwd": import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"integer"> & {
33
+ description: string;
34
+ };
35
+ };
36
+ run(): Promise<void>;
37
+ }
@@ -745,6 +745,16 @@ export declare const SETTINGS_SCHEMA: {
745
745
  readonly description: "Render Markdown H1 headings at 2x scale using Kitty's OSC 66 text-sizing protocol. Only takes effect on Kitty terminals; ignored everywhere else. Off by default.";
746
746
  };
747
747
  };
748
+ readonly "tui.renderMermaid": {
749
+ readonly type: "boolean";
750
+ readonly default: true;
751
+ readonly ui: {
752
+ readonly tab: "appearance";
753
+ readonly group: "Display";
754
+ readonly label: "Render Mermaid Diagrams";
755
+ readonly description: "Render Mermaid fenced code blocks as ASCII diagrams";
756
+ };
757
+ };
748
758
  readonly "tui.hyperlinks": {
749
759
  readonly type: "enum";
750
760
  readonly values: readonly ["off", "auto", "always"];
@@ -1709,6 +1719,16 @@ export declare const SETTINGS_SCHEMA: {
1709
1719
  readonly description: "Automatically compact context when it gets too large";
1710
1720
  };
1711
1721
  };
1722
+ readonly "compaction.midTurnEnabled": {
1723
+ readonly type: "boolean";
1724
+ readonly default: true;
1725
+ readonly ui: {
1726
+ readonly tab: "context";
1727
+ readonly group: "Compaction";
1728
+ readonly label: "Mid-Turn Compaction";
1729
+ readonly description: "Check thresholds at safe mid-turn tool-loop boundaries before the next provider request";
1730
+ };
1731
+ };
1712
1732
  readonly "compaction.strategy": {
1713
1733
  readonly type: "enum";
1714
1734
  readonly values: readonly ["context-full", "handoff", "shake", "snapcompact", "off"];
@@ -5062,6 +5082,30 @@ export declare const SETTINGS_SCHEMA: {
5062
5082
  readonly values: readonly ["unset", "granted", "denied"];
5063
5083
  readonly default: "unset";
5064
5084
  };
5085
+ readonly "gc.blobs": {
5086
+ readonly type: "boolean";
5087
+ readonly default: true;
5088
+ };
5089
+ readonly "gc.archive": {
5090
+ readonly type: "boolean";
5091
+ readonly default: true;
5092
+ };
5093
+ readonly "gc.wal": {
5094
+ readonly type: "boolean";
5095
+ readonly default: true;
5096
+ };
5097
+ readonly "gc.coldArchiveAfterDays": {
5098
+ readonly type: "number";
5099
+ readonly default: 30;
5100
+ };
5101
+ readonly "gc.retainNewestGlobal": {
5102
+ readonly type: "number";
5103
+ readonly default: 20;
5104
+ };
5105
+ readonly "gc.retainNewestPerCwd": {
5106
+ readonly type: "number";
5107
+ readonly default: 10;
5108
+ };
5065
5109
  readonly "thinkingBudgets.minimal": {
5066
5110
  readonly type: "number";
5067
5111
  readonly default: 1024;
@@ -5133,6 +5177,7 @@ export interface CompactionSettings {
5133
5177
  thresholdTokens: number;
5134
5178
  reserveTokens: number;
5135
5179
  keepRecentTokens: number;
5180
+ midTurnEnabled: boolean;
5136
5181
  handoffSaveToDisk: boolean;
5137
5182
  autoContinue: boolean;
5138
5183
  remoteEnabled: boolean;
@@ -5262,6 +5307,14 @@ export interface CodexResetsSettings {
5262
5307
  minBlockedMinutes: number;
5263
5308
  keepCredits: number;
5264
5309
  }
5310
+ export interface GcSettings {
5311
+ blobs: boolean;
5312
+ archive: boolean;
5313
+ wal: boolean;
5314
+ coldArchiveAfterDays: number;
5315
+ retainNewestGlobal: number;
5316
+ retainNewestPerCwd: number;
5317
+ }
5265
5318
  /** Map group prefix -> typed settings interface */
5266
5319
  export interface GroupTypeMap {
5267
5320
  compaction: CompactionSettings;
@@ -5281,6 +5334,7 @@ export interface GroupTypeMap {
5281
5334
  cycleOrder: string[];
5282
5335
  shellMinimizer: ShellMinimizerSettings;
5283
5336
  codexResets: CodexResetsSettings;
5337
+ gc: GcSettings;
5284
5338
  }
5285
5339
  export type GroupPrefix = keyof GroupTypeMap;
5286
5340
  export {};
@@ -28,6 +28,8 @@ export interface SettingsOptions {
28
28
  agentDir?: string;
29
29
  /** Don't persist to disk (for tests) */
30
30
  inMemory?: boolean;
31
+ /** Read config sources without opening storage or writing migrations */
32
+ readOnly?: boolean;
31
33
  /** Initial overrides */
32
34
  overrides?: Partial<Record<SettingPath, unknown>>;
33
35
  /** Extra config.yml-style overlays loaded after global/project settings */
@@ -41,6 +43,15 @@ export declare class Settings {
41
43
  * Call once at startup before accessing `settings`.
42
44
  */
43
45
  static init(options?: SettingsOptions): Promise<Settings>;
46
+ /**
47
+ * Load effective settings from config.yml and project providers without
48
+ * opening agent.db, migrating legacy settings, or writing marker files.
49
+ */
50
+ static loadReadOnly(options?: SettingsOptions): Promise<Settings>;
51
+ /**
52
+ * Load a persisted settings instance without touching the global singleton.
53
+ */
54
+ static loadIsolated(options?: SettingsOptions): Promise<Settings>;
44
55
  /**
45
56
  * Create an isolated instance for testing.
46
57
  * Does not affect the global singleton.
@@ -5,15 +5,39 @@
5
5
  * Messages are newline-delimited JSON.
6
6
  */
7
7
  import type { MCPRequestOptions, MCPStdioServerConfig, MCPTransport } from "../../mcp/types";
8
- /** Subprocess argv for launching an MCP stdio server. */
8
+ /** Subprocess argv and platform-derived spawn flags for an MCP stdio server. */
9
9
  export interface StdioSpawnCommand {
10
10
  cmd: string[];
11
+ /**
12
+ * Hide the Windows console window for the direct child.
13
+ *
14
+ * Windows uses this only when the OMP host has no console to share. When
15
+ * the host is running inside a terminal, `windowsHide: true` maps to
16
+ * `CREATE_NO_WINDOW`, which strips that inheritable console from hidden
17
+ * `cmd.exe` / PowerShell wrapper chains. Their console grandchildren then
18
+ * allocate fresh visible conhost windows during startup or reconnects
19
+ * (#3567).
20
+ */
11
21
  windowsHide?: boolean;
22
+ /**
23
+ * Run the subprocess in its own session.
24
+ *
25
+ * POSIX: `true`. Detach → `setsid`, so the MCP process tree has no
26
+ * controlling terminal and terminal job-control signals (Ctrl+Z SIGTSTP,
27
+ * background-read SIGTTIN) cannot stop stdio servers such as
28
+ * `chrome-devtools-mcp` and leave our read loop blocked on silent pipes.
29
+ *
30
+ * Windows: `false`. There is no SIGTSTP/SIGTTIN to escape, and Windows
31
+ * wrapper chains must stay in the OMP console session so nested console
32
+ * grandchildren keep stdout routed through our pipe (#3544).
33
+ */
34
+ detached: boolean;
12
35
  }
13
36
  /** Inputs used to resolve platform-specific stdio spawn behavior. */
14
37
  export interface ResolveStdioSpawnOptions {
15
38
  cwd: string;
16
39
  env: Record<string, string | undefined>;
40
+ hostHasInheritableConsole?: boolean;
17
41
  platform?: NodeJS.Platform;
18
42
  }
19
43
  /**
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -347,6 +347,7 @@ export declare function getThemeExportColors(themeName?: string): Promise<{
347
347
  */
348
348
  export declare function highlightCode(code: string, lang?: string, highlightTheme?: Theme): string[];
349
349
  export declare function getSymbolTheme(): SymbolTheme;
350
+ export declare function setMarkdownMermaidRendering(enabled: boolean): void;
350
351
  export declare function getMarkdownTheme(): MarkdownTheme;
351
352
  export declare function getSelectListTheme(): SelectListTheme;
352
353
  export declare function getEditorTheme(): EditorTheme;
@@ -60,10 +60,19 @@ export declare function recoverOrphanedBackups(sessionDir: string, storage: Sess
60
60
  * file's lifecycle {@link SessionStatus}.
61
61
  */
62
62
  export declare function listSessions(sessionDir: string, storage: SessionStorage): Promise<SessionInfo[]>;
63
+ /**
64
+ * List sessions without repairing orphaned backups or mutating the directory.
65
+ */
66
+ export declare function listSessionsReadOnly(sessionDir: string, storage: SessionStorage): Promise<SessionInfo[]>;
63
67
  /** List all sessions across all project directories (newest first). */
64
68
  export declare function listAllSessions(storage?: SessionStorage): Promise<SessionInfo[]>;
65
69
  /** Exported for testing */
66
70
  export declare function findMostRecentSession(sessionDir: string, storage?: SessionStorage): Promise<string | null>;
67
71
  /** Get recent sessions for display in the welcome screen. */
68
72
  export declare function getRecentSessions(sessionDir: string, limit?: number, storage?: SessionStorage): Promise<RecentSessionInfo[]>;
69
- export declare function resolveResumableSession(sessionArg: string, cwd: string, sessionDir?: string, storage?: SessionStorage): Promise<ResolvedSessionMatch | undefined>;
73
+ /** Controls cross-directory fallback for resumable session lookup. */
74
+ export interface ResolveResumableSessionOptions {
75
+ /** Search default global session buckets after the active/custom session directory misses. */
76
+ allowGlobalFallback?: boolean;
77
+ }
78
+ export declare function resolveResumableSession(sessionArg: string, cwd: string, sessionDir?: string, storageOrOptions?: SessionStorage | ResolveResumableSessionOptions, options?: ResolveResumableSessionOptions): Promise<ResolvedSessionMatch | undefined>;
@@ -112,6 +112,8 @@ export interface BuildSystemPromptOptions {
112
112
  personality?: Personality;
113
113
  /** Whether to include the workspace directory tree in the system prompt. Default: false */
114
114
  includeWorkspaceTree?: boolean;
115
+ /** Whether Mermaid fenced blocks render as terminal ASCII diagrams. Default: true */
116
+ renderMermaid?: boolean;
115
117
  }
116
118
  /** Result of building provider-facing system prompt messages. */
117
119
  export interface BuildSystemPromptResult {
@@ -6,6 +6,13 @@ import type { ToolSession } from ".";
6
6
  * resolver surfaces the real error. Exported for callers (e.g. `write`) that
7
7
  * make scheme/bridge-routing decisions before {@link resolvePlanPath} runs. */
8
8
  export declare function unwrapHashlineHeaderPath(targetPath: string): string;
9
+ /** True when `targetPath` resolves into the session-local artifact sandbox.
10
+ * Routes through {@link resolvePlanPath} so the guard and the eventual write
11
+ * always agree on the absolute target (including bracketed hashline headers,
12
+ * `local://` URLs, and bare absolute paths). Files inside the sandbox are not
13
+ * part of the working tree, so plan mode treats them as freely writable
14
+ * scratch/plan space — and tag-based path recovery may rebind onto them. */
15
+ export declare function targetsLocalSandbox(session: ToolSession, targetPath: string): boolean;
9
16
  /**
10
17
  * Resolve a write/edit target to its absolute filesystem path, honoring the
11
18
  * `local://` and `vault://` schemes. Plain paths resolve against the session cwd.
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": "16.1.21",
4
+ "version": "16.1.23",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -48,17 +48,17 @@
48
48
  "@agentclientprotocol/sdk": "0.25.0",
49
49
  "@babel/parser": "^7.29.7",
50
50
  "@mozilla/readability": "^0.6.0",
51
- "@oh-my-pi/hashline": "16.1.21",
52
- "@oh-my-pi/omp-stats": "16.1.21",
53
- "@oh-my-pi/pi-agent-core": "16.1.21",
54
- "@oh-my-pi/pi-ai": "16.1.21",
55
- "@oh-my-pi/pi-catalog": "16.1.21",
56
- "@oh-my-pi/pi-mnemopi": "16.1.21",
57
- "@oh-my-pi/pi-natives": "16.1.21",
58
- "@oh-my-pi/pi-tui": "16.1.21",
59
- "@oh-my-pi/pi-utils": "16.1.21",
60
- "@oh-my-pi/pi-wire": "16.1.21",
61
- "@oh-my-pi/snapcompact": "16.1.21",
51
+ "@oh-my-pi/hashline": "16.1.23",
52
+ "@oh-my-pi/omp-stats": "16.1.23",
53
+ "@oh-my-pi/pi-agent-core": "16.1.23",
54
+ "@oh-my-pi/pi-ai": "16.1.23",
55
+ "@oh-my-pi/pi-catalog": "16.1.23",
56
+ "@oh-my-pi/pi-mnemopi": "16.1.23",
57
+ "@oh-my-pi/pi-natives": "16.1.23",
58
+ "@oh-my-pi/pi-tui": "16.1.23",
59
+ "@oh-my-pi/pi-utils": "16.1.23",
60
+ "@oh-my-pi/pi-wire": "16.1.23",
61
+ "@oh-my-pi/snapcompact": "16.1.23",
62
62
  "@opentelemetry/api": "^1.9.1",
63
63
  "@opentelemetry/context-async-hooks": "^2.7.1",
64
64
  "@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
@@ -22,7 +22,7 @@ import * as path from "node:path";
22
22
 
23
23
  const THRESHOLD = 1.05; // 5% regression budget
24
24
  const BASELINE_PATH = path.join(import.meta.dir, "..", "bench", "boot-baseline.json");
25
- const BENCH_COMMAND = "PI_TIMING=x bun src/cli.ts";
25
+ const BENCH_COMMAND = "PI_TIMING=x PI_STRICT_EDIT_MODE=1 bun src/cli.ts";
26
26
  const cwd = path.join(import.meta.dir, "..");
27
27
 
28
28
  function medianOf(hyperfineJson: string): number {