@fleetagent/pi-coding-agent 0.0.5 → 0.0.7

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 (201) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +28 -5
  3. package/dist/cli/args.d.ts +2 -0
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +9 -0
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/file-processor.d.ts.map +1 -1
  8. package/dist/cli/file-processor.js +2 -3
  9. package/dist/cli/file-processor.js.map +1 -1
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +15 -2
  12. package/dist/config.js.map +1 -1
  13. package/dist/core/agent-session.d.ts +13 -3
  14. package/dist/core/agent-session.d.ts.map +1 -1
  15. package/dist/core/agent-session.js +130 -23
  16. package/dist/core/agent-session.js.map +1 -1
  17. package/dist/core/diagnostics.d.ts +1 -1
  18. package/dist/core/diagnostics.d.ts.map +1 -1
  19. package/dist/core/diagnostics.js.map +1 -1
  20. package/dist/core/export-html/template.js +6 -3
  21. package/dist/core/extensions/runner.d.ts +5 -1
  22. package/dist/core/extensions/runner.d.ts.map +1 -1
  23. package/dist/core/extensions/runner.js +13 -3
  24. package/dist/core/extensions/runner.js.map +1 -1
  25. package/dist/core/extensions/types.d.ts +6 -3
  26. package/dist/core/extensions/types.d.ts.map +1 -1
  27. package/dist/core/extensions/types.js.map +1 -1
  28. package/dist/core/model-registry.d.ts.map +1 -1
  29. package/dist/core/model-registry.js +65 -13
  30. package/dist/core/model-registry.js.map +1 -1
  31. package/dist/core/output-guard.d.ts +1 -0
  32. package/dist/core/output-guard.d.ts.map +1 -1
  33. package/dist/core/output-guard.js +52 -22
  34. package/dist/core/output-guard.js.map +1 -1
  35. package/dist/core/package-manager.d.ts +1 -0
  36. package/dist/core/package-manager.d.ts.map +1 -1
  37. package/dist/core/package-manager.js +161 -24
  38. package/dist/core/package-manager.js.map +1 -1
  39. package/dist/core/pi-agent.d.ts.map +1 -1
  40. package/dist/core/pi-agent.js +12 -3
  41. package/dist/core/pi-agent.js.map +1 -1
  42. package/dist/core/resolve-config-value.d.ts +9 -1
  43. package/dist/core/resolve-config-value.d.ts.map +1 -1
  44. package/dist/core/resolve-config-value.js +134 -11
  45. package/dist/core/resolve-config-value.js.map +1 -1
  46. package/dist/core/resource-loader.d.ts +30 -0
  47. package/dist/core/resource-loader.d.ts.map +1 -1
  48. package/dist/core/resource-loader.js +94 -0
  49. package/dist/core/resource-loader.js.map +1 -1
  50. package/dist/core/rules.d.ts +57 -0
  51. package/dist/core/rules.d.ts.map +1 -0
  52. package/dist/core/rules.js +384 -0
  53. package/dist/core/rules.js.map +1 -0
  54. package/dist/core/session/jsonl-helpers.d.ts +2 -1
  55. package/dist/core/session/jsonl-helpers.d.ts.map +1 -1
  56. package/dist/core/session/jsonl-helpers.js +6 -3
  57. package/dist/core/session/jsonl-helpers.js.map +1 -1
  58. package/dist/core/session/local-session-manager.d.ts +1 -0
  59. package/dist/core/session/local-session-manager.d.ts.map +1 -1
  60. package/dist/core/session/local-session-manager.js +12 -4
  61. package/dist/core/session/local-session-manager.js.map +1 -1
  62. package/dist/core/session/session-manager.d.ts +1 -0
  63. package/dist/core/session/session-manager.d.ts.map +1 -1
  64. package/dist/core/session/session-manager.js.map +1 -1
  65. package/dist/core/session/stores/jsonl-session-store.d.ts +2 -1
  66. package/dist/core/session/stores/jsonl-session-store.d.ts.map +1 -1
  67. package/dist/core/session/stores/jsonl-session-store.js +105 -78
  68. package/dist/core/session/stores/jsonl-session-store.js.map +1 -1
  69. package/dist/core/settings-manager.d.ts +7 -0
  70. package/dist/core/settings-manager.d.ts.map +1 -1
  71. package/dist/core/settings-manager.js +28 -9
  72. package/dist/core/settings-manager.js.map +1 -1
  73. package/dist/core/slash-commands.d.ts +1 -1
  74. package/dist/core/slash-commands.d.ts.map +1 -1
  75. package/dist/core/slash-commands.js +1 -1
  76. package/dist/core/slash-commands.js.map +1 -1
  77. package/dist/core/system-prompt.d.ts +3 -0
  78. package/dist/core/system-prompt.d.ts.map +1 -1
  79. package/dist/core/system-prompt.js +11 -3
  80. package/dist/core/system-prompt.js.map +1 -1
  81. package/dist/core/tools/bash.d.ts.map +1 -1
  82. package/dist/core/tools/bash.js +73 -63
  83. package/dist/core/tools/bash.js.map +1 -1
  84. package/dist/core/tools/edit.d.ts.map +1 -1
  85. package/dist/core/tools/edit.js +45 -76
  86. package/dist/core/tools/edit.js.map +1 -1
  87. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  88. package/dist/core/tools/file-mutation-queue.js +27 -12
  89. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  90. package/dist/core/tools/find.d.ts.map +1 -1
  91. package/dist/core/tools/find.js +11 -2
  92. package/dist/core/tools/find.js.map +1 -1
  93. package/dist/core/tools/grep.d.ts.map +1 -1
  94. package/dist/core/tools/grep.js +3 -3
  95. package/dist/core/tools/grep.js.map +1 -1
  96. package/dist/core/tools/ls.d.ts.map +1 -1
  97. package/dist/core/tools/ls.js +13 -4
  98. package/dist/core/tools/ls.js.map +1 -1
  99. package/dist/core/tools/path-utils.d.ts +1 -0
  100. package/dist/core/tools/path-utils.d.ts.map +1 -1
  101. package/dist/core/tools/path-utils.js +37 -0
  102. package/dist/core/tools/path-utils.js.map +1 -1
  103. package/dist/core/tools/read.d.ts.map +1 -1
  104. package/dist/core/tools/read.js +13 -8
  105. package/dist/core/tools/read.js.map +1 -1
  106. package/dist/core/tools/write.d.ts.map +1 -1
  107. package/dist/core/tools/write.js +24 -32
  108. package/dist/core/tools/write.js.map +1 -1
  109. package/dist/index.d.ts +1 -0
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +2 -0
  112. package/dist/index.js.map +1 -1
  113. package/dist/main.d.ts.map +1 -1
  114. package/dist/main.js +6 -2
  115. package/dist/main.js.map +1 -1
  116. package/dist/migrations.d.ts.map +1 -1
  117. package/dist/migrations.js +118 -1
  118. package/dist/migrations.js.map +1 -1
  119. package/dist/modes/interactive/components/config-selector.d.ts +1 -1
  120. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  121. package/dist/modes/interactive/components/config-selector.js +12 -3
  122. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  123. package/dist/modes/interactive/components/footer.d.ts +1 -0
  124. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  125. package/dist/modes/interactive/components/footer.js +14 -5
  126. package/dist/modes/interactive/components/footer.js.map +1 -1
  127. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  128. package/dist/modes/interactive/components/settings-selector.js +1 -1
  129. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  130. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  131. package/dist/modes/interactive/components/user-message.js +1 -1
  132. package/dist/modes/interactive/components/user-message.js.map +1 -1
  133. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  134. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  135. package/dist/modes/interactive/interactive-mode.js +64 -9
  136. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  137. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  138. package/dist/modes/interactive/theme/theme.js +10 -0
  139. package/dist/modes/interactive/theme/theme.js.map +1 -1
  140. package/dist/modes/rpc/rpc-client.d.ts +5 -0
  141. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  142. package/dist/modes/rpc/rpc-client.js +91 -18
  143. package/dist/modes/rpc/rpc-client.js.map +1 -1
  144. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  145. package/dist/modes/rpc/rpc-mode.js +23 -3
  146. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  147. package/dist/modes/rpc/rpc-types.d.ts +1 -1
  148. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  149. package/dist/modes/rpc/rpc-types.js.map +1 -1
  150. package/dist/utils/clipboard-native.d.ts +3 -1
  151. package/dist/utils/clipboard-native.d.ts.map +1 -1
  152. package/dist/utils/clipboard-native.js +14 -8
  153. package/dist/utils/clipboard-native.js.map +1 -1
  154. package/dist/utils/deprecation.d.ts +4 -0
  155. package/dist/utils/deprecation.d.ts.map +1 -0
  156. package/dist/utils/deprecation.js +13 -0
  157. package/dist/utils/deprecation.js.map +1 -0
  158. package/dist/utils/image-resize-core.d.ts +30 -0
  159. package/dist/utils/image-resize-core.d.ts.map +1 -0
  160. package/dist/utils/image-resize-core.js +124 -0
  161. package/dist/utils/image-resize-core.js.map +1 -0
  162. package/dist/utils/image-resize-worker.d.ts +2 -0
  163. package/dist/utils/image-resize-worker.d.ts.map +1 -0
  164. package/dist/utils/image-resize-worker.js +31 -0
  165. package/dist/utils/image-resize-worker.js.map +1 -0
  166. package/dist/utils/image-resize.d.ts +6 -27
  167. package/dist/utils/image-resize.d.ts.map +1 -1
  168. package/dist/utils/image-resize.js +60 -116
  169. package/dist/utils/image-resize.js.map +1 -1
  170. package/dist/utils/json.d.ts +3 -0
  171. package/dist/utils/json.d.ts.map +1 -0
  172. package/dist/utils/json.js +7 -0
  173. package/dist/utils/json.js.map +1 -0
  174. package/docs/custom-provider.md +22 -9
  175. package/docs/extensions.md +13 -11
  176. package/docs/index.md +3 -2
  177. package/docs/models.md +34 -12
  178. package/docs/packages.md +11 -8
  179. package/docs/providers.md +13 -5
  180. package/docs/quickstart.md +1 -1
  181. package/docs/rpc.md +4 -2
  182. package/docs/rules.md +102 -0
  183. package/docs/sdk.md +57 -1
  184. package/docs/settings.md +6 -3
  185. package/docs/terminal-setup.md +6 -0
  186. package/docs/usage.md +6 -4
  187. package/examples/extensions/README.md +2 -1
  188. package/examples/extensions/custom-provider-anthropic/index.ts +1 -1
  189. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  190. package/examples/extensions/custom-provider-gitlab-duo/index.ts +54 -3
  191. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  192. package/examples/extensions/dynamic-resources/RULES.md +8 -0
  193. package/examples/extensions/dynamic-resources/index.ts +1 -0
  194. package/examples/extensions/git-merge-and-resolve.ts +115 -0
  195. package/examples/extensions/reload-runtime.ts +2 -2
  196. package/examples/extensions/sandbox/package.json +1 -1
  197. package/examples/extensions/with-deps/package.json +1 -1
  198. package/examples/sdk/12-full-control.ts +1 -0
  199. package/examples/sdk/README.md +1 -1
  200. package/npm-shrinkwrap.json +13 -12
  201. package/package.json +5 -5
@@ -110,6 +110,9 @@ export class AgentSession {
110
110
  // Compaction state
111
111
  _compactionAbortController = undefined;
112
112
  _autoCompactionAbortController = undefined;
113
+ _extensionCompactionQueue = [];
114
+ _extensionCompactionTimer = undefined;
115
+ _extensionCompactionRunning = false;
113
116
  _overflowRecoveryAttempted = false;
114
117
  // Branch summarization state
115
118
  _branchSummaryAbortController = undefined;
@@ -299,6 +302,9 @@ export class AgentSession {
299
302
  await this._emitExtensionEvent(event);
300
303
  // Notify all listeners
301
304
  this._emit(event.type === "agent_end" ? { ...event, willRetry: this._willRetryAfterAgentEnd(event) } : event);
305
+ if (event.type === "agent_end") {
306
+ this._scheduleExtensionCompactions();
307
+ }
302
308
  // Handle session persistence
303
309
  if (event.type === "message_end") {
304
310
  // Check if this is a custom message from extensions
@@ -503,6 +509,21 @@ export class AgentSession {
503
509
  * Call this when completely done with the session.
504
510
  */
505
511
  dispose() {
512
+ try {
513
+ this.abortRetry();
514
+ this.abortCompaction();
515
+ this.abortBranchSummary();
516
+ this.abortBash();
517
+ this.agent.abort();
518
+ }
519
+ catch {
520
+ // Dispose must succeed even if an abort hook throws.
521
+ }
522
+ if (this._extensionCompactionTimer !== undefined) {
523
+ clearTimeout(this._extensionCompactionTimer);
524
+ this._extensionCompactionTimer = undefined;
525
+ }
526
+ this._extensionCompactionQueue = [];
506
527
  this._extensionRunner.invalidate("This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().");
507
528
  this._disconnectFromAgent();
508
529
  this._eventListeners = [];
@@ -663,10 +684,12 @@ export class AgentSession {
663
684
  const loaderAppendSystemPrompt = this._resourceLoader.getAppendSystemPrompt();
664
685
  const appendSystemPrompt = loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join("\n\n") : undefined;
665
686
  const loadedSkills = this._resourceLoader.getSkills().skills;
687
+ const loadedRules = this._resourceLoader.getRules().rules;
666
688
  const loadedContextFiles = this._resourceLoader.getAgentsFiles().agentsFiles;
667
689
  this._baseSystemPromptOptions = {
668
690
  cwd: this._cwd,
669
691
  skills: loadedSkills,
692
+ rules: loadedRules,
670
693
  contextFiles: loadedContextFiles,
671
694
  customPrompt: loaderSystemPrompt,
672
695
  appendSystemPrompt,
@@ -708,7 +731,12 @@ export class AgentSession {
708
731
  });
709
732
  this._retryAttempt = 0;
710
733
  }
711
- return await this._checkCompaction(msg);
734
+ if (await this._checkCompaction(msg)) {
735
+ return true;
736
+ }
737
+ // The agent loop drains both queues before emitting agent_end. Any messages
738
+ // here were queued by agent_end extension handlers and need a continuation.
739
+ return this.agent.hasQueuedMessages();
712
740
  }
713
741
  async getStructuredResponse(options) {
714
742
  if (this.isStreaming) {
@@ -918,7 +946,7 @@ export class AgentSession {
918
946
  let currentText = text;
919
947
  let currentImages = options?.images;
920
948
  if (this._extensionRunner.hasHandlers("input")) {
921
- const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? "interactive");
949
+ const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? "interactive", this.isStreaming ? options?.streamingBehavior : undefined);
922
950
  if (inputResult.action === "handled") {
923
951
  preflightResult?.(true);
924
952
  return;
@@ -928,10 +956,11 @@ export class AgentSession {
928
956
  currentImages = inputResult.images ?? currentImages;
929
957
  }
930
958
  }
931
- // Expand skill commands (/skill:name args) and prompt templates (/template args)
959
+ // Expand skill/rule commands (/skill:name or /rule:name args) and prompt templates (/template args)
932
960
  let expandedText = currentText;
933
961
  if (expandPromptTemplates) {
934
962
  expandedText = this._expandSkillCommand(expandedText);
963
+ expandedText = this._expandRuleCommand(expandedText);
935
964
  expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
936
965
  }
937
966
  // If streaming, queue via steer() or followUp() based on option
@@ -1084,11 +1113,35 @@ export class AgentSession {
1084
1113
  return text; // Return original on error
1085
1114
  }
1086
1115
  }
1116
+ _expandRuleCommand(text) {
1117
+ if (!text.startsWith("/rule:"))
1118
+ return text;
1119
+ const spaceIndex = text.indexOf(" ");
1120
+ const ruleName = spaceIndex === -1 ? text.slice(6) : text.slice(6, spaceIndex);
1121
+ const args = spaceIndex === -1 ? "" : text.slice(spaceIndex + 1).trim();
1122
+ const rule = this.resourceLoader.getRules().rules.find((r) => r.name === ruleName);
1123
+ if (!rule)
1124
+ return text; // Unknown rule, pass through
1125
+ try {
1126
+ const content = readFileSync(rule.filePath, "utf-8");
1127
+ const body = stripFrontmatter(content).trim();
1128
+ const ruleBlock = `<rule name="${rule.name}" location="${rule.filePath}">\nReferences are relative to ${rule.baseDir}.\n\n${body}\n</rule>`;
1129
+ return args ? `${ruleBlock}\n\n${args}` : ruleBlock;
1130
+ }
1131
+ catch (err) {
1132
+ this._extensionRunner.emitError({
1133
+ extensionPath: rule.filePath,
1134
+ event: "rule_expansion",
1135
+ error: err instanceof Error ? err.message : String(err),
1136
+ });
1137
+ return text;
1138
+ }
1139
+ }
1087
1140
  /**
1088
1141
  * Queue a steering message while the agent is running.
1089
1142
  * Delivered after the current assistant turn finishes executing its tool calls,
1090
1143
  * before the next LLM call.
1091
- * Expands skill commands and prompt templates. Errors on extension commands.
1144
+ * Expands skill/rule commands and prompt templates. Errors on extension commands.
1092
1145
  * @param images Optional image attachments to include with the message
1093
1146
  * @throws Error if text is an extension command
1094
1147
  */
@@ -1097,15 +1150,16 @@ export class AgentSession {
1097
1150
  if (text.startsWith("/")) {
1098
1151
  this._throwIfExtensionCommand(text);
1099
1152
  }
1100
- // Expand skill commands and prompt templates
1153
+ // Expand skill/rule commands and prompt templates
1101
1154
  let expandedText = this._expandSkillCommand(text);
1155
+ expandedText = this._expandRuleCommand(expandedText);
1102
1156
  expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
1103
1157
  await this._queueSteer(expandedText, images);
1104
1158
  }
1105
1159
  /**
1106
1160
  * Queue a follow-up message to be processed after the agent finishes.
1107
1161
  * Delivered only when agent has no more tool calls or steering messages.
1108
- * Expands skill commands and prompt templates. Errors on extension commands.
1162
+ * Expands skill/rule commands and prompt templates. Errors on extension commands.
1109
1163
  * @param images Optional image attachments to include with the message
1110
1164
  * @throws Error if text is an extension command
1111
1165
  */
@@ -1114,8 +1168,9 @@ export class AgentSession {
1114
1168
  if (text.startsWith("/")) {
1115
1169
  this._throwIfExtensionCommand(text);
1116
1170
  }
1117
- // Expand skill commands and prompt templates
1171
+ // Expand skill/rule commands and prompt templates
1118
1172
  let expandedText = this._expandSkillCommand(text);
1173
+ expandedText = this._expandRuleCommand(expandedText);
1119
1174
  expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
1120
1175
  await this._queueFollowUp(expandedText, images);
1121
1176
  }
@@ -1200,8 +1255,8 @@ export class AgentSession {
1200
1255
  else {
1201
1256
  this.agent.state.messages.push(appMessage);
1202
1257
  this.session.appendCustomMessageEntry(message.customType, message.content, message.display, message.details);
1203
- this._emit({ type: "message_start", message: appMessage });
1204
- this._emit({ type: "message_end", message: appMessage });
1258
+ await this._emit({ type: "message_start", message: appMessage });
1259
+ await this._emit({ type: "message_end", message: appMessage });
1205
1260
  }
1206
1261
  }
1207
1262
  /**
@@ -1456,6 +1511,55 @@ export class AgentSession {
1456
1511
  // =========================================================================
1457
1512
  // Compaction
1458
1513
  // =========================================================================
1514
+ /** Queue extension-triggered compaction outside the currently active agent turn. */
1515
+ _requestExtensionCompaction(options) {
1516
+ this._extensionCompactionQueue.push(options ?? {});
1517
+ if (this.isStreaming) {
1518
+ return;
1519
+ }
1520
+ this._scheduleExtensionCompactions();
1521
+ }
1522
+ _scheduleExtensionCompactions() {
1523
+ const alreadyScheduled = this._extensionCompactionTimer !== undefined;
1524
+ if (this._extensionCompactionRunning || alreadyScheduled || this._extensionCompactionQueue.length === 0) {
1525
+ return;
1526
+ }
1527
+ this._extensionCompactionTimer = setTimeout(() => {
1528
+ this._extensionCompactionTimer = undefined;
1529
+ void this._drainExtensionCompactionQueue();
1530
+ }, 0);
1531
+ }
1532
+ async _drainExtensionCompactionQueue() {
1533
+ if (this._extensionCompactionRunning) {
1534
+ return;
1535
+ }
1536
+ this._extensionCompactionRunning = true;
1537
+ try {
1538
+ while (!this.isStreaming) {
1539
+ const options = this._extensionCompactionQueue.shift();
1540
+ if (!options) {
1541
+ break;
1542
+ }
1543
+ await this._runRequestedExtensionCompaction(options);
1544
+ }
1545
+ }
1546
+ finally {
1547
+ this._extensionCompactionRunning = false;
1548
+ }
1549
+ if (!this.isStreaming) {
1550
+ this._scheduleExtensionCompactions();
1551
+ }
1552
+ }
1553
+ async _runRequestedExtensionCompaction(options) {
1554
+ try {
1555
+ const result = await this.compact(options.customInstructions);
1556
+ options.onComplete?.(result);
1557
+ }
1558
+ catch (error) {
1559
+ const err = error instanceof Error ? error : new Error(String(error));
1560
+ options.onError?.(err);
1561
+ }
1562
+ }
1459
1563
  /**
1460
1564
  * Manually compact the session context.
1461
1565
  * Aborts current agent operation first.
@@ -1851,12 +1955,13 @@ export class AgentSession {
1851
1955
  if (!this._extensionRunner.hasHandlers("resources_discover")) {
1852
1956
  return;
1853
1957
  }
1854
- const { skillPaths, promptPaths, themePaths } = await this._extensionRunner.emitResourcesDiscover(this._cwd, reason);
1855
- if (skillPaths.length === 0 && promptPaths.length === 0 && themePaths.length === 0) {
1958
+ const { skillPaths, rulePaths, promptPaths, themePaths } = await this._extensionRunner.emitResourcesDiscover(this._cwd, reason);
1959
+ if (skillPaths.length === 0 && rulePaths.length === 0 && promptPaths.length === 0 && themePaths.length === 0) {
1856
1960
  return;
1857
1961
  }
1858
1962
  const extensionPaths = {
1859
1963
  skillPaths: this.buildExtensionResourcePaths(skillPaths),
1964
+ rulePaths: this.buildExtensionResourcePaths(rulePaths),
1860
1965
  promptPaths: this.buildExtensionResourcePaths(promptPaths),
1861
1966
  themePaths: this.buildExtensionResourcePaths(themePaths),
1862
1967
  };
@@ -1926,7 +2031,13 @@ export class AgentSession {
1926
2031
  source: "skill",
1927
2032
  sourceInfo: skill.sourceInfo,
1928
2033
  }));
1929
- return [...extensionCommands, ...templates, ...skills];
2034
+ const rules = this._resourceLoader.getRules().rules.map((rule) => ({
2035
+ name: `rule:${rule.name}`,
2036
+ description: rule.description,
2037
+ source: "rule",
2038
+ sourceInfo: rule.sourceInfo,
2039
+ }));
2040
+ return [...extensionCommands, ...templates, ...skills, ...rules];
1930
2041
  };
1931
2042
  runner.bindCore({
1932
2043
  sendMessage: (message, options) => {
@@ -1989,16 +2100,7 @@ export class AgentSession {
1989
2100
  },
1990
2101
  getContextUsage: () => this.getContextUsage(),
1991
2102
  compact: (options) => {
1992
- void (async () => {
1993
- try {
1994
- const result = await this.compact(options?.customInstructions);
1995
- options?.onComplete?.(result);
1996
- }
1997
- catch (error) {
1998
- const err = error instanceof Error ? error : new Error(String(error));
1999
- options?.onError?.(err);
2000
- }
2001
- })();
2103
+ this._requestExtensionCompaction(options);
2002
2104
  },
2003
2105
  getSystemPrompt: () => this.systemPrompt,
2004
2106
  }, {
@@ -2146,6 +2248,9 @@ export class AgentSession {
2146
2248
  // =========================================================================
2147
2249
  // Auto-Retry
2148
2250
  // =========================================================================
2251
+ _isNonRetryableProviderLimitError(errorMessage) {
2252
+ return /GoUsageLimitError|FreeUsageLimitError|Monthly usage limit reached|available balance|insufficient_quota|out of budget|quota exceeded|billing/i.test(errorMessage);
2253
+ }
2149
2254
  /**
2150
2255
  * Check if an error is retryable (overloaded, rate limit, server errors).
2151
2256
  * Context overflow errors are NOT retryable (handled by compaction instead).
@@ -2158,6 +2263,8 @@ export class AgentSession {
2158
2263
  if (isContextOverflow(message, contextWindow))
2159
2264
  return false;
2160
2265
  const err = message.errorMessage;
2266
+ if (this._isNonRetryableProviderLimitError(err))
2267
+ return false;
2161
2268
  // Match: overloaded_error, provider returned error, rate limit, 429, 500, 502, 503, 504, service unavailable, network/connection errors (including connection lost), WebSocket transport closes/errors, fetch failed, premature stream endings, HTTP/2 closed before response, terminated, retry delay exceeded
2162
2269
  return /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|ended without|stream ended before message_stop|http2 request did not get a response|timed? out|timeout|terminated|retry delay/i.test(err);
2163
2270
  }
@@ -2325,7 +2432,7 @@ export class AgentSession {
2325
2432
  */
2326
2433
  setSessionName(name) {
2327
2434
  this.session.appendSessionInfo(name);
2328
- this._emit({ type: "session_info_changed", name: this.session.getSessionName() });
2435
+ void this._emit({ type: "session_info_changed", name: this.session.getSessionName() });
2329
2436
  }
2330
2437
  // =========================================================================
2331
2438
  // Tree Navigation