@oh-my-pi/pi-coding-agent 17.0.1 → 17.0.3

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 (179) hide show
  1. package/CHANGELOG.md +162 -40
  2. package/dist/cli.js +4559 -4543
  3. package/dist/types/advisor/config.d.ts +14 -6
  4. package/dist/types/advisor/runtime.d.ts +20 -11
  5. package/dist/types/autolearn/controller.d.ts +1 -0
  6. package/dist/types/config/model-discovery.d.ts +17 -0
  7. package/dist/types/config/model-resolver.d.ts +6 -2
  8. package/dist/types/config/settings-schema.d.ts +39 -10
  9. package/dist/types/config/settings.d.ts +50 -0
  10. package/dist/types/cursor.d.ts +11 -0
  11. package/dist/types/discovery/helpers.d.ts +5 -2
  12. package/dist/types/eval/agent-bridge.d.ts +7 -19
  13. package/dist/types/exec/bash-executor.d.ts +2 -0
  14. package/dist/types/extensibility/extensions/managed-timers.d.ts +15 -0
  15. package/dist/types/extensibility/extensions/runner.d.ts +7 -0
  16. package/dist/types/extensibility/extensions/types.d.ts +18 -0
  17. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +55 -1
  18. package/dist/types/extensibility/shared-events.d.ts +6 -0
  19. package/dist/types/extensibility/utils.d.ts +2 -2
  20. package/dist/types/lsp/client.d.ts +2 -0
  21. package/dist/types/lsp/types.d.ts +3 -0
  22. package/dist/types/mcp/transports/stdio.d.ts +42 -1
  23. package/dist/types/modes/components/advisor-config.d.ts +8 -1
  24. package/dist/types/modes/components/agent-hub.d.ts +15 -0
  25. package/dist/types/modes/components/hook-editor.d.ts +7 -0
  26. package/dist/types/modes/components/model-hub.d.ts +5 -2
  27. package/dist/types/modes/components/session-selector.d.ts +2 -0
  28. package/dist/types/modes/controllers/command-controller.d.ts +8 -0
  29. package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
  30. package/dist/types/modes/print-mode.d.ts +1 -1
  31. package/dist/types/modes/warp-events.d.ts +24 -0
  32. package/dist/types/modes/warp-events.test.d.ts +1 -0
  33. package/dist/types/plan-mode/model-transition.d.ts +47 -0
  34. package/dist/types/plan-mode/model-transition.test.d.ts +1 -0
  35. package/dist/types/registry/agent-lifecycle.d.ts +26 -1
  36. package/dist/types/registry/persisted-agents.d.ts +3 -0
  37. package/dist/types/sdk.d.ts +27 -5
  38. package/dist/types/session/agent-session.d.ts +34 -10
  39. package/dist/types/session/session-entries.d.ts +6 -1
  40. package/dist/types/session/session-history-format.d.ts +10 -0
  41. package/dist/types/session/session-manager.d.ts +19 -0
  42. package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +9 -0
  43. package/dist/types/task/executor.d.ts +26 -1
  44. package/dist/types/task/index.d.ts +1 -1
  45. package/dist/types/task/label.d.ts +1 -1
  46. package/dist/types/task/parallel.d.ts +14 -0
  47. package/dist/types/task/structured-subagent.d.ts +111 -0
  48. package/dist/types/task/types.d.ts +51 -0
  49. package/dist/types/telemetry-export.d.ts +34 -9
  50. package/dist/types/tools/approval.d.ts +8 -0
  51. package/dist/types/tools/bash.d.ts +2 -0
  52. package/dist/types/tools/essential-tools.d.ts +29 -0
  53. package/dist/types/tools/fetch.d.ts +4 -5
  54. package/dist/types/tools/hub/messaging.d.ts +5 -1
  55. package/dist/types/tools/image-gen.d.ts +2 -1
  56. package/dist/types/tools/index.d.ts +17 -1
  57. package/dist/types/tools/todo.d.ts +31 -0
  58. package/dist/types/tools/xdev.d.ts +11 -2
  59. package/dist/types/tui/tree-list.d.ts +7 -0
  60. package/dist/types/utils/markit.d.ts +11 -0
  61. package/dist/types/utils/title-generator.d.ts +2 -1
  62. package/dist/types/web/search/providers/kimi.d.ts +4 -1
  63. package/dist/types/web/search/types.d.ts +1 -1
  64. package/package.json +21 -16
  65. package/src/advisor/__tests__/advisor.test.ts +1304 -42
  66. package/src/advisor/__tests__/config.test.ts +58 -2
  67. package/src/advisor/config.ts +76 -24
  68. package/src/advisor/runtime.ts +445 -92
  69. package/src/autolearn/controller.ts +23 -28
  70. package/src/cli/file-processor.ts +1 -2
  71. package/src/cli.ts +5 -1
  72. package/src/config/model-discovery.ts +81 -21
  73. package/src/config/model-registry.ts +25 -6
  74. package/src/config/model-resolver.ts +14 -7
  75. package/src/config/settings-schema.ts +46 -9
  76. package/src/config/settings.ts +405 -25
  77. package/src/cursor.ts +20 -3
  78. package/src/debug/report-bundle.ts +40 -4
  79. package/src/discovery/helpers.ts +28 -5
  80. package/src/eval/__tests__/agent-bridge.test.ts +133 -47
  81. package/src/eval/__tests__/prelude-agent.test.ts +29 -0
  82. package/src/eval/agent-bridge.ts +104 -477
  83. package/src/eval/jl/prelude.jl +7 -6
  84. package/src/eval/js/shared/prelude.txt +5 -4
  85. package/src/eval/py/prelude.py +11 -39
  86. package/src/eval/rb/prelude.rb +5 -6
  87. package/src/exec/bash-executor.ts +14 -5
  88. package/src/extensibility/custom-tools/loader.ts +3 -3
  89. package/src/extensibility/custom-tools/wrapper.ts +2 -1
  90. package/src/extensibility/extensions/loader.ts +3 -3
  91. package/src/extensibility/extensions/managed-timers.ts +83 -0
  92. package/src/extensibility/extensions/runner.ts +26 -0
  93. package/src/extensibility/extensions/types.ts +18 -0
  94. package/src/extensibility/extensions/wrapper.ts +2 -1
  95. package/src/extensibility/hooks/loader.ts +3 -3
  96. package/src/extensibility/legacy-pi-coding-agent-shim.ts +149 -8
  97. package/src/extensibility/plugins/legacy-pi-compat.ts +225 -22
  98. package/src/extensibility/plugins/manager.ts +2 -2
  99. package/src/extensibility/shared-events.ts +6 -0
  100. package/src/extensibility/utils.ts +91 -25
  101. package/src/irc/bus.ts +22 -3
  102. package/src/launch/broker.ts +3 -2
  103. package/src/launch/client.ts +2 -2
  104. package/src/launch/presence.ts +2 -2
  105. package/src/lsp/client.ts +58 -1
  106. package/src/lsp/index.ts +62 -6
  107. package/src/lsp/types.ts +3 -0
  108. package/src/main.ts +11 -8
  109. package/src/mcp/manager.ts +9 -3
  110. package/src/mcp/oauth-flow.ts +20 -0
  111. package/src/mcp/transports/stdio.test.ts +269 -1
  112. package/src/mcp/transports/stdio.ts +255 -24
  113. package/src/modes/components/advisor-config.ts +65 -3
  114. package/src/modes/components/agent-hub.ts +1 -72
  115. package/src/modes/components/ask-dialog.ts +1 -1
  116. package/src/modes/components/bash-execution.ts +7 -3
  117. package/src/modes/components/eval-execution.ts +3 -1
  118. package/src/modes/components/hook-editor.ts +18 -3
  119. package/src/modes/components/model-hub.ts +138 -42
  120. package/src/modes/components/session-selector.ts +4 -0
  121. package/src/modes/components/status-line/component.test.ts +1 -0
  122. package/src/modes/components/status-line/segments.ts +21 -6
  123. package/src/modes/controllers/command-controller.ts +167 -47
  124. package/src/modes/controllers/event-controller.ts +5 -0
  125. package/src/modes/controllers/extension-ui-controller.ts +4 -22
  126. package/src/modes/controllers/input-controller.ts +12 -12
  127. package/src/modes/controllers/selector-controller.ts +191 -31
  128. package/src/modes/interactive-mode.ts +169 -62
  129. package/src/modes/print-mode.ts +3 -3
  130. package/src/modes/rpc/host-tools.ts +2 -1
  131. package/src/modes/rpc/rpc-mode.ts +19 -4
  132. package/src/modes/warp-events.test.ts +794 -0
  133. package/src/modes/warp-events.ts +232 -0
  134. package/src/plan-mode/model-transition.test.ts +60 -0
  135. package/src/plan-mode/model-transition.ts +51 -0
  136. package/src/prompts/system/system-prompt.md +1 -1
  137. package/src/prompts/tools/eval.md +5 -2
  138. package/src/prompts/tools/read.md +1 -1
  139. package/src/prompts/tools/task.md +12 -8
  140. package/src/prompts/tools/write.md +1 -1
  141. package/src/registry/agent-lifecycle.ts +133 -18
  142. package/src/registry/persisted-agents.ts +74 -0
  143. package/src/sdk.ts +343 -122
  144. package/src/session/agent-session.ts +1359 -368
  145. package/src/session/session-entries.ts +6 -1
  146. package/src/session/session-history-format.ts +20 -5
  147. package/src/session/session-manager.ts +57 -0
  148. package/src/session/streaming-output.ts +41 -1
  149. package/src/slash-commands/builtin-registry.ts +7 -0
  150. package/src/slash-commands/helpers/active-oauth-account.ts +16 -0
  151. package/src/system-prompt.ts +7 -2
  152. package/src/task/executor.ts +100 -22
  153. package/src/task/index.ts +258 -429
  154. package/src/task/label.ts +2 -0
  155. package/src/task/parallel.ts +43 -0
  156. package/src/task/persisted-revive.ts +19 -7
  157. package/src/task/structured-subagent.ts +642 -0
  158. package/src/task/types.ts +58 -0
  159. package/src/telemetry-export.ts +453 -97
  160. package/src/tools/__tests__/eval-description.test.ts +1 -1
  161. package/src/tools/approval.ts +11 -0
  162. package/src/tools/bash.ts +71 -38
  163. package/src/tools/essential-tools.ts +45 -0
  164. package/src/tools/fetch.ts +28 -105
  165. package/src/tools/gh.ts +169 -2
  166. package/src/tools/hub/messaging.ts +16 -3
  167. package/src/tools/image-gen.ts +69 -7
  168. package/src/tools/index.ts +50 -15
  169. package/src/tools/path-utils.ts +1 -0
  170. package/src/tools/read.ts +62 -29
  171. package/src/tools/todo.ts +126 -13
  172. package/src/tools/write.ts +22 -4
  173. package/src/tools/xdev.ts +14 -3
  174. package/src/tui/tree-list.ts +39 -0
  175. package/src/utils/markit.ts +12 -0
  176. package/src/utils/title-generator.ts +15 -4
  177. package/src/utils/zip.ts +16 -1
  178. package/src/web/search/providers/kimi.ts +18 -12
  179. package/src/web/search/types.ts +6 -1
@@ -201,9 +201,13 @@ describe("WATCHDOG.yml file round-trip", () => {
201
201
  });
202
202
 
203
203
  const doc: WatchdogConfigDoc = {
204
- instructions: 'Shared baseline.\nSecond line with: a colon and "quotes".',
204
+ instructions: 'Shared baseline.\n\nSecond line with: a colon and "quotes".',
205
205
  advisors: [
206
- { name: "Architecture", model: "x-ai/grok-code-fast:high", instructions: "Watch module boundaries." },
206
+ {
207
+ name: "Architecture",
208
+ model: "x-ai/grok-code-fast:high",
209
+ instructions: "Watch module boundaries.\nReport coupling.",
210
+ },
207
211
  { name: "Security", tools: ["read", "grep"] },
208
212
  ],
209
213
  };
@@ -222,11 +226,25 @@ describe("WATCHDOG.yml file round-trip", () => {
222
226
  // Block style (not the flow `{...}` form), so it stays hand-editable.
223
227
  expect(text).toContain("advisors:");
224
228
  expect(text).not.toMatch(/^\{/);
229
+ expect(text).toContain('instructions: |2-\n Shared baseline.\n \n Second line with: a colon and "quotes".');
230
+ expect(text).toContain(" instructions: |2-\n Watch module boundaries.\n Report coupling.");
231
+ expect(text).not.toContain("\\n");
225
232
  const { advisors, sharedInstructions } = await discoverAdvisorConfigs(tmp, tmp);
226
233
  expect(advisors.map(a => a.name)).toEqual(["Architecture", "Security"]);
227
234
  expect(sharedInstructions).toContain("Shared baseline.");
228
235
  });
229
236
 
237
+ it("preserves significant leading whitespace and trailing newlines in block scalars", async () => {
238
+ const file = path.join(tmp, "WATCHDOG.yml");
239
+ const whitespaceDoc: WatchdogConfigDoc = {
240
+ instructions: " indented first line\nplain second line\n\n",
241
+ advisors: [{ name: "Whitespace", instructions: "\n indented after blank\nplain" }],
242
+ };
243
+
244
+ await saveWatchdogConfigFile(file, whitespaceDoc);
245
+ expect(await loadWatchdogConfigFile(file)).toEqual(whitespaceDoc);
246
+ });
247
+
230
248
  it("round-trips an explicit empty tools list without collapsing it into the default", async () => {
231
249
  const file = path.join(tmp, "WATCHDOG.yml");
232
250
  const explicitNoToolsDoc: WatchdogConfigDoc = {
@@ -291,3 +309,41 @@ describe("resolveAdvisorConfigEditPath", () => {
291
309
  expect(await resolveAdvisorConfigEditPath("project", dirs(tmp))).toBe(path.join(tmp, "WATCHDOG.yml"));
292
310
  });
293
311
  });
312
+
313
+ describe("per-advisor enabled field", () => {
314
+ it("preserves explicit true, explicit false, and absence through save and discovery", async () => {
315
+ const tmp = await fsp.mkdtemp(path.join(os.tmpdir(), "omp-advisor-enabled-"));
316
+ try {
317
+ const doc: WatchdogConfigDoc = {
318
+ advisors: [
319
+ { name: "Explicit On", model: "test/model-a", enabled: true },
320
+ { name: "Explicit Off", model: "test/model-b", enabled: false },
321
+ { name: "Default", model: "test/model-c" },
322
+ ],
323
+ };
324
+ const file = path.join(tmp, "WATCHDOG.yml");
325
+ await saveWatchdogConfigFile(file, doc);
326
+
327
+ const loaded = await loadWatchdogConfigFile(file);
328
+ expect(loaded.advisors.map(advisor => advisor.enabled)).toEqual([true, false, undefined]);
329
+
330
+ const { advisors } = await discoverAdvisorConfigs(tmp, tmp);
331
+ expect(advisors.map(advisor => advisor.enabled)).toEqual([true, false, undefined]);
332
+ } finally {
333
+ await fsp.rm(tmp, { recursive: true, force: true });
334
+ }
335
+ });
336
+
337
+ it("emits explicit boolean values but omits an absent enabled field", () => {
338
+ const text = serializeWatchdogConfig({
339
+ advisors: [
340
+ { name: "Explicit On", enabled: true },
341
+ { name: "Explicit Off", enabled: false },
342
+ { name: "Default" },
343
+ ],
344
+ });
345
+ expect(text).toContain("enabled: true");
346
+ expect(text).toContain("enabled: false");
347
+ expect(text.match(/enabled:/g)).toHaveLength(2);
348
+ });
349
+ });
@@ -22,8 +22,23 @@ export interface AdvisorConfig {
22
22
  model?: string;
23
23
  tools?: string[];
24
24
  instructions?: string;
25
+ /** Per-advisor on/off toggle (default `true`). When `false`, the advisor
26
+ * stays in the roster but its runtime is never built — it shows `○` in
27
+ * the status line and `/advisor status` rather than disappearing. */
28
+ enabled?: boolean;
25
29
  }
26
30
 
31
+ /**
32
+ * Runtime health of a single advisor, surfaced in stats and the status line.
33
+ * - `running` — actively processing primary turns
34
+ * - `paused` — user-toggled off via per-advisor switch (runtime disposed)
35
+ * - `quota_exhausted` — provider returned a quota/rate-limit error; the
36
+ * runtime auto-retries after a cooldown so it can resume without user action
37
+ * - `error` — repeated transient failures; backlog dropped to prevent stall
38
+ * - `no_model` — no model resolved for this advisor's role/explicit model
39
+ */
40
+ export type AdvisorRuntimeStatus = "running" | "paused" | "quota_exhausted" | "error" | "no_model";
41
+
27
42
  /**
28
43
  * The result of walking the `WATCHDOG.yml`/`WATCHDOG.yaml` search path: the
29
44
  * deduped advisor roster plus the concatenated top-level `instructions` baseline
@@ -39,6 +54,7 @@ const advisorEntrySchema = type({
39
54
  "model?": "string",
40
55
  "tools?": "string[]",
41
56
  "instructions?": "string",
57
+ "enabled?": "boolean",
42
58
  });
43
59
 
44
60
  const watchdogYamlSchema = type({
@@ -156,6 +172,7 @@ export async function discoverAdvisorConfigs(cwd: string, agentDir?: string): Pr
156
172
  model: entry.model?.trim() || undefined,
157
173
  tools: filterAdvisorTools(entry.tools, item.path),
158
174
  instructions,
175
+ enabled: entry.enabled,
159
176
  });
160
177
  }
161
178
  }
@@ -236,38 +253,73 @@ export async function loadWatchdogConfigFile(filePath: string): Promise<Watchdog
236
253
  logger.warn("Advisor config: invalid schema for edit", { path: filePath, error: result.summary });
237
254
  return { advisors: [] };
238
255
  }
239
- return {
240
- instructions: result.instructions?.trim() ? result.instructions : undefined,
241
- advisors: (result.advisors ?? []).map(a => ({
242
- name: a.name,
243
- model: a.model?.trim() || undefined,
244
- tools: a.tools === undefined ? undefined : [...a.tools],
245
- instructions: a.instructions?.trim() ? a.instructions : undefined,
246
- })),
247
- };
256
+ const advisors = (result.advisors ?? []).map(a => {
257
+ const advisor: AdvisorConfig = { name: a.name };
258
+ if (a.model?.trim()) advisor.model = a.model;
259
+ if (a.tools !== undefined) advisor.tools = [...a.tools];
260
+ if (a.instructions?.trim()) advisor.instructions = a.instructions;
261
+ if (a.enabled !== undefined) advisor.enabled = a.enabled;
262
+ return advisor;
263
+ });
264
+ const doc: WatchdogConfigDoc = { advisors };
265
+ if (result.instructions?.trim()) doc.instructions = result.instructions;
266
+ return doc;
248
267
  }
249
268
 
250
269
  /**
251
- * Serialize an editable doc back to block-style `WATCHDOG.yml` text via Bun's
252
- * `YAML.stringify` (the same API the repo uses for other hand-editable config),
253
- * omitting empty fields. Round-trips through {@link loadWatchdogConfigFile}.
270
+ * Serialize an editable doc back to canonical, hand-editable `WATCHDOG.yml`.
271
+ * Multiline instruction fields use literal block scalars while scalar quoting
272
+ * delegates to Bun's YAML encoder. Round-trips through {@link loadWatchdogConfigFile}.
254
273
  * Returns `""` for an empty doc.
255
274
  */
275
+
276
+ function appendYamlString(lines: string[], indent: string, key: string, value: string): void {
277
+ const hasSignificantLeadingWhitespace = value.split("\n").some(line => /^[ \t]/.test(line));
278
+ if (!value.includes("\n") || hasSignificantLeadingWhitespace) {
279
+ lines.push(`${indent}${key}: ${YAML.stringify(value)}`);
280
+ return;
281
+ }
282
+ const normalized = value.replaceAll("\r\n", "\n");
283
+ let trailingNewlines = 0;
284
+ for (let index = normalized.length - 1; index >= 0 && normalized[index] === "\n"; index--) {
285
+ trailingNewlines++;
286
+ }
287
+ const chomp = trailingNewlines === 0 ? "|2-" : trailingNewlines === 1 ? "|2" : "|2+";
288
+ const body = trailingNewlines === 0 ? normalized : normalized.slice(0, -trailingNewlines);
289
+ lines.push(`${indent}${key}: ${chomp}`);
290
+ for (const line of body.split("\n")) {
291
+ lines.push(`${indent} ${line}`);
292
+ }
293
+ for (let index = 1; index < trailingNewlines; index++) {
294
+ lines.push(`${indent} `);
295
+ }
296
+ }
297
+
256
298
  export function serializeWatchdogConfig(doc: WatchdogConfigDoc): string {
257
- const out: { instructions?: string; advisors?: AdvisorConfig[] } = {};
258
- if (doc.instructions?.trim()) out.instructions = doc.instructions;
299
+ const lines: string[] = [];
300
+ if (doc.instructions?.trim()) appendYamlString(lines, "", "instructions", doc.instructions);
259
301
  if (doc.advisors.length > 0) {
260
- out.advisors = doc.advisors.map(a => {
261
- const entry: AdvisorConfig = { name: a.name };
262
- if (a.model?.trim()) entry.model = a.model;
263
- if (a.tools !== undefined) entry.tools = [...a.tools];
264
- if (a.instructions?.trim()) entry.instructions = a.instructions;
265
- return entry;
266
- });
302
+ lines.push("advisors:");
303
+ for (const advisor of doc.advisors) {
304
+ lines.push(` - name: ${YAML.stringify(advisor.name)}`);
305
+ if (advisor.model?.trim()) lines.push(` model: ${YAML.stringify(advisor.model)}`);
306
+ if (advisor.tools !== undefined) {
307
+ if (advisor.tools.length === 0) {
308
+ lines.push(" tools: []");
309
+ } else {
310
+ lines.push(" tools:");
311
+ for (const tool of advisor.tools) {
312
+ lines.push(` - ${YAML.stringify(tool)}`);
313
+ }
314
+ }
315
+ }
316
+ if (advisor.instructions?.trim()) {
317
+ appendYamlString(lines, " ", "instructions", advisor.instructions);
318
+ }
319
+ if (advisor.enabled !== undefined) lines.push(` enabled: ${advisor.enabled}`);
320
+ }
267
321
  }
268
- if (out.instructions === undefined && out.advisors === undefined) return "";
269
- const text = YAML.stringify(out, null, 2);
270
- return text.endsWith("\n") ? text : `${text}\n`;
322
+ return lines.length === 0 ? "" : `${lines.join("\n")}\n`;
271
323
  }
272
324
 
273
325
  /**