@oh-my-pi/pi-coding-agent 17.1.6 → 17.1.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.
Files changed (130) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/dist/{CHANGELOG-x9zt79k8.md → CHANGELOG-vt8ene9g.md} +58 -0
  3. package/dist/cli.js +4309 -7287
  4. package/dist/template-dys3vk5b.js +1671 -0
  5. package/dist/template-f8wx9vfn.css +1355 -0
  6. package/dist/template-qat058wr.html +55 -0
  7. package/dist/tool-views.generated-jdfmzwmn.js +35 -0
  8. package/dist/types/advisor/advise-tool.d.ts +0 -7
  9. package/dist/types/advisor/runtime.d.ts +0 -9
  10. package/dist/types/async/job-manager.d.ts +11 -0
  11. package/dist/types/cleanse/agent.d.ts +19 -0
  12. package/dist/types/cleanse/balance.d.ts +7 -0
  13. package/dist/types/cleanse/checkers.d.ts +13 -0
  14. package/dist/types/cleanse/index.d.ts +16 -0
  15. package/dist/types/cleanse/loop.d.ts +16 -0
  16. package/dist/types/cleanse/parsers.d.ts +13 -0
  17. package/dist/types/cleanse/progress.d.ts +14 -0
  18. package/dist/types/cleanse/types.d.ts +64 -0
  19. package/dist/types/commands/cleanse.d.ts +23 -0
  20. package/dist/types/config/settings-schema.d.ts +16 -1
  21. package/dist/types/cursor.d.ts +2 -1
  22. package/dist/types/export/html/index.d.ts +2 -0
  23. package/dist/types/extensibility/extensions/runner.d.ts +4 -0
  24. package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +27 -1
  25. package/dist/types/extensibility/shared-events.d.ts +18 -1
  26. package/dist/types/modes/components/custom-editor.d.ts +5 -0
  27. package/dist/types/modes/interactive-mode.d.ts +4 -3
  28. package/dist/types/session/agent-session-types.d.ts +5 -5
  29. package/dist/types/session/agent-session.d.ts +26 -1
  30. package/dist/types/session/async-job-delivery.d.ts +8 -0
  31. package/dist/types/session/model-controls.d.ts +4 -4
  32. package/dist/types/session/session-tools.d.ts +44 -6
  33. package/dist/types/session/streaming-output.d.ts +7 -2
  34. package/dist/types/session/turn-recovery.d.ts +1 -1
  35. package/dist/types/task/isolation-ownership.d.ts +34 -0
  36. package/dist/types/tools/browser/cmux/cmux-tab.d.ts +1 -2
  37. package/dist/types/tools/browser/tab-worker.d.ts +1 -4
  38. package/dist/types/tools/index.d.ts +8 -3
  39. package/dist/types/tools/output-meta.d.ts +5 -0
  40. package/dist/types/tools/read.d.ts +9 -1
  41. package/dist/types/tools/xdev.d.ts +53 -67
  42. package/dist/types/tui/output-block.d.ts +5 -5
  43. package/dist/types/utils/cpuprofile.d.ts +51 -0
  44. package/dist/types/utils/inspect-image-mode.d.ts +29 -0
  45. package/dist/types/utils/profile-tree.d.ts +47 -0
  46. package/dist/types/utils/sample-profile.d.ts +67 -0
  47. package/package.json +16 -12
  48. package/scripts/bundle-dist.ts +3 -1
  49. package/src/advisor/advise-tool.ts +0 -11
  50. package/src/advisor/runtime.ts +0 -12
  51. package/src/async/job-manager.ts +30 -7
  52. package/src/cleanse/agent.ts +226 -0
  53. package/src/cleanse/balance.ts +79 -0
  54. package/src/cleanse/checkers.ts +996 -0
  55. package/src/cleanse/index.ts +190 -0
  56. package/src/cleanse/loop.ts +51 -0
  57. package/src/cleanse/parsers.ts +726 -0
  58. package/src/cleanse/progress.ts +50 -0
  59. package/src/cleanse/prompts/assignment.md +47 -0
  60. package/src/cleanse/types.ts +72 -0
  61. package/src/cli/update-cli.ts +3 -0
  62. package/src/cli/usage-cli.ts +29 -4
  63. package/src/cli/worktree-cli.ts +28 -11
  64. package/src/cli-commands.ts +1 -0
  65. package/src/cli.ts +2 -1
  66. package/src/commands/cleanse.ts +45 -0
  67. package/src/config/settings-schema.ts +15 -1
  68. package/src/config/settings.ts +35 -0
  69. package/src/cursor.ts +4 -3
  70. package/src/discovery/builtin-rules/index.ts +2 -0
  71. package/src/discovery/builtin-rules/ts-no-local-is-record.md +48 -0
  72. package/src/discovery/claude-plugins.ts +144 -34
  73. package/src/export/html/index.ts +17 -10
  74. package/src/extensibility/extensions/runner.ts +26 -0
  75. package/src/extensibility/extensions/wrapper.ts +74 -42
  76. package/src/extensibility/hooks/tool-wrapper.ts +11 -4
  77. package/src/extensibility/legacy-pi-ai-shim.ts +46 -1
  78. package/src/extensibility/shared-events.ts +18 -1
  79. package/src/launch/broker.ts +14 -4
  80. package/src/modes/acp/acp-agent.ts +12 -9
  81. package/src/modes/acp/acp-event-mapper.ts +38 -4
  82. package/src/modes/components/custom-editor.ts +39 -16
  83. package/src/modes/components/settings-selector.ts +9 -1
  84. package/src/modes/components/tips.txt +2 -1
  85. package/src/modes/components/tool-execution.ts +8 -7
  86. package/src/modes/controllers/extension-ui-controller.ts +4 -4
  87. package/src/modes/controllers/selector-controller.ts +7 -2
  88. package/src/modes/interactive-mode.ts +36 -47
  89. package/src/modes/prompt-action-autocomplete.ts +5 -3
  90. package/src/prompts/goals/guided-goal-interview.md +41 -6
  91. package/src/prompts/system/vibe-mode-active.md +4 -1
  92. package/src/prompts/tools/browser.md +1 -0
  93. package/src/prompts/tools/goal.md +1 -1
  94. package/src/sdk.ts +47 -50
  95. package/src/session/agent-session-types.ts +5 -5
  96. package/src/session/agent-session.ts +151 -11
  97. package/src/session/async-job-delivery.ts +8 -0
  98. package/src/session/model-controls.ts +9 -9
  99. package/src/session/session-advisors.ts +2 -7
  100. package/src/session/session-history-format.ts +31 -6
  101. package/src/session/session-listing.ts +66 -4
  102. package/src/session/session-tools.ts +158 -52
  103. package/src/session/streaming-output.ts +18 -6
  104. package/src/session/turn-recovery.ts +4 -4
  105. package/src/slash-commands/builtin-registry.ts +74 -2
  106. package/src/task/isolation-ownership.ts +106 -0
  107. package/src/task/worktree.ts +8 -0
  108. package/src/tools/ask.ts +3 -3
  109. package/src/tools/ast-edit.ts +9 -2
  110. package/src/tools/bash.ts +16 -9
  111. package/src/tools/browser/cmux/cmux-tab.ts +9 -14
  112. package/src/tools/browser/tab-worker.ts +12 -35
  113. package/src/tools/browser.ts +2 -2
  114. package/src/tools/gh-renderer.ts +3 -3
  115. package/src/tools/index.ts +46 -17
  116. package/src/tools/output-meta.ts +20 -0
  117. package/src/tools/read.ts +87 -13
  118. package/src/tools/write.ts +51 -7
  119. package/src/tools/xdev.ts +198 -210
  120. package/src/tui/code-cell.ts +4 -4
  121. package/src/tui/output-block.ts +25 -8
  122. package/src/utils/cpuprofile.ts +235 -0
  123. package/src/utils/inspect-image-mode.ts +39 -0
  124. package/src/utils/profile-tree.ts +111 -0
  125. package/src/utils/sample-profile.ts +437 -0
  126. package/src/utils/shell-snapshot-fn-env.sh +5 -2
  127. package/src/web/search/render.ts +2 -2
  128. package/dist/types/goals/guided-setup.d.ts +0 -30
  129. package/src/goals/guided-setup.ts +0 -171
  130. package/src/prompts/goals/guided-goal-system.md +0 -33
@@ -0,0 +1,190 @@
1
+ import { getProjectDir, sanitizeText } from "@oh-my-pi/pi-utils";
2
+ import { shortenPath } from "../tools/render-utils";
3
+ import { type CleanseAgentRuntime, createCleanseAgentRuntime } from "./agent";
4
+ import { groupDiagnosticsByFile } from "./balance";
5
+ import { discoverCleanseDiagnosticSuite } from "./checkers";
6
+ import { runCleanseLoop } from "./loop";
7
+ import { createCleanseProgressReporter } from "./progress";
8
+ import type { CleanseAgentOutcome, CleanseAssignment, CleanseDiagnosticReport, CleanseLoopResult } from "./types";
9
+
10
+ const DEFAULT_MODEL = "@smol";
11
+ const DISPLAY_FILE_LIMIT = 50;
12
+
13
+ /** User-facing options for `omp cleanse`. */
14
+ export interface CleanseCommandOptions {
15
+ maxAgents?: number;
16
+ model?: string;
17
+ includeTests?: boolean;
18
+ }
19
+
20
+ /** Observable completion state returned to the CLI adapter. */
21
+ export interface CleanseCommandResult {
22
+ exitCode: number;
23
+ status: "clean" | "unresolved" | "unsupported" | "cancelled";
24
+ report: CleanseDiagnosticReport;
25
+ sessionFile?: string;
26
+ }
27
+
28
+ /** Detect project diagnostics, dispatch one bounded repair batch, and verify it. */
29
+ export async function runCleanseCommand(options: CleanseCommandOptions = {}): Promise<CleanseCommandResult> {
30
+ const maxAgents = options.maxAgents ?? 8;
31
+ if (!Number.isInteger(maxAgents) || maxAgents <= 0) throw new Error("--agents must be a positive integer");
32
+ const model = options.model?.trim() || DEFAULT_MODEL;
33
+ const cwd = getProjectDir();
34
+ const abortController = new AbortController();
35
+ const abort = (): void => abortController.abort(new Error("Cleanse interrupted"));
36
+ process.once("SIGINT", abort);
37
+ process.once("SIGTERM", abort);
38
+ let runtime: CleanseAgentRuntime | undefined;
39
+ let loopResult: CleanseLoopResult | undefined;
40
+ const progress = createCleanseProgressReporter();
41
+ const interactiveFailures: CleanseAgentOutcome[] = [];
42
+ let interactiveFailuresPrinted = false;
43
+ const printInteractiveFailures = (): void => {
44
+ if (!progress.interactive || interactiveFailuresPrinted) return;
45
+ interactiveFailuresPrinted = true;
46
+ for (const outcome of interactiveFailures) printAgentOutcome(outcome);
47
+ };
48
+
49
+ try {
50
+ process.stdout.write("Detecting configured project checkers...\n");
51
+ const suite = await discoverCleanseDiagnosticSuite(cwd, { includeTests: options.includeTests });
52
+ if (suite.checkCount === 0) {
53
+ const report: CleanseDiagnosticReport = { checks: [], diagnostics: [], skipped: [...suite.skipped] };
54
+ printSkippedChecks(report);
55
+ process.stderr.write("No supported checker with an available executable was found.\n");
56
+ return { exitCode: 1, status: "unsupported", report };
57
+ }
58
+ const initialReport = await suite.run(abortController.signal);
59
+ printCheckReport(initialReport);
60
+ if (initialReport.diagnostics.length === 0) {
61
+ process.stdout.write(
62
+ `Clean: ${initialReport.checks.length} checker${initialReport.checks.length === 1 ? "" : "s"} passed.\n`,
63
+ );
64
+ return { exitCode: 0, status: "clean", report: initialReport };
65
+ }
66
+
67
+ const assignments = groupDiagnosticsByFile(initialReport.diagnostics);
68
+ const agentCount = Math.min(maxAgents, assignments.length);
69
+ const fileCount = assignments.filter(group => group.file !== undefined).length;
70
+ process.stdout.write(
71
+ `Found ${initialReport.diagnostics.length} diagnostic${initialReport.diagnostics.length === 1 ? "" : "s"} across ${fileCount} file${fileCount === 1 ? "" : "s"}; launching ${agentCount} subagent${agentCount === 1 ? "" : "s"}.\n`,
72
+ );
73
+ process.stdout.write(`Resolving model ${model}...\n`);
74
+ const activeRuntime = await createCleanseAgentRuntime({
75
+ cwd,
76
+ model,
77
+ hooks: {
78
+ onStart(name, assignment) {
79
+ if (progress.interactive) return;
80
+ process.stdout.write(
81
+ `[start] ${name}: ${formatAssignmentFiles(assignment)} (weight ${assignment.weight})\n`,
82
+ );
83
+ },
84
+ onFinish(outcome) {
85
+ progress.complete();
86
+ if (progress.interactive) {
87
+ if (!outcome.success) interactiveFailures.push(outcome);
88
+ return;
89
+ }
90
+ printAgentOutcome(outcome);
91
+ },
92
+ },
93
+ });
94
+ runtime = activeRuntime;
95
+ process.stdout.write(`Model: ${activeRuntime.model}\nSession: ${shortenPath(activeRuntime.sessionFile)}\n`);
96
+ loopResult = await runCleanseLoop(
97
+ { maxAgents, initialReport, signal: abortController.signal },
98
+ {
99
+ collect: signal => suite.run(signal),
100
+ dispatch: (batch, wave, report, signal) => activeRuntime.dispatch(batch, wave, report, signal),
101
+ onWave(_wave, batch) {
102
+ process.stdout.write(
103
+ `Dispatching ${batch.length} weighted assignment${batch.length === 1 ? "" : "s"}...\n`,
104
+ );
105
+ progress.start(batch.length);
106
+ },
107
+ onReport(_wave, report) {
108
+ progress.finish();
109
+ printInteractiveFailures();
110
+ process.stdout.write(
111
+ `Verification: ${report.diagnostics.length} diagnostic${report.diagnostics.length === 1 ? "" : "s"} remaining.\n`,
112
+ );
113
+ },
114
+ },
115
+ );
116
+ progress.finish();
117
+ printInteractiveFailures();
118
+ await activeRuntime.close(loopResult);
119
+ if (loopResult.status === "cancelled") {
120
+ process.stderr.write("Cleanse cancelled.\n");
121
+ return {
122
+ exitCode: 130,
123
+ status: "cancelled",
124
+ report: loopResult.report,
125
+ sessionFile: activeRuntime.sessionFile,
126
+ };
127
+ }
128
+ if (loopResult.status === "clean") {
129
+ process.stdout.write("Clean: all detected diagnostics are resolved.\n");
130
+ return { exitCode: 0, status: "clean", report: loopResult.report, sessionFile: activeRuntime.sessionFile };
131
+ }
132
+ printRemaining(loopResult.report);
133
+ return { exitCode: 1, status: "unresolved", report: loopResult.report, sessionFile: activeRuntime.sessionFile };
134
+ } catch (error) {
135
+ if (!abortController.signal.aborted) throw error;
136
+ const report: CleanseDiagnosticReport = loopResult?.report ?? { checks: [], diagnostics: [], skipped: [] };
137
+ progress.finish();
138
+ printInteractiveFailures();
139
+ process.stderr.write("Cleanse cancelled.\n");
140
+ return { exitCode: 130, status: "cancelled", report, sessionFile: runtime?.sessionFile };
141
+ } finally {
142
+ progress.finish();
143
+ printInteractiveFailures();
144
+ process.off("SIGINT", abort);
145
+ process.off("SIGTERM", abort);
146
+ await runtime?.close(loopResult);
147
+ }
148
+ }
149
+
150
+ function printAgentOutcome(outcome: CleanseAgentOutcome): void {
151
+ if (outcome.success) {
152
+ process.stdout.write(`[done] ${outcome.name}${outcome.resolvedModel ? ` (${outcome.resolvedModel})` : ""}\n`);
153
+ return;
154
+ }
155
+ const error = sanitizeText(outcome.error ?? "subagent failed")
156
+ .replace(/\s+/g, " ")
157
+ .slice(0, 300);
158
+ process.stderr.write(`[fail] ${outcome.name}: ${error}\n`);
159
+ }
160
+
161
+ function printCheckReport(report: CleanseDiagnosticReport): void {
162
+ for (const check of report.checks) {
163
+ const count = check.diagnostics.length;
164
+ process.stdout.write(`- ${check.label}: ${count === 0 ? "clean" : `${count} issue${count === 1 ? "" : "s"}`}\n`);
165
+ }
166
+ printSkippedChecks(report);
167
+ }
168
+
169
+ function printSkippedChecks(report: CleanseDiagnosticReport): void {
170
+ for (const skipped of report.skipped) {
171
+ process.stdout.write(`- ${skipped.label}: skipped (${skipped.reason})\n`);
172
+ }
173
+ }
174
+
175
+ function formatAssignmentFiles(assignment: CleanseAssignment): string {
176
+ return assignment.groups.map(group => group.file ?? "<project>").join(", ");
177
+ }
178
+
179
+ function printRemaining(report: CleanseDiagnosticReport): void {
180
+ const groups = groupDiagnosticsByFile(report.diagnostics);
181
+ process.stderr.write(
182
+ `Unresolved: ${report.diagnostics.length} diagnostic${report.diagnostics.length === 1 ? "" : "s"}.\n`,
183
+ );
184
+ for (const group of groups.slice(0, DISPLAY_FILE_LIMIT)) {
185
+ process.stderr.write(`- ${group.file ?? "<project>"}: ${group.diagnostics.length}\n`);
186
+ }
187
+ if (groups.length > DISPLAY_FILE_LIMIT) {
188
+ process.stderr.write(`- ... ${groups.length - DISPLAY_FILE_LIMIT} more files\n`);
189
+ }
190
+ }
@@ -0,0 +1,51 @@
1
+ import { balanceDiagnostics } from "./balance";
2
+ import type { CleanseAgentOutcome, CleanseAssignment, CleanseDiagnosticReport, CleanseLoopResult } from "./types";
3
+
4
+ /** Runtime seams for one bounded diagnose, dispatch, and verify pass. */
5
+ export interface CleanseLoopDependencies {
6
+ collect(signal?: AbortSignal): Promise<CleanseDiagnosticReport>;
7
+ dispatch(
8
+ assignments: CleanseAssignment[],
9
+ wave: number,
10
+ report: CleanseDiagnosticReport,
11
+ signal?: AbortSignal,
12
+ ): Promise<CleanseAgentOutcome[]>;
13
+ onWave?(wave: number, assignments: readonly CleanseAssignment[]): void;
14
+ onReport?(wave: number, report: CleanseDiagnosticReport): void;
15
+ }
16
+
17
+ /** Inputs controlling one complete cleanse loop. */
18
+ export interface CleanseLoopOptions {
19
+ maxAgents: number;
20
+ initialReport: CleanseDiagnosticReport;
21
+ signal?: AbortSignal;
22
+ }
23
+
24
+ /** Dispatch at most `maxAgents` workers once, then verify their combined edits. */
25
+ export async function runCleanseLoop(
26
+ options: CleanseLoopOptions,
27
+ dependencies: CleanseLoopDependencies,
28
+ ): Promise<CleanseLoopResult> {
29
+ const initialReport = options.initialReport;
30
+ if (initialReport.diagnostics.length === 0) {
31
+ return { status: "clean", waves: 0, report: initialReport, outcomes: [] };
32
+ }
33
+ if (options.signal?.aborted) {
34
+ return { status: "cancelled", waves: 0, report: initialReport, outcomes: [] };
35
+ }
36
+ const wave = 1;
37
+ const assignments = balanceDiagnostics(initialReport.diagnostics, options.maxAgents);
38
+ dependencies.onWave?.(wave, assignments);
39
+ const outcomes = await dependencies.dispatch(assignments, wave, initialReport, options.signal);
40
+ if (options.signal?.aborted) {
41
+ return { status: "cancelled", waves: 1, report: initialReport, outcomes };
42
+ }
43
+ const report = await dependencies.collect(options.signal);
44
+ dependencies.onReport?.(wave, report);
45
+ return {
46
+ status: report.diagnostics.length === 0 ? "clean" : "stalled",
47
+ waves: 1,
48
+ report,
49
+ outcomes,
50
+ };
51
+ }