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

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 (126) hide show
  1. package/CHANGELOG.md +92 -20
  2. package/dist/cli.js +3485 -3448
  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 +32 -7
  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/exec/bash-executor.d.ts +2 -0
  13. package/dist/types/extensibility/extensions/managed-timers.d.ts +15 -0
  14. package/dist/types/extensibility/extensions/runner.d.ts +7 -0
  15. package/dist/types/extensibility/extensions/types.d.ts +18 -0
  16. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +40 -0
  17. package/dist/types/extensibility/shared-events.d.ts +6 -0
  18. package/dist/types/extensibility/utils.d.ts +2 -2
  19. package/dist/types/mcp/transports/stdio.d.ts +13 -1
  20. package/dist/types/modes/components/advisor-config.d.ts +8 -1
  21. package/dist/types/modes/components/hook-editor.d.ts +7 -0
  22. package/dist/types/modes/components/model-hub.d.ts +5 -2
  23. package/dist/types/modes/components/session-selector.d.ts +2 -0
  24. package/dist/types/modes/controllers/command-controller.d.ts +8 -0
  25. package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
  26. package/dist/types/modes/print-mode.d.ts +1 -1
  27. package/dist/types/modes/warp-events.d.ts +24 -0
  28. package/dist/types/modes/warp-events.test.d.ts +1 -0
  29. package/dist/types/plan-mode/model-transition.d.ts +47 -0
  30. package/dist/types/plan-mode/model-transition.test.d.ts +1 -0
  31. package/dist/types/registry/agent-lifecycle.d.ts +26 -1
  32. package/dist/types/sdk.d.ts +13 -2
  33. package/dist/types/session/agent-session.d.ts +34 -10
  34. package/dist/types/session/session-history-format.d.ts +10 -0
  35. package/dist/types/session/session-manager.d.ts +14 -0
  36. package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +9 -0
  37. package/dist/types/task/label.d.ts +1 -1
  38. package/dist/types/telemetry-export.d.ts +34 -9
  39. package/dist/types/tools/approval.d.ts +8 -0
  40. package/dist/types/tools/bash.d.ts +2 -0
  41. package/dist/types/tools/essential-tools.d.ts +29 -0
  42. package/dist/types/tools/image-gen.d.ts +2 -1
  43. package/dist/types/tools/index.d.ts +1 -0
  44. package/dist/types/tools/xdev.d.ts +11 -2
  45. package/dist/types/utils/title-generator.d.ts +2 -1
  46. package/dist/types/web/search/providers/kimi.d.ts +4 -1
  47. package/dist/types/web/search/types.d.ts +1 -1
  48. package/package.json +21 -16
  49. package/src/advisor/__tests__/advisor.test.ts +1304 -42
  50. package/src/advisor/__tests__/config.test.ts +58 -2
  51. package/src/advisor/config.ts +76 -24
  52. package/src/advisor/runtime.ts +445 -92
  53. package/src/autolearn/controller.ts +23 -28
  54. package/src/cli.ts +5 -1
  55. package/src/config/model-discovery.ts +81 -21
  56. package/src/config/model-registry.ts +25 -6
  57. package/src/config/model-resolver.ts +14 -7
  58. package/src/config/settings-schema.ts +42 -6
  59. package/src/config/settings.ts +405 -25
  60. package/src/cursor.ts +20 -3
  61. package/src/debug/report-bundle.ts +40 -4
  62. package/src/discovery/helpers.ts +28 -5
  63. package/src/exec/bash-executor.ts +14 -5
  64. package/src/extensibility/custom-tools/loader.ts +3 -3
  65. package/src/extensibility/custom-tools/wrapper.ts +2 -1
  66. package/src/extensibility/extensions/loader.ts +3 -3
  67. package/src/extensibility/extensions/managed-timers.ts +83 -0
  68. package/src/extensibility/extensions/runner.ts +26 -0
  69. package/src/extensibility/extensions/types.ts +18 -0
  70. package/src/extensibility/extensions/wrapper.ts +2 -1
  71. package/src/extensibility/hooks/loader.ts +3 -3
  72. package/src/extensibility/legacy-pi-coding-agent-shim.ts +96 -1
  73. package/src/extensibility/plugins/legacy-pi-compat.ts +225 -22
  74. package/src/extensibility/plugins/manager.ts +2 -2
  75. package/src/extensibility/shared-events.ts +6 -0
  76. package/src/extensibility/utils.ts +91 -25
  77. package/src/irc/bus.ts +22 -3
  78. package/src/launch/broker.ts +3 -2
  79. package/src/launch/client.ts +2 -2
  80. package/src/launch/presence.ts +2 -2
  81. package/src/lsp/client.ts +1 -1
  82. package/src/main.ts +11 -8
  83. package/src/mcp/manager.ts +9 -3
  84. package/src/mcp/transports/stdio.ts +103 -23
  85. package/src/modes/components/advisor-config.ts +65 -3
  86. package/src/modes/components/ask-dialog.ts +1 -1
  87. package/src/modes/components/hook-editor.ts +18 -3
  88. package/src/modes/components/model-hub.ts +138 -42
  89. package/src/modes/components/session-selector.ts +4 -0
  90. package/src/modes/components/status-line/component.test.ts +1 -0
  91. package/src/modes/components/status-line/segments.ts +21 -6
  92. package/src/modes/controllers/command-controller.ts +167 -47
  93. package/src/modes/controllers/event-controller.ts +5 -0
  94. package/src/modes/controllers/extension-ui-controller.ts +4 -22
  95. package/src/modes/controllers/input-controller.ts +12 -12
  96. package/src/modes/controllers/selector-controller.ts +191 -31
  97. package/src/modes/interactive-mode.ts +139 -54
  98. package/src/modes/print-mode.ts +3 -3
  99. package/src/modes/rpc/host-tools.ts +2 -1
  100. package/src/modes/rpc/rpc-mode.ts +19 -4
  101. package/src/modes/warp-events.test.ts +794 -0
  102. package/src/modes/warp-events.ts +232 -0
  103. package/src/plan-mode/model-transition.test.ts +60 -0
  104. package/src/plan-mode/model-transition.ts +51 -0
  105. package/src/registry/agent-lifecycle.ts +133 -18
  106. package/src/sdk.ts +221 -42
  107. package/src/session/agent-session.ts +1285 -348
  108. package/src/session/session-history-format.ts +20 -5
  109. package/src/session/session-manager.ts +48 -0
  110. package/src/slash-commands/builtin-registry.ts +7 -0
  111. package/src/slash-commands/helpers/active-oauth-account.ts +16 -0
  112. package/src/task/executor.ts +1 -1
  113. package/src/task/label.ts +2 -0
  114. package/src/telemetry-export.ts +453 -97
  115. package/src/tools/approval.ts +11 -0
  116. package/src/tools/bash.ts +71 -38
  117. package/src/tools/essential-tools.ts +45 -0
  118. package/src/tools/gh.ts +169 -2
  119. package/src/tools/image-gen.ts +69 -7
  120. package/src/tools/index.ts +7 -5
  121. package/src/tools/read.ts +48 -3
  122. package/src/tools/write.ts +22 -4
  123. package/src/tools/xdev.ts +14 -3
  124. package/src/utils/title-generator.ts +15 -4
  125. package/src/web/search/providers/kimi.ts +18 -12
  126. package/src/web/search/types.ts +6 -1
@@ -46,6 +46,15 @@ export interface HistoryFormatOptions {
46
46
  * this so it sees what changed without re-reading the file.
47
47
  */
48
48
  expandEditDiffs?: boolean;
49
+ /**
50
+ * Chunked rendering support: a caller formatting one logical transcript in
51
+ * several calls (the advisor's chunked delta render) passes a result index
52
+ * built over the WHOLE delta plus one shared consumed-id set, so a toolCall
53
+ * finds its toolResult across chunk boundaries and the result is never
54
+ * re-rendered as an orphan in a later chunk.
55
+ */
56
+ toolResultIndex?: ReadonlyMap<string, ToolResultMessage>;
57
+ consumedToolCallIds?: Set<string>;
49
58
  }
50
59
 
51
60
  /** Max length of the primary-arg summary inside `→ tool(...)` lines. */
@@ -273,13 +282,19 @@ export function formatSessionHistoryMarkdown(messages: unknown[], opts?: History
273
282
  }
274
283
 
275
284
  // Index tool results by call id so each toolCall collapses to one line.
276
- const resultsByCallId = new Map<string, ToolResultMessage>();
277
- for (const msg of typed) {
278
- if (msg.role === "toolResult") {
279
- resultsByCallId.set(msg.toolCallId, msg);
285
+ // Chunked callers supply a whole-delta index + shared consumed set so
286
+ // call/result pairs resolve across chunk boundaries.
287
+ let resultsByCallId = opts?.toolResultIndex;
288
+ if (!resultsByCallId) {
289
+ const local = new Map<string, ToolResultMessage>();
290
+ for (const msg of typed) {
291
+ if (msg.role === "toolResult") {
292
+ local.set(msg.toolCallId, msg);
293
+ }
280
294
  }
295
+ resultsByCallId = local;
281
296
  }
282
- const consumed = new Set<string>();
297
+ const consumed = opts?.consumedToolCallIds ?? new Set<string>();
283
298
  // In watched mode, consecutive same-role messages collapse under one label
284
299
  // (the watched agent emits one assistant message per tool call, so otherwise
285
300
  // every call repeats `**agent**:`). Cleared whenever a
@@ -935,6 +935,26 @@ export class SessionManager {
935
935
  };
936
936
  }
937
937
 
938
+ /**
939
+ * Create an independent manager for the current logical session and branch.
940
+ * The clone shares the storage backend but owns its entry index and writer, so
941
+ * callers can finish session-owned work after this manager switches elsewhere.
942
+ * Set `persist` false when the original session is intentionally being dropped.
943
+ */
944
+ cloneCurrentSession(options?: { persist?: boolean }): SessionManager {
945
+ const persist = options?.persist ?? this.#persist;
946
+ const clone = new SessionManager(this.#cwd, this.#sessionDir, persist, this.#storage);
947
+ clone.#suppressBreadcrumb = true;
948
+ clone.restoreState(this.captureState());
949
+ if (!persist) {
950
+ clone.#sessionFile = undefined;
951
+ clone.#fileIsCurrent = false;
952
+ clone.#rewriteRequired = false;
953
+ clone.#forceFileCreation = false;
954
+ }
955
+ return clone;
956
+ }
957
+
938
958
  restoreState(snapshot: SessionManagerStateSnapshot): void {
939
959
  this.#closeWriterEventually();
940
960
  this.#diskTail = Promise.resolve();
@@ -1470,6 +1490,34 @@ export class SessionManager {
1470
1490
  return entry.id;
1471
1491
  }
1472
1492
 
1493
+ /**
1494
+ * Append to a non-active branch without changing the current leaf.
1495
+ * Used by work that retains ownership of a branch across tree navigation.
1496
+ */
1497
+ appendMessageToBranch(
1498
+ message:
1499
+ | Message
1500
+ | CustomMessage
1501
+ | HookMessage
1502
+ | BashExecutionMessage
1503
+ | PythonExecutionMessage
1504
+ | FileMentionMessage,
1505
+ parentId: string | null,
1506
+ ): string {
1507
+ if (parentId !== null && !this.#index.has(parentId)) throw new Error(`Entry ${parentId} not found`);
1508
+ const activeLeafId = this.#index.leafId();
1509
+ const entry: SessionMessageEntry = {
1510
+ type: "message",
1511
+ id: generateId(this.#index),
1512
+ parentId,
1513
+ timestamp: nowIso(),
1514
+ message,
1515
+ };
1516
+ this.#recordEntry(entry);
1517
+ this.#index.setLeaf(activeLeafId);
1518
+ return entry.id;
1519
+ }
1520
+
1473
1521
  /** Append a thinking level change as child of current leaf, then advance leaf. Returns entry id. */
1474
1522
  appendThinkingLevelChange(thinkingLevel?: string, configured?: string): string {
1475
1523
  const entry: ThinkingLevelChangeEntry = {
@@ -1389,6 +1389,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1389
1389
  },
1390
1390
  {
1391
1391
  name: "new",
1392
+ aliases: ["clear"],
1392
1393
  description: "Start a new session",
1393
1394
  handleTui: async (_command, runtime) => {
1394
1395
  runtime.ctx.editor.setText("");
@@ -1704,6 +1705,11 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1704
1705
  } catch {
1705
1706
  return usage(`Directory does not exist: ${resolvedPath}`, runtime);
1706
1707
  }
1708
+ try {
1709
+ await runtime.settings.flush();
1710
+ } catch (err) {
1711
+ return usage(`Failed to save pending settings: ${errorMessage(err)}`, runtime);
1712
+ }
1707
1713
  try {
1708
1714
  await runtime.sessionManager.moveTo(resolvedPath);
1709
1715
  } catch (err) {
@@ -2320,6 +2326,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
2320
2326
  },
2321
2327
  {
2322
2328
  name: "quit",
2329
+ aliases: ["q"],
2323
2330
  description: "Quit the application",
2324
2331
  handleTui: shutdownHandlerTui,
2325
2332
  },
@@ -5,6 +5,22 @@ function normalizeIdentityValue(value: unknown): string | undefined {
5
5
  return typeof value === "string" && value.trim() ? value.trim().toLowerCase() : undefined;
6
6
  }
7
7
 
8
+ /**
9
+ * Session marker label for an active OAuth identity: the base identifier
10
+ * (email → accountId → projectId) suffixed with the organization when present
11
+ * and distinct. Same-email Anthropic multi-org accounts share the base, so the
12
+ * org suffix is the only field that tells the session's quota pool apart —
13
+ * mirrors the account-list rows (`formatUsageReportAccount`) and login success.
14
+ * Returns `undefined` when no identifier is recoverable.
15
+ */
16
+ export function formatActiveAccountLabel(identity: OAuthAccountIdentity | undefined): string | undefined {
17
+ if (!identity) return undefined;
18
+ const base = identity.email || identity.accountId || identity.projectId;
19
+ if (!base) return undefined;
20
+ const org = identity.orgName || identity.orgId;
21
+ return org && org !== base ? `${base} (${org})` : base;
22
+ }
23
+
8
24
  /**
9
25
  * True when a single usage-limit column belongs to the given OAuth identity.
10
26
  *
@@ -1052,7 +1052,7 @@ function createSubagentRunMonitor(args: RunMonitorArgs): SubagentRunMonitor {
1052
1052
  // failures just leave the label unset.
1053
1053
  const labelSource = assignment?.trim();
1054
1054
  if (!args.description && args.modelRegistry && args.settings && labelSource) {
1055
- generateTaskLabel(labelSource, args.modelRegistry, args.settings, id)
1055
+ generateTaskLabel(labelSource, args.modelRegistry, args.settings, id, abortSignal)
1056
1056
  .then(label => {
1057
1057
  if (!label || abortSignal.aborted || progress.description) return;
1058
1058
  progress.description = label;
package/src/task/label.ts CHANGED
@@ -15,6 +15,7 @@ export async function generateTaskLabel(
15
15
  registry: ModelRegistry,
16
16
  settings: Settings,
17
17
  sessionId?: string,
18
+ signal?: AbortSignal,
18
19
  ): Promise<string | null> {
19
20
  const text = assignment.trim();
20
21
  if (!text) return null;
@@ -27,6 +28,7 @@ export async function generateTaskLabel(
27
28
  undefined,
28
29
  undefined,
29
30
  TASK_LABEL_SYSTEM_PROMPT,
31
+ signal,
30
32
  );
31
33
  } catch (err) {
32
34
  logger.debug("task-label: generation failed", {