@defai.digital/automatosx 11.2.8 → 11.3.0

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.
package/dist/index.js CHANGED
@@ -15,14 +15,14 @@ import chalk5 from 'chalk';
15
15
  import ora8 from 'ora';
16
16
  import * as readline2 from 'readline';
17
17
  import readline2__default, { createInterface } from 'readline';
18
+ import { Mutex } from 'async-mutex';
18
19
  import { promisify } from 'util';
19
20
  import yargs from 'yargs';
20
21
  import { hideBin } from 'yargs/helpers';
21
- import { randomUUID, createHash } from 'crypto';
22
+ import crypto2, { randomUUID, createHash } from 'crypto';
22
23
  import * as yaml4 from 'js-yaml';
23
24
  import yaml4__default, { load, dump } from 'js-yaml';
24
25
  import Table from 'cli-table3';
25
- import { Mutex } from 'async-mutex';
26
26
  import inquirer from 'inquirer';
27
27
  import Ajv from 'ajv';
28
28
  import addFormats from 'ajv-formats';
@@ -2535,6 +2535,15 @@ var init_base_provider = __esm({
2535
2535
  "test-provider"
2536
2536
  // For unit tests
2537
2537
  ];
2538
+ /** Environment variables to force non-interactive CLI mode */
2539
+ static NON_INTERACTIVE_ENV = {
2540
+ TERM: "dumb",
2541
+ NO_COLOR: "1",
2542
+ FORCE_COLOR: "0",
2543
+ CI: "true",
2544
+ NO_UPDATE_NOTIFIER: "1",
2545
+ DEBIAN_FRONTEND: "noninteractive"
2546
+ };
2538
2547
  config;
2539
2548
  logger = logger;
2540
2549
  health;
@@ -2627,19 +2636,7 @@ var init_base_provider = __esm({
2627
2636
  shell: true,
2628
2637
  // Auto-detects: cmd.exe on Windows, /bin/sh on Unix
2629
2638
  timeout: this.config.timeout || 12e4,
2630
- env: {
2631
- ...process.env,
2632
- // Force non-interactive mode for CLIs
2633
- TERM: "dumb",
2634
- NO_COLOR: "1",
2635
- // Disable TTY checks for codex and other CLIs
2636
- FORCE_COLOR: "0",
2637
- CI: "true",
2638
- // Many CLIs disable TTY checks in CI mode
2639
- NO_UPDATE_NOTIFIER: "1",
2640
- // Disable interactive prompts
2641
- DEBIAN_FRONTEND: "noninteractive"
2642
- }
2639
+ env: { ...process.env, ..._BaseProvider.NON_INTERACTIVE_ENV }
2643
2640
  });
2644
2641
  let stdout = "";
2645
2642
  let stderr = "";
@@ -2789,22 +2786,14 @@ var init_base_provider = __esm({
2789
2786
  });
2790
2787
  const child = spawn(cliCommand2, commandArgs, {
2791
2788
  timeout: this.config.timeout || 12e4,
2792
- env: {
2793
- ...process.env,
2794
- // Force non-interactive mode for CLIs
2795
- TERM: "dumb",
2796
- NO_COLOR: "1",
2797
- FORCE_COLOR: "0",
2798
- CI: "true",
2799
- NO_UPDATE_NOTIFIER: "1",
2800
- DEBIAN_FRONTEND: "noninteractive"
2801
- }
2789
+ env: { ...process.env, ..._BaseProvider.NON_INTERACTIVE_ENV }
2802
2790
  });
2803
2791
  let stdout = "";
2804
2792
  let stderr = "";
2805
2793
  let timeoutId = null;
2806
2794
  let forceKillTimer = null;
2807
2795
  let readlineInterface = null;
2796
+ let stderrInterface = null;
2808
2797
  const streamingEnabled = process.env.AUTOMATOSX_SHOW_PROVIDER_OUTPUT === "true";
2809
2798
  const debugMode = process.env.AUTOMATOSX_DEBUG === "true";
2810
2799
  const verbosity = VerbosityManager.getInstance();
@@ -2849,7 +2838,7 @@ var init_base_provider = __esm({
2849
2838
  });
2850
2839
  }
2851
2840
  if (child.stderr) {
2852
- const stderrInterface = readline2__default.createInterface({
2841
+ stderrInterface = readline2__default.createInterface({
2853
2842
  input: child.stderr,
2854
2843
  crlfDelay: Infinity
2855
2844
  });
@@ -2865,6 +2854,13 @@ var init_base_provider = __esm({
2865
2854
  }
2866
2855
  }
2867
2856
  });
2857
+ stderrInterface.on("error", (error) => {
2858
+ if (error.message !== "Readable stream already read") {
2859
+ logger.debug("Stderr readline error (non-fatal)", {
2860
+ error: error.message
2861
+ });
2862
+ }
2863
+ });
2868
2864
  }
2869
2865
  const cleanup = () => {
2870
2866
  if (timeoutId) {
@@ -2883,22 +2879,35 @@ var init_base_provider = __esm({
2883
2879
  readlineInterface = null;
2884
2880
  }
2885
2881
  }
2882
+ if (stderrInterface) {
2883
+ try {
2884
+ stderrInterface.close();
2885
+ } catch (error) {
2886
+ } finally {
2887
+ stderrInterface = null;
2888
+ }
2889
+ }
2886
2890
  };
2887
2891
  child.on("close", (code, signal) => {
2888
2892
  cleanup();
2889
2893
  if (stderr) {
2890
2894
  logger.debug(`${cliCommand2} CLI stderr output`, { stderr: stderr.trim() });
2891
2895
  }
2892
- if (code === 0) {
2896
+ if ((code === 0 || code === null) && !signal) {
2893
2897
  if (progressParser) {
2894
2898
  progressParser.succeed(`${cliCommand2} completed successfully`);
2895
2899
  }
2896
2900
  resolve13({ stdout, stderr });
2901
+ } else if (signal) {
2902
+ if (progressParser) {
2903
+ progressParser.fail(`${cliCommand2} killed by signal ${signal}`);
2904
+ }
2905
+ reject(new Error(`${cliCommand2} CLI killed by signal ${signal}. stderr: ${stderr || "none"}`));
2897
2906
  } else {
2898
2907
  if (progressParser) {
2899
2908
  progressParser.fail(`${cliCommand2} failed with code ${code}`);
2900
2909
  }
2901
- reject(new Error(`${cliCommand2} CLI exited with code ${code}${signal ? ` (signal: ${signal})` : ""}. stderr: ${stderr || "none"}`));
2910
+ reject(new Error(`${cliCommand2} CLI exited with code ${code}. stderr: ${stderr || "none"}`));
2902
2911
  }
2903
2912
  });
2904
2913
  child.on("error", (error) => {
@@ -2934,8 +2943,18 @@ var init_base_provider = __esm({
2934
2943
  /**
2935
2944
  * Check if CLI is available - Template method pattern
2936
2945
  * Uses getCLICommand() to determine which CLI to check
2946
+ *
2947
+ * v11.2.9 Fix: Always return true in mock mode (AX_MOCK_PROVIDERS=true)
2948
+ * This allows integration tests in CI to run without installing actual provider CLIs
2937
2949
  */
2938
2950
  async checkCLIAvailable() {
2951
+ if (process.env.AX_MOCK_PROVIDERS === "true") {
2952
+ logger.debug(`${this.getCLICommand()} CLI availability check (mock mode)`, {
2953
+ available: true,
2954
+ mockMode: true
2955
+ });
2956
+ return true;
2957
+ }
2939
2958
  try {
2940
2959
  const cliCommand2 = this.getCLICommand();
2941
2960
  const result = findOnPath(cliCommand2);
@@ -3854,8 +3873,6 @@ var init_cli_wrapper = __esm({
3854
3873
  };
3855
3874
  }
3856
3875
  });
3857
-
3858
- // src/integrations/openai-codex/sdk-adapter.ts
3859
3876
  var CodexSdkAdapter;
3860
3877
  var init_sdk_adapter = __esm({
3861
3878
  "src/integrations/openai-codex/sdk-adapter.ts"() {
@@ -3868,6 +3885,8 @@ var init_sdk_adapter = __esm({
3868
3885
  sdkModule = null;
3869
3886
  options;
3870
3887
  initialized = false;
3888
+ initMutex = new Mutex();
3889
+ // v11.2.8: Prevent race condition in ensureInitialized
3871
3890
  constructor(options = {}) {
3872
3891
  this.options = {
3873
3892
  streamingEnabled: true,
@@ -3962,18 +3981,20 @@ var init_sdk_adapter = __esm({
3962
3981
  return this.activeThread;
3963
3982
  }
3964
3983
  async ensureInitialized() {
3965
- if (this.initialized) return;
3966
- try {
3967
- this.sdkModule = await import('@openai/codex-sdk');
3968
- this.codex = new this.sdkModule.Codex();
3969
- this.initialized = true;
3970
- logger.info("Codex SDK initialized");
3971
- } catch (error) {
3972
- throw new CodexError(
3973
- "CLI_NOT_FOUND" /* CLI_NOT_FOUND */,
3974
- "Codex SDK not available. Install with: npm install @openai/codex-sdk"
3975
- );
3976
- }
3984
+ return this.initMutex.runExclusive(async () => {
3985
+ if (this.initialized) return;
3986
+ try {
3987
+ this.sdkModule = await import('@openai/codex-sdk');
3988
+ this.codex = new this.sdkModule.Codex();
3989
+ this.initialized = true;
3990
+ logger.info("Codex SDK initialized");
3991
+ } catch (error) {
3992
+ throw new CodexError(
3993
+ "CLI_NOT_FOUND" /* CLI_NOT_FOUND */,
3994
+ "Codex SDK not available. Install with: npm install @openai/codex-sdk"
3995
+ );
3996
+ }
3997
+ });
3977
3998
  }
3978
3999
  async destroy() {
3979
4000
  this.activeThread = null;
@@ -4379,6 +4400,9 @@ var init_command_builder = __esm({
4379
4400
  * @returns Environment variable object
4380
4401
  */
4381
4402
  buildEnv(options) {
4403
+ if (!options.apiKey && !options.baseUrl && !options.model) {
4404
+ return null;
4405
+ }
4382
4406
  const env = {};
4383
4407
  if (options.apiKey) {
4384
4408
  env.YOUR_API_KEY = options.apiKey;
@@ -4426,6 +4450,27 @@ var init_response_parser = __esm({
4426
4450
  AxCliResponseParser = class _AxCliResponseParser {
4427
4451
  /** Maximum number of assistant messages to prevent memory exhaustion */
4428
4452
  static MAX_ASSISTANT_MESSAGES = 1e3;
4453
+ /** Pre-compiled regex patterns for error detection (avoids recompilation per call) */
4454
+ static ERROR_WITH_COLON_REGEX = /Sorry, I encountered an error: (.+?)$/;
4455
+ static ERROR_WITHOUT_COLON_REGEX = /Sorry, I encountered an error(.*?)$/;
4456
+ /**
4457
+ * Extract error message from content if present
4458
+ * @returns Error message or null if no error
4459
+ */
4460
+ extractErrorFromContent(content) {
4461
+ if (!content.includes("Sorry, I encountered an error")) {
4462
+ return null;
4463
+ }
4464
+ const matchWithColon = content.match(_AxCliResponseParser.ERROR_WITH_COLON_REGEX);
4465
+ if (matchWithColon?.[1]) {
4466
+ return matchWithColon[1];
4467
+ }
4468
+ const matchWithoutColon = content.match(_AxCliResponseParser.ERROR_WITHOUT_COLON_REGEX);
4469
+ if (matchWithoutColon) {
4470
+ return matchWithoutColon[1] ? matchWithoutColon[1].trim() : "API error";
4471
+ }
4472
+ return "API error";
4473
+ }
4429
4474
  /**
4430
4475
  * Parse JSONL output from ax-cli into ProviderResponse
4431
4476
  *
@@ -4450,17 +4495,9 @@ var init_response_parser = __esm({
4450
4495
  const parsed = JSON.parse(line);
4451
4496
  const validated = AxCliMessageSchema.parse(parsed);
4452
4497
  if (validated.role === "assistant") {
4453
- if (validated.content.includes("Sorry, I encountered an error")) {
4454
- const matchWithColon = validated.content.match(/Sorry, I encountered an error: (.+?)$/);
4455
- if (matchWithColon) {
4456
- throw new Error(`ax-cli error: ${matchWithColon[1]}`);
4457
- }
4458
- const matchWithoutColon = validated.content.match(/Sorry, I encountered an error(.*?)$/);
4459
- if (matchWithoutColon) {
4460
- const errorMsg = matchWithoutColon[1] ? matchWithoutColon[1].trim() : "API error";
4461
- throw new Error(`ax-cli error: ${errorMsg}`);
4462
- }
4463
- throw new Error("ax-cli error: API error");
4498
+ const errorMsg = this.extractErrorFromContent(validated.content);
4499
+ if (errorMsg) {
4500
+ throw new Error(`ax-cli error: ${errorMsg}`);
4464
4501
  }
4465
4502
  if (assistantMessages.length >= _AxCliResponseParser.MAX_ASSISTANT_MESSAGES) {
4466
4503
  throw new Error(
@@ -4538,16 +4575,9 @@ var init_response_parser = __esm({
4538
4575
  try {
4539
4576
  const parsed = JSON.parse(line);
4540
4577
  if (parsed.role === "assistant" && parsed.content) {
4541
- if (parsed.content.includes("Sorry, I encountered an error")) {
4542
- const matchWithColon = parsed.content.match(/Sorry, I encountered an error: (.+?)$/);
4543
- if (matchWithColon) {
4544
- return matchWithColon[1];
4545
- }
4546
- const matchWithoutColon = parsed.content.match(/Sorry, I encountered an error(.*?)$/);
4547
- if (matchWithoutColon) {
4548
- return matchWithoutColon[1] ? matchWithoutColon[1].trim() : "Sorry, I encountered an error";
4549
- }
4550
- return parsed.content;
4578
+ const errorMsg = this.extractErrorFromContent(parsed.content);
4579
+ if (errorMsg) {
4580
+ return errorMsg;
4551
4581
  }
4552
4582
  }
4553
4583
  } catch {
@@ -4605,7 +4635,7 @@ var init_adapter = __esm({
4605
4635
  // 10MB
4606
4636
  env: {
4607
4637
  ...process.env,
4608
- ...this.commandBuilder.buildEnv(options)
4638
+ ...this.commandBuilder.buildEnv(options) ?? {}
4609
4639
  }
4610
4640
  });
4611
4641
  if (stderr && stderr.trim().length > 0) {
@@ -4824,11 +4854,12 @@ var init_token_estimator = __esm({
4824
4854
  });
4825
4855
 
4826
4856
  // src/integrations/ax-cli-sdk/subagent-adapter.ts
4827
- var SubagentAdapter;
4857
+ var TOKEN_SPLIT, SubagentAdapter;
4828
4858
  var init_subagent_adapter = __esm({
4829
4859
  "src/integrations/ax-cli-sdk/subagent-adapter.ts"() {
4830
4860
  init_esm_shims();
4831
4861
  init_logger();
4862
+ TOKEN_SPLIT = { PROMPT: 0.3, COMPLETION: 0.7 };
4832
4863
  SubagentAdapter = class {
4833
4864
  orchestrator = null;
4834
4865
  subagents = /* @__PURE__ */ new Map();
@@ -5033,9 +5064,8 @@ ${task.task}` : task.task;
5033
5064
  success: true,
5034
5065
  latencyMs,
5035
5066
  tokensUsed: totalTokens > 0 ? {
5036
- prompt: Math.floor(totalTokens * 0.3),
5037
- // Estimated split
5038
- completion: Math.floor(totalTokens * 0.7),
5067
+ prompt: Math.floor(totalTokens * TOKEN_SPLIT.PROMPT),
5068
+ completion: Math.floor(totalTokens * TOKEN_SPLIT.COMPLETION),
5039
5069
  total: totalTokens
5040
5070
  } : void 0
5041
5071
  };
@@ -5198,7 +5228,10 @@ ${task.task}` : task.task;
5198
5228
  for (const [key, subagent] of this.subagents) {
5199
5229
  try {
5200
5230
  if (subagent.dispose) {
5201
- subagent.dispose();
5231
+ const result = subagent.dispose();
5232
+ if (result instanceof Promise) {
5233
+ await result;
5234
+ }
5202
5235
  }
5203
5236
  logger.debug("Subagent disposed", { key });
5204
5237
  } catch (error) {
@@ -6354,7 +6387,7 @@ var init_adapter2 = __esm({
6354
6387
  init_instructions_bridge();
6355
6388
  init_mcp_manager();
6356
6389
  init_mcp_manager();
6357
- AxCliSdkAdapter = class {
6390
+ AxCliSdkAdapter = class _AxCliSdkAdapter {
6358
6391
  agent = null;
6359
6392
  // Will type as LLMAgent after import
6360
6393
  agentConfig = null;
@@ -6565,7 +6598,7 @@ var init_adapter2 = __esm({
6565
6598
  if (!await this.ensureSDKAvailable()) {
6566
6599
  throw new Error("ax-cli SDK not available. Install with: npm install @defai.digital/ax-cli");
6567
6600
  }
6568
- if (!this.agent || await this.hasConfigChanged(options)) {
6601
+ if (!this.agent || this.hasConfigChanged(options)) {
6569
6602
  await this.initializeAgent(options);
6570
6603
  }
6571
6604
  logger.debug("Executing via SDK (streaming mode for token tracking)", {
@@ -6712,8 +6745,9 @@ var init_adapter2 = __esm({
6712
6745
  * Check if agent config has changed (requires new agent)
6713
6746
  *
6714
6747
  * Since SDK manages credentials via settings, we only track maxToolRounds
6748
+ * v11.2.8: Removed unnecessary async (no async operations)
6715
6749
  */
6716
- async hasConfigChanged(options) {
6750
+ hasConfigChanged(options) {
6717
6751
  if (!this.agentConfig) return true;
6718
6752
  const changed = this.agentConfig.maxToolRounds !== (options.maxToolRounds || 400);
6719
6753
  if (changed) {
@@ -6797,6 +6831,49 @@ var init_adapter2 = __esm({
6797
6831
  });
6798
6832
  }
6799
6833
  }
6834
+ /**
6835
+ * Extract token usage from various sources with priority:
6836
+ * 1. SDK events (token_count emissions) - most accurate
6837
+ * 2. Usage object (ChatEntry.usage or response.usage)
6838
+ * 3. Estimation fallback
6839
+ */
6840
+ extractTokenUsage(prompt, content, totalTokensFromEvents, usageObject, sourceName) {
6841
+ if (totalTokensFromEvents > 0) {
6842
+ const estimated2 = TokenEstimator.estimateUsage(prompt, content);
6843
+ const tokens = {
6844
+ prompt: estimated2.prompt,
6845
+ completion: estimated2.completion,
6846
+ total: totalTokensFromEvents
6847
+ };
6848
+ logger.info(`Using token count from SDK events${sourceName ? ` (${sourceName})` : ""}`, {
6849
+ tokens: TokenEstimator.format(tokens),
6850
+ accuracy: "100% (total), 80-90% (split)",
6851
+ source: "token_count events"
6852
+ });
6853
+ return tokens;
6854
+ }
6855
+ const usage = usageObject || {};
6856
+ const actualTokens = {
6857
+ prompt: usage.prompt_tokens || usage.prompt || usage.input || usage.promptTokens || 0,
6858
+ completion: usage.completion_tokens || usage.completion || usage.output || usage.completionTokens || 0,
6859
+ total: usage.total_tokens || usage.total || usage.totalTokens || 0
6860
+ };
6861
+ if (actualTokens.total > 0) {
6862
+ logger.info(`Using token counts from ${sourceName || "usage object"}`, {
6863
+ tokens: TokenEstimator.format(actualTokens),
6864
+ accuracy: "100%",
6865
+ source: sourceName || "usage"
6866
+ });
6867
+ return actualTokens;
6868
+ }
6869
+ const estimated = TokenEstimator.estimateUsage(prompt, content);
6870
+ logger.warn(`SDK did not provide token counts${sourceName ? ` (${sourceName})` : ""}, using estimation`, {
6871
+ tokens: TokenEstimator.format(estimated, true),
6872
+ accuracy: "80-90% (estimated)",
6873
+ source: "estimation"
6874
+ });
6875
+ return estimated;
6876
+ }
6800
6877
  /**
6801
6878
  * Convert SDK response to ExecutionResponse format
6802
6879
  *
@@ -6827,116 +6904,47 @@ var init_adapter2 = __esm({
6827
6904
  }
6828
6905
  const lastAssistant = assistantMessages[assistantMessages.length - 1];
6829
6906
  const content2 = lastAssistant.content || "";
6830
- let finalTokens2;
6831
- if (totalTokensFromEvents > 0) {
6832
- const estimated = TokenEstimator.estimateUsage(prompt, content2);
6833
- finalTokens2 = {
6834
- prompt: estimated.prompt,
6835
- // Estimated split
6836
- completion: estimated.completion,
6837
- // Estimated split
6838
- total: totalTokensFromEvents
6839
- // Actual total from events
6840
- };
6841
- logger.info("Using token count from SDK events", {
6842
- tokens: TokenEstimator.format(finalTokens2),
6843
- accuracy: "100% (total), 80-90% (split)",
6844
- source: "token_count events"
6845
- });
6846
- } else {
6847
- const usage = lastAssistant.usage || lastAssistant.tokens || {};
6848
- const actualTokens = {
6849
- prompt: usage.prompt_tokens || usage.prompt || usage.input || usage.promptTokens || 0,
6850
- completion: usage.completion_tokens || usage.completion || usage.output || usage.completionTokens || 0,
6851
- total: usage.total_tokens || usage.total || usage.totalTokens || 0
6852
- };
6853
- const hasActualTokens = actualTokens.total > 0;
6854
- if (hasActualTokens) {
6855
- finalTokens2 = {
6856
- prompt: actualTokens.prompt,
6857
- completion: actualTokens.completion,
6858
- total: actualTokens.total
6859
- };
6860
- logger.info("Using token counts from ChatEntry.usage", {
6861
- tokens: TokenEstimator.format(finalTokens2),
6862
- accuracy: "100%",
6863
- source: "ChatEntry.usage"
6864
- });
6865
- } else {
6866
- finalTokens2 = TokenEstimator.estimateUsage(prompt, content2);
6867
- logger.warn("SDK did not provide token counts, using estimation", {
6868
- tokens: TokenEstimator.format(finalTokens2, true),
6869
- accuracy: "80-90% (estimated)",
6870
- source: "estimation"
6871
- });
6872
- }
6873
- }
6874
- const model2 = this.agent.getCurrentModel();
6875
- const finishReason2 = "stop";
6907
+ const tokensUsed2 = this.extractTokenUsage(
6908
+ prompt,
6909
+ content2,
6910
+ totalTokensFromEvents,
6911
+ lastAssistant.usage || lastAssistant.tokens,
6912
+ "ChatEntry.usage"
6913
+ );
6876
6914
  return {
6877
6915
  content: content2,
6878
- model: model2,
6879
- tokensUsed: finalTokens2,
6916
+ model: this.agent?.getCurrentModel() ?? "unknown",
6917
+ tokensUsed: tokensUsed2,
6880
6918
  latencyMs,
6881
- finishReason: finishReason2,
6919
+ finishReason: "stop",
6882
6920
  cached: false
6883
- // SDK doesn't expose cache status via ChatEntry
6884
6921
  };
6885
6922
  }
6886
6923
  const content = typeof result === "string" ? result : result.content || result.text || "";
6887
- let finalTokens;
6888
- if (totalTokensFromEvents > 0) {
6889
- const estimated = TokenEstimator.estimateUsage(prompt, content);
6890
- finalTokens = {
6891
- prompt: estimated.prompt,
6892
- completion: estimated.completion,
6893
- total: totalTokensFromEvents
6894
- };
6895
- logger.info("Using token count from SDK events (fallback path)", {
6896
- tokens: TokenEstimator.format(finalTokens),
6897
- accuracy: "100% (total), 80-90% (split)",
6898
- source: "token_count events"
6899
- });
6900
- } else {
6901
- const usage = result.usage || result.tokens || {};
6902
- const actualTokens = {
6903
- prompt: usage.prompt_tokens || usage.prompt || usage.input || usage.promptTokens || 0,
6904
- completion: usage.completion_tokens || usage.completion || usage.output || usage.completionTokens || 0,
6905
- total: usage.total_tokens || usage.total || usage.totalTokens || 0
6906
- };
6907
- const hasActualTokens = actualTokens.total > 0;
6908
- if (hasActualTokens) {
6909
- finalTokens = {
6910
- prompt: actualTokens.prompt,
6911
- completion: actualTokens.completion,
6912
- total: actualTokens.total
6913
- };
6914
- logger.info("Using token counts from response.usage (fallback path)", {
6915
- tokens: TokenEstimator.format(finalTokens),
6916
- accuracy: "100%",
6917
- source: "response.usage"
6918
- });
6919
- } else {
6920
- finalTokens = TokenEstimator.estimateUsage(prompt, content);
6921
- logger.warn("SDK did not provide token counts (fallback path), using estimation", {
6922
- tokens: TokenEstimator.format(finalTokens, true),
6923
- accuracy: "80-90% (estimated)",
6924
- source: "estimation"
6925
- });
6926
- }
6927
- }
6928
- const model = this.agent.getCurrentModel();
6929
- const finishReason = "stop";
6924
+ const tokensUsed = this.extractTokenUsage(
6925
+ prompt,
6926
+ content,
6927
+ totalTokensFromEvents,
6928
+ result.usage || result.tokens,
6929
+ "response.usage (fallback path)"
6930
+ );
6930
6931
  return {
6931
6932
  content,
6932
- model,
6933
- tokensUsed: finalTokens,
6933
+ model: this.agent?.getCurrentModel() ?? "unknown",
6934
+ tokensUsed,
6934
6935
  latencyMs,
6935
- finishReason,
6936
+ finishReason: "stop",
6936
6937
  cached: false
6937
- // SDK doesn't expose cache status
6938
6938
  };
6939
6939
  }
6940
+ /** Error mapping patterns: [patterns, prefix, code] */
6941
+ static ERROR_MAPPINGS = [
6942
+ [["rate limit", "rate_limit"], "Rate limit exceeded", "RATE_LIMIT_EXCEEDED"],
6943
+ [["context length", "max_tokens"], "Context length exceeded", "CONTEXT_LENGTH_EXCEEDED"],
6944
+ [["timeout", "timed out"], "Request timeout", "TIMEOUT"],
6945
+ [["invalid api key", "authentication"], "Authentication failed", "AUTHENTICATION_FAILED"],
6946
+ [["network", "econnrefused"], "Network error", "NETWORK_ERROR"]
6947
+ ];
6940
6948
  /**
6941
6949
  * Map SDK errors to AutomatosX error types
6942
6950
  */
@@ -6945,30 +6953,12 @@ var init_adapter2 = __esm({
6945
6953
  return new Error(`SDK error: ${String(error)}`);
6946
6954
  }
6947
6955
  const message = error.message.toLowerCase();
6948
- if (message.includes("rate limit") || message.includes("rate_limit")) {
6949
- const mappedError = new Error(`Rate limit exceeded: ${error.message}`);
6950
- mappedError.code = "RATE_LIMIT_EXCEEDED";
6951
- return mappedError;
6952
- }
6953
- if (message.includes("context length") || message.includes("max_tokens")) {
6954
- const mappedError = new Error(`Context length exceeded: ${error.message}`);
6955
- mappedError.code = "CONTEXT_LENGTH_EXCEEDED";
6956
- return mappedError;
6957
- }
6958
- if (message.includes("timeout") || message.includes("timed out")) {
6959
- const mappedError = new Error(`Request timeout: ${error.message}`);
6960
- mappedError.code = "TIMEOUT";
6961
- return mappedError;
6962
- }
6963
- if (message.includes("invalid api key") || message.includes("authentication")) {
6964
- const mappedError = new Error(`Authentication failed: ${error.message}`);
6965
- mappedError.code = "AUTHENTICATION_FAILED";
6966
- return mappedError;
6967
- }
6968
- if (message.includes("network") || message.includes("econnrefused")) {
6969
- const mappedError = new Error(`Network error: ${error.message}`);
6970
- mappedError.code = "NETWORK_ERROR";
6971
- return mappedError;
6956
+ for (const [patterns, prefix, code] of _AxCliSdkAdapter.ERROR_MAPPINGS) {
6957
+ if (patterns.some((pattern) => message.includes(pattern))) {
6958
+ const mappedError = new Error(`${prefix}: ${error.message}`);
6959
+ mappedError.code = code;
6960
+ return mappedError;
6961
+ }
6972
6962
  }
6973
6963
  return error;
6974
6964
  }
@@ -7003,15 +6993,10 @@ var init_adapter2 = __esm({
7003
6993
  * Get SDK version
7004
6994
  */
7005
6995
  async getVersion() {
7006
- try {
7007
- await import('@defai.digital/ax-cli/sdk');
6996
+ if (await this.ensureSDKAvailable()) {
7008
6997
  return "3.14.5+";
7009
- } catch (error) {
7010
- logger.warn("Failed to get SDK version", {
7011
- error: error instanceof Error ? error.message : String(error)
7012
- });
7013
- return "unknown";
7014
6998
  }
6999
+ return "unknown";
7015
7000
  }
7016
7001
  /**
7017
7002
  * Get command name (for compatibility with AxCliAdapter interface)
@@ -7031,7 +7016,10 @@ var init_adapter2 = __esm({
7031
7016
  async destroy() {
7032
7017
  if (this.agent) {
7033
7018
  try {
7034
- this.agent.dispose();
7019
+ const result = this.agent.dispose();
7020
+ if (result instanceof Promise) {
7021
+ await result;
7022
+ }
7035
7023
  this.agent = null;
7036
7024
  this.agentConfig = null;
7037
7025
  logger.debug("SDK agent destroyed");
@@ -9285,7 +9273,7 @@ var PRECOMPILED_CONFIG = {
9285
9273
  "enableFreeTierPrioritization": true,
9286
9274
  "enableWorkloadAwareRouting": true
9287
9275
  },
9288
- "version": "11.2.8"
9276
+ "version": "11.3.0"
9289
9277
  };
9290
9278
 
9291
9279
  // src/core/config/schemas.ts
@@ -15174,7 +15162,7 @@ function parseAXMD(content) {
15174
15162
  "Useful Links"
15175
15163
  ];
15176
15164
  for (const section of sections) {
15177
- const sectionName = section.split("\n")[0];
15165
+ const sectionName = section.split("\n")[0] ?? "";
15178
15166
  if (sectionName && !standardSections.includes(sectionName)) {
15179
15167
  result.customSections.push(sectionName);
15180
15168
  }
@@ -16567,6 +16555,8 @@ var ProviderLimitManager = class _ProviderLimitManager extends EventEmitter {
16567
16555
  getManualOverride() {
16568
16556
  if (this.manualOverride && this.manualOverride.expiresAtMs) {
16569
16557
  if (Date.now() >= this.manualOverride.expiresAtMs) {
16558
+ this.manualOverride;
16559
+ this.manualOverride = void 0;
16570
16560
  void this.clearManualOverride();
16571
16561
  return void 0;
16572
16562
  }
@@ -16907,19 +16897,33 @@ var ProviderMetricsTracker = class extends EventEmitter {
16907
16897
  const p50 = getPercentile(latencies, 50);
16908
16898
  const p95 = getPercentile(latencies, 95);
16909
16899
  const p99 = getPercentile(latencies, 99);
16910
- const successful = records.filter((r) => r.success);
16911
- const failed = records.filter((r) => !r.success);
16912
- const stopFinishes = successful.filter((r) => r.finishReason === "stop");
16913
- const lengthFinishes = successful.filter((r) => r.finishReason === "length");
16914
- const errorFinishes = records.filter((r) => r.finishReason === "error");
16915
- const successRate = successful.length / records.length;
16916
- const properStopRate = successful.length > 0 ? stopFinishes.length / successful.length : 0;
16900
+ let successCount = 0;
16901
+ let failCount = 0;
16902
+ let stopFinishCount = 0;
16903
+ let lengthFinishCount = 0;
16904
+ let errorFinishCount = 0;
16905
+ let lastSuccessTimestamp = 0;
16906
+ let lastFailureTimestamp = 0;
16907
+ for (const r of records) {
16908
+ if (r.success) {
16909
+ successCount++;
16910
+ lastSuccessTimestamp = r.timestamp;
16911
+ if (r.finishReason === "stop") stopFinishCount++;
16912
+ else if (r.finishReason === "length") lengthFinishCount++;
16913
+ } else {
16914
+ failCount++;
16915
+ lastFailureTimestamp = r.timestamp;
16916
+ }
16917
+ if (r.finishReason === "error") errorFinishCount++;
16918
+ }
16919
+ const successRate = successCount / records.length;
16920
+ const properStopRate = successCount > 0 ? stopFinishCount / successCount : 0;
16917
16921
  const totalCost = records.reduce((sum, r) => sum + r.costUsd, 0);
16918
16922
  const avgCostPerRequest = totalCost / records.length;
16919
16923
  const totalTokens = records.reduce((sum, r) => sum + r.totalTokens, 0);
16920
16924
  const avgCostPer1M = totalTokens > 0 ? totalCost / totalTokens * 1e6 : 0;
16921
- const lastSuccess = successful.length > 0 ? successful[successful.length - 1].timestamp : 0;
16922
- const lastFailure = failed.length > 0 ? failed[failed.length - 1].timestamp : 0;
16925
+ const lastSuccess = lastSuccessTimestamp;
16926
+ const lastFailure = lastFailureTimestamp;
16923
16927
  let consecutiveFailures = 0;
16924
16928
  for (let i = records.length - 1; i >= 0; i--) {
16925
16929
  if (!records[i].success) {
@@ -16942,12 +16946,12 @@ var ProviderMetricsTracker = class extends EventEmitter {
16942
16946
  },
16943
16947
  quality: {
16944
16948
  totalRequests: records.length,
16945
- successfulRequests: successful.length,
16946
- failedRequests: failed.length,
16949
+ successfulRequests: successCount,
16950
+ failedRequests: failCount,
16947
16951
  successRate,
16948
- stopFinishes: stopFinishes.length,
16949
- lengthFinishes: lengthFinishes.length,
16950
- errorFinishes: errorFinishes.length,
16952
+ stopFinishes: stopFinishCount,
16953
+ lengthFinishes: lengthFinishCount,
16954
+ errorFinishes: errorFinishCount,
16951
16955
  properStopRate
16952
16956
  },
16953
16957
  cost: {
@@ -17056,7 +17060,7 @@ var ProviderMetricsTracker = class extends EventEmitter {
17056
17060
  * v9.0.2: Added score caching to reduce redundant calculations
17057
17061
  */
17058
17062
  async calculateScore(provider, weights, allProviders, healthMultiplier = 1) {
17059
- const cacheKey = `${provider}-${JSON.stringify(weights)}-${healthMultiplier}`;
17063
+ const cacheKey = `${provider}-${weights.cost}-${weights.latency}-${weights.quality}-${weights.availability}-${healthMultiplier}`;
17060
17064
  const cached = this.scoreCache.get(cacheKey);
17061
17065
  const currentRequestCount = this.getRequestCount(provider);
17062
17066
  if (cached) {
@@ -18221,8 +18225,7 @@ var Router = class {
18221
18225
  }
18222
18226
  }
18223
18227
  if (limitedProviders2.length === allProviders2.length && limitedProviders2.length > 0) {
18224
- const soonestReset = Math.min(...limitedProviders2.map((p) => p.resetAtMs));
18225
- throw ProviderError.allProvidersLimited(limitedProviders2, soonestReset);
18228
+ throw ProviderError.allProvidersLimited(limitedProviders2, this.getSoonestLimitReset(limitedProviders2));
18226
18229
  }
18227
18230
  throw ProviderError.noAvailableProviders();
18228
18231
  }
@@ -18628,8 +18631,7 @@ var Router = class {
18628
18631
  }
18629
18632
  }
18630
18633
  if (limitedProviders.length === allProviders.length && limitedProviders.length > 0) {
18631
- const soonestReset = Math.min(...limitedProviders.map((p) => p.resetAtMs));
18632
- throw ProviderError.allProvidersLimited(limitedProviders, soonestReset);
18634
+ throw ProviderError.allProvidersLimited(limitedProviders, this.getSoonestLimitReset(limitedProviders));
18633
18635
  }
18634
18636
  const errorDetails = {
18635
18637
  lastError: lastError?.message,
@@ -18863,6 +18865,16 @@ Run 'ax doctor' to diagnose provider setup.` : "";
18863
18865
  })
18864
18866
  };
18865
18867
  }
18868
+ /**
18869
+ * Calculate the soonest reset time from limited providers
18870
+ * v11.2.8: Added guard against empty array (Math.min on empty array returns Infinity)
18871
+ */
18872
+ getSoonestLimitReset(limitedProviders) {
18873
+ if (limitedProviders.length === 0) {
18874
+ return Date.now() + 6e4;
18875
+ }
18876
+ return Math.min(...limitedProviders.map((p) => p.resetAtMs));
18877
+ }
18866
18878
  };
18867
18879
 
18868
18880
  // src/core/memory/lazy-manager.ts
@@ -20698,8 +20710,6 @@ z.object({
20698
20710
  limit: z.number().int().positive().max(1e4).optional(),
20699
20711
  offset: z.number().int().nonnegative().optional()
20700
20712
  }).strict();
20701
-
20702
- // src/core/session/manager.ts
20703
20713
  var SessionManager = class _SessionManager {
20704
20714
  /** Active sessions (in-memory, keyed by session ID) */
20705
20715
  activeSessions = /* @__PURE__ */ new Map();
@@ -20772,8 +20782,9 @@ var SessionManager = class _SessionManager {
20772
20782
  try {
20773
20783
  SessionManagerConfigSchema.parse(config);
20774
20784
  } catch (error) {
20785
+ const message = error instanceof ZodError ? error.message : String(error);
20775
20786
  throw new SessionError(
20776
- `Invalid session manager config: ${error.message}`,
20787
+ `Invalid session manager config: ${message}`,
20777
20788
  void 0,
20778
20789
  "invalid_configuration"
20779
20790
  );
@@ -22175,8 +22186,8 @@ var ProjectContextLoader = class {
22175
22186
  const projectMatch = markdown.match(/>\s*Project:\s*(.+?)$/im);
22176
22187
  if (projectMatch && projectMatch[1]) {
22177
22188
  const parts = projectMatch[1].trim().split(/\s+v/);
22178
- metadata.name = parts[0];
22179
- if (parts[1]) {
22189
+ metadata.name = parts[0] || "";
22190
+ if (parts.length > 1 && parts[1]) {
22180
22191
  metadata.version = parts[1];
22181
22192
  }
22182
22193
  }
@@ -29880,13 +29891,23 @@ var MetricsCollector = class {
29880
29891
  */
29881
29892
  getMetricsSummary(serverMetrics) {
29882
29893
  const totalServers = serverMetrics.length;
29883
- const healthyServers = serverMetrics.filter((m) => m.memoryUsageMB > 0).length;
29884
- const totalCpu = serverMetrics.reduce((sum, m) => sum + m.cpuUsagePercent, 0);
29885
- const totalMemory = serverMetrics.reduce((sum, m) => sum + m.memoryUsageMB, 0);
29886
- const totalRequests = serverMetrics.reduce((sum, m) => sum + m.totalRequests, 0);
29887
- const totalFailed = serverMetrics.reduce((sum, m) => sum + m.failedRequests, 0);
29888
- const totalRestarts = serverMetrics.reduce((sum, m) => sum + m.restartCount, 0);
29889
- const avgResponseTime = serverMetrics.length > 0 ? serverMetrics.reduce((sum, m) => sum + m.avgResponseTimeMs, 0) / serverMetrics.length : 0;
29894
+ let healthyServers = 0;
29895
+ let totalCpu = 0;
29896
+ let totalMemory = 0;
29897
+ let totalRequests = 0;
29898
+ let totalFailed = 0;
29899
+ let totalRestarts = 0;
29900
+ let totalResponseTime = 0;
29901
+ for (const m of serverMetrics) {
29902
+ if (m.memoryUsageMB > 0) healthyServers++;
29903
+ totalCpu += m.cpuUsagePercent;
29904
+ totalMemory += m.memoryUsageMB;
29905
+ totalRequests += m.totalRequests;
29906
+ totalFailed += m.failedRequests;
29907
+ totalRestarts += m.restartCount;
29908
+ totalResponseTime += m.avgResponseTimeMs;
29909
+ }
29910
+ const avgResponseTime = totalServers > 0 ? totalResponseTime / totalServers : 0;
29890
29911
  const errorRate = totalRequests > 0 ? totalFailed / totalRequests * 100 : 0;
29891
29912
  return {
29892
29913
  totalServers,
@@ -31758,7 +31779,7 @@ var addCommand = {
31758
31779
  throw new Error(`Invalid metadata JSON: ${error.message}`);
31759
31780
  }
31760
31781
  }
31761
- const embedding = new Array(1536).fill(0);
31782
+ const embedding = Array(1536).fill(0);
31762
31783
  const entry = await manager.add(argv.content, embedding, metadata);
31763
31784
  printSuccess("\nMemory entry added successfully\n");
31764
31785
  console.log(`${chalk5.bold("ID:")} ${chalk5.white(entry.id)}`);
@@ -34106,47 +34127,39 @@ ${action.modifications}`;
34106
34127
  * @param stage - Stage to execute
34107
34128
  * @param context - Stage context
34108
34129
  * @returns Stage task prompt
34130
+ * v11.2.8: Refactored to use array.join() for better string building performance
34109
34131
  */
34110
34132
  buildStageTask(stage, context) {
34111
- let prompt = `# Stage: ${stage.name}
34112
-
34113
- `;
34114
- prompt += `## Stage Description
34133
+ const parts = [
34134
+ `# Stage: ${stage.name}
34135
+ `,
34136
+ `## Stage Description
34115
34137
  ${stage.description}
34116
-
34117
- `;
34118
- prompt += `## Original Task
34138
+ `,
34139
+ `## Original Task
34119
34140
  ${context.task}
34120
-
34121
- `;
34141
+ `
34142
+ ];
34122
34143
  if (context.previousOutputs.length > 0) {
34123
- prompt += `## Previous Stage Outputs
34124
-
34125
- `;
34126
- context.previousOutputs.forEach((output, index) => {
34127
- prompt += `### Stage ${index + 1} Output
34144
+ parts.push(`## Previous Stage Outputs
34145
+ `);
34146
+ parts.push(...context.previousOutputs.map(
34147
+ (output, index) => `### Stage ${index + 1} Output
34128
34148
  ${output}
34129
-
34130
- `;
34131
- });
34149
+ `
34150
+ ));
34132
34151
  }
34133
34152
  if (stage.key_questions && stage.key_questions.length > 0) {
34134
- prompt += `## Key Questions to Address
34135
- `;
34136
- stage.key_questions.forEach((q) => prompt += `- ${q}
34137
- `);
34138
- prompt += `
34139
- `;
34153
+ parts.push(`## Key Questions to Address`);
34154
+ parts.push(...stage.key_questions.map((q) => `- ${q}`));
34155
+ parts.push("");
34140
34156
  }
34141
34157
  if (stage.outputs && stage.outputs.length > 0) {
34142
- prompt += `## Expected Outputs
34143
- `;
34144
- stage.outputs.forEach((o) => prompt += `- ${o}
34145
- `);
34146
- prompt += `
34147
- `;
34158
+ parts.push(`## Expected Outputs`);
34159
+ parts.push(...stage.outputs.map((o) => `- ${o}`));
34160
+ parts.push("");
34148
34161
  }
34149
- return prompt;
34162
+ return parts.join("\n");
34150
34163
  }
34151
34164
  /**
34152
34165
  * Enhance stages with index and defaults
@@ -36222,10 +36235,10 @@ var runCommand = {
36222
36235
  }).positional("task", {
36223
36236
  describe: "Task to execute",
36224
36237
  type: "string"
36225
- }).option("no-auto-select", {
36226
- describe: "Disable agent auto-selection (v11.1.0+)",
36238
+ }).option("auto-select", {
36239
+ describe: "Enable agent auto-selection when agent not found (v11.1.0+)",
36227
36240
  type: "boolean",
36228
- default: false
36241
+ default: true
36229
36242
  }).option("provider", {
36230
36243
  describe: "Override provider (claude, gemini, openai)",
36231
36244
  type: "string"
@@ -36367,7 +36380,7 @@ var runCommand = {
36367
36380
  console.log(chalk5.gray(' ax run backend "implement API" # uses specified agent'));
36368
36381
  process.exit(1);
36369
36382
  }
36370
- if (!agentProvided && argv.noAutoSelect) {
36383
+ if (!agentProvided && argv.autoSelect === false) {
36371
36384
  console.log(chalk5.red.bold("\n\u274C Error: Agent name is required when --no-auto-select is used\n"));
36372
36385
  console.log(chalk5.gray("Usage: ax run <agent> <task> --no-auto-select"));
36373
36386
  process.exit(1);
@@ -36502,7 +36515,7 @@ var runCommand = {
36502
36515
  }
36503
36516
  }
36504
36517
  } catch (error) {
36505
- if (argv.noAutoSelect) {
36518
+ if (argv.autoSelect === false) {
36506
36519
  console.error(chalk5.red.bold(`
36507
36520
  \u274C Agent not found: ${actualAgent}
36508
36521
  `));
@@ -44704,10 +44717,11 @@ function displayPlanSummary(plan) {
44704
44717
  console.log(chalk5.gray(` Storage: ${plan.resourceRequirements.storage}`));
44705
44718
  console.log(chalk5.gray(` Network: ${plan.resourceRequirements.network}
44706
44719
  `));
44720
+ const SEVERITY_ICONS = { high: "\u{1F534}", medium: "\u{1F7E1}", low: "\u{1F7E2}" };
44707
44721
  if (plan.risks.length > 0) {
44708
44722
  console.log(chalk5.blue("Identified Risks:"));
44709
44723
  for (const risk of plan.risks) {
44710
- const icon = risk.severity === "high" ? "\u{1F534}" : risk.severity === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
44724
+ const icon = SEVERITY_ICONS[risk.severity] ?? "\u{1F7E2}";
44711
44725
  console.log(` ${icon} ${risk.severity.toUpperCase()}: ${risk.title}`);
44712
44726
  console.log(chalk5.gray(` ${risk.description}`));
44713
44727
  console.log(chalk5.gray(` Mitigation: ${risk.mitigation}
@@ -44863,24 +44877,24 @@ async function handleList(config, argv) {
44863
44877
  });
44864
44878
  }
44865
44879
  }
44866
- let displayProviders = argv.available ? providers.filter((p) => p.enabled && !p.limitInfo?.isBlocked) : providers;
44880
+ let displayProviders2 = argv.available ? providers.filter((p) => p.enabled && !p.limitInfo?.isBlocked) : providers;
44867
44881
  switch (argv.sort) {
44868
44882
  case "cost":
44869
- displayProviders.sort((a, b) => {
44883
+ displayProviders2.sort((a, b) => {
44870
44884
  const costA = a.metadata ? (a.metadata.costPerToken.input + a.metadata.costPerToken.output) / 2 : Infinity;
44871
44885
  const costB = b.metadata ? (b.metadata.costPerToken.input + b.metadata.costPerToken.output) / 2 : Infinity;
44872
44886
  return costA - costB;
44873
44887
  });
44874
44888
  break;
44875
44889
  case "latency":
44876
- displayProviders.sort((a, b) => {
44890
+ displayProviders2.sort((a, b) => {
44877
44891
  const latA = a.metadata?.latencyEstimate.p95 || Infinity;
44878
44892
  const latB = b.metadata?.latencyEstimate.p95 || Infinity;
44879
44893
  return latA - latB;
44880
44894
  });
44881
44895
  break;
44882
44896
  case "reliability":
44883
- displayProviders.sort((a, b) => {
44897
+ displayProviders2.sort((a, b) => {
44884
44898
  const relA = a.metadata?.reliability.availability || 0;
44885
44899
  const relB = b.metadata?.reliability.availability || 0;
44886
44900
  return relB - relA;
@@ -44888,15 +44902,15 @@ async function handleList(config, argv) {
44888
44902
  break;
44889
44903
  case "priority":
44890
44904
  default:
44891
- displayProviders.sort((a, b) => a.priority - b.priority);
44905
+ displayProviders2.sort((a, b) => a.priority - b.priority);
44892
44906
  break;
44893
44907
  }
44894
44908
  if (argv.json) {
44895
- console.log(JSON.stringify({ providers: displayProviders }, null, 2));
44909
+ console.log(JSON.stringify({ providers: displayProviders2 }, null, 2));
44896
44910
  return;
44897
44911
  }
44898
44912
  console.log(chalk5.gray("Provider Status & Metadata:\n"));
44899
- for (const provider of displayProviders) {
44913
+ for (const provider of displayProviders2) {
44900
44914
  const status = provider.enabled ? provider.limitInfo?.isBlocked ? chalk5.red("\u25CF BLOCKED") : chalk5.green("\u25CF ENABLED") : chalk5.gray("\u25CB DISABLED");
44901
44915
  console.log(`${status} ${chalk5.bold(provider.name)} ${chalk5.gray(`(priority: ${provider.priority})`)}`);
44902
44916
  if (provider.metadata && argv.verbose) {
@@ -46143,9 +46157,11 @@ async function checkDiskSpace(workingDir, verbose) {
46143
46157
  timeout: 5e3
46144
46158
  });
46145
46159
  const parts = dfOutput.trim().split(/\s+/);
46146
- const availableKB = parseInt(parts[3] || "0", 10);
46147
- const availableMB = Math.round(availableKB / 1024);
46148
- const availableGB = (availableKB / (1024 * 1024)).toFixed(2);
46160
+ const rawAvailable = parts.length > 3 ? parts[3] : "0";
46161
+ const availableKB = parseInt(rawAvailable || "0", 10);
46162
+ const safeAvailableKB = isNaN(availableKB) ? 0 : availableKB;
46163
+ const availableMB = Math.round(safeAvailableKB / 1024);
46164
+ const availableGB = (safeAvailableKB / (1024 * 1024)).toFixed(2);
46149
46165
  const hasEnoughSpace = availableMB > 100;
46150
46166
  results.push({
46151
46167
  name: "Available Disk Space",
@@ -46833,37 +46849,38 @@ var TelemetryCollector = class {
46833
46849
  logger.warn("Query called on closed or uninitialized telemetry collector");
46834
46850
  return [];
46835
46851
  }
46836
- let sql = "SELECT * FROM telemetry_events WHERE 1=1";
46852
+ const conditions = [];
46837
46853
  const params = [];
46838
46854
  if (filters.provider) {
46839
- sql += " AND provider = ?";
46855
+ conditions.push("provider = ?");
46840
46856
  params.push(filters.provider);
46841
46857
  }
46842
46858
  if (filters.agentName) {
46843
- sql += " AND agent_name = ?";
46859
+ conditions.push("agent_name = ?");
46844
46860
  params.push(filters.agentName);
46845
46861
  }
46846
46862
  if (filters.sessionId) {
46847
- sql += " AND session_id = ?";
46863
+ conditions.push("session_id = ?");
46848
46864
  params.push(filters.sessionId);
46849
46865
  }
46850
46866
  if (filters.type) {
46851
- sql += " AND type = ?";
46867
+ conditions.push("type = ?");
46852
46868
  params.push(filters.type);
46853
46869
  }
46854
46870
  if (filters.startDate) {
46855
- sql += " AND timestamp >= ?";
46871
+ conditions.push("timestamp >= ?");
46856
46872
  params.push(filters.startDate);
46857
46873
  }
46858
46874
  if (filters.endDate) {
46859
- sql += " AND timestamp <= ?";
46875
+ conditions.push("timestamp <= ?");
46860
46876
  params.push(filters.endDate);
46861
46877
  }
46862
46878
  if (filters.success !== void 0) {
46863
- sql += " AND success = ?";
46879
+ conditions.push("success = ?");
46864
46880
  params.push(filters.success ? 1 : 0);
46865
46881
  }
46866
- sql += " ORDER BY timestamp DESC LIMIT ?";
46882
+ const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
46883
+ const sql = `SELECT * FROM telemetry_events ${whereClause} ORDER BY timestamp DESC LIMIT ?`;
46867
46884
  params.push(filters.limit || 1e3);
46868
46885
  const rows = this.db.prepare(sql).all(...params);
46869
46886
  return rows.map((row) => this.mapRowToEvent(row));
@@ -46877,20 +46894,22 @@ var TelemetryCollector = class {
46877
46894
  if (this.closed || !this.db) {
46878
46895
  return 0;
46879
46896
  }
46880
- let sql = "SELECT COUNT(*) as count FROM telemetry_events WHERE 1=1";
46897
+ const conditions = [];
46881
46898
  const params = [];
46882
46899
  if (filters.provider) {
46883
- sql += " AND provider = ?";
46900
+ conditions.push("provider = ?");
46884
46901
  params.push(filters.provider);
46885
46902
  }
46886
46903
  if (filters.startDate) {
46887
- sql += " AND timestamp >= ?";
46904
+ conditions.push("timestamp >= ?");
46888
46905
  params.push(filters.startDate);
46889
46906
  }
46890
46907
  if (filters.endDate) {
46891
- sql += " AND timestamp <= ?";
46908
+ conditions.push("timestamp <= ?");
46892
46909
  params.push(filters.endDate);
46893
46910
  }
46911
+ const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
46912
+ const sql = `SELECT COUNT(*) as count FROM telemetry_events ${whereClause}`;
46894
46913
  const result = this.db.prepare(sql).get(...params);
46895
46914
  return result.count;
46896
46915
  }
@@ -47610,9 +47629,11 @@ async function optimizeHandler(argv) {
47610
47629
  console.log(chalk5.green("\u2705 No optimization opportunities found. You're doing great!\n"));
47611
47630
  return;
47612
47631
  }
47632
+ const TYPE_ICONS = { cost_saving: "\u{1F4B0}", performance: "\u26A1", security: "\u{1F512}" };
47633
+ const SEVERITY_COLORS = { high: chalk5.red, medium: chalk5.yellow, low: chalk5.gray };
47613
47634
  for (const rec of recommendations) {
47614
- const icon = rec.type === "cost_saving" ? "\u{1F4B0}" : rec.type === "performance" ? "\u26A1" : "\u{1F512}";
47615
- const severityColor = rec.severity === "high" ? chalk5.red : rec.severity === "medium" ? chalk5.yellow : chalk5.gray;
47635
+ const icon = TYPE_ICONS[rec.type] ?? "\u{1F512}";
47636
+ const severityColor = SEVERITY_COLORS[rec.severity] ?? chalk5.gray;
47616
47637
  console.log(`${icon} ${severityColor(rec.severity.toUpperCase())}: ${chalk5.bold(rec.title)}`);
47617
47638
  console.log(` ${rec.description}`);
47618
47639
  if (rec.estimatedSavings) {
@@ -48510,6 +48531,2880 @@ var uninstallCommand = {
48510
48531
  }
48511
48532
  };
48512
48533
 
48534
+ // src/cli/commands/mode.ts
48535
+ init_esm_shims();
48536
+ init_logger();
48537
+
48538
+ // src/core/workflow/index.ts
48539
+ init_esm_shims();
48540
+
48541
+ // src/core/workflow/workflow-mode.ts
48542
+ init_esm_shims();
48543
+ var WorkflowModeSchema = z.enum(["default", "plan", "iterate", "review"]);
48544
+ z.object({
48545
+ name: WorkflowModeSchema,
48546
+ description: z.string(),
48547
+ displayName: z.string(),
48548
+ allowedTools: z.array(z.string()).optional(),
48549
+ blockedTools: z.array(z.string()).optional(),
48550
+ systemInstructions: z.string(),
48551
+ allowNesting: z.boolean(),
48552
+ maxNestingDepth: z.number().int().positive().optional(),
48553
+ autoExitConditions: z.object({
48554
+ maxTurns: z.number().int().positive().optional(),
48555
+ onToolUse: z.array(z.string()).optional(),
48556
+ onKeywords: z.array(z.string()).optional()
48557
+ }).optional()
48558
+ });
48559
+ var WRITE_TOOLS = [
48560
+ "Write",
48561
+ "Edit",
48562
+ "NotebookEdit",
48563
+ "Bash"
48564
+ ];
48565
+ var DEFAULT_MODE_CONFIG = {
48566
+ name: "default",
48567
+ displayName: "Default",
48568
+ description: "Standard operation mode with all tools available",
48569
+ systemInstructions: "",
48570
+ allowNesting: true,
48571
+ maxNestingDepth: 3
48572
+ };
48573
+ var PLAN_MODE_CONFIG = {
48574
+ name: "plan",
48575
+ displayName: "Plan Mode",
48576
+ description: "Planning mode - read-only exploration without code modifications",
48577
+ blockedTools: [...WRITE_TOOLS],
48578
+ systemInstructions: `## Plan Mode Active
48579
+
48580
+ You are in **Plan Mode**. This mode is for exploration and planning only.
48581
+
48582
+ **Restrictions:**
48583
+ - You CANNOT use Write, Edit, or Bash tools that modify files
48584
+ - Focus on reading, searching, and understanding the codebase
48585
+ - Create a comprehensive plan before implementation
48586
+
48587
+ **Your Goals:**
48588
+ 1. Explore the codebase to understand existing patterns
48589
+ 2. Identify files that need to be modified
48590
+ 3. Design an implementation approach
48591
+ 4. Document your plan clearly
48592
+ 5. Use ExitPlanMode when ready to implement
48593
+
48594
+ **Remember:** No code modifications in this mode. Plan first, implement later.`,
48595
+ allowNesting: false,
48596
+ autoExitConditions: {
48597
+ onToolUse: ["ExitPlanMode"]
48598
+ }
48599
+ };
48600
+ var ITERATE_MODE_CONFIG = {
48601
+ name: "iterate",
48602
+ displayName: "Iterate Mode",
48603
+ description: "Continuous iteration mode for implementation with automatic continuation",
48604
+ systemInstructions: `## Iterate Mode Active
48605
+
48606
+ You are in **Iterate Mode**. This mode enables continuous task execution.
48607
+
48608
+ **Behavior:**
48609
+ - Continue working until the task is complete
48610
+ - After each step, assess progress and continue
48611
+ - Don't stop to ask for confirmation unless critical
48612
+ - Mark todos as completed as you finish them
48613
+
48614
+ **Guidelines:**
48615
+ 1. Work through tasks systematically
48616
+ 2. Test changes as you go when possible
48617
+ 3. Update todo list to track progress
48618
+ 4. Only pause for critical decisions or blockers
48619
+
48620
+ **Remember:** Keep iterating until the task is done or you hit a blocker.`,
48621
+ allowNesting: true,
48622
+ maxNestingDepth: 2
48623
+ };
48624
+ var REVIEW_MODE_CONFIG = {
48625
+ name: "review",
48626
+ displayName: "Review Mode",
48627
+ description: "Code review mode - analyze code quality, security, and best practices",
48628
+ blockedTools: [...WRITE_TOOLS],
48629
+ systemInstructions: `## Review Mode Active
48630
+
48631
+ You are in **Review Mode**. This mode is for code review and analysis.
48632
+
48633
+ **Focus Areas:**
48634
+ - Code quality and readability
48635
+ - Security vulnerabilities (OWASP Top 10)
48636
+ - Performance issues
48637
+ - Best practices and patterns
48638
+ - Test coverage gaps
48639
+
48640
+ **Output Format:**
48641
+ Provide structured feedback:
48642
+ 1. **Critical Issues** - Must fix before merge
48643
+ 2. **Warnings** - Should address
48644
+ 3. **Suggestions** - Nice to have improvements
48645
+ 4. **Positive Notes** - Good patterns observed
48646
+
48647
+ **Remember:** No code modifications. Provide actionable feedback only.`,
48648
+ allowNesting: false
48649
+ };
48650
+ var WORKFLOW_MODE_CONFIGS = {
48651
+ default: DEFAULT_MODE_CONFIG,
48652
+ plan: PLAN_MODE_CONFIG,
48653
+ iterate: ITERATE_MODE_CONFIG,
48654
+ review: REVIEW_MODE_CONFIG
48655
+ };
48656
+ function getWorkflowModeConfig(mode) {
48657
+ return WORKFLOW_MODE_CONFIGS[mode];
48658
+ }
48659
+ function isToolAllowedInMode(tool, mode) {
48660
+ const config = getWorkflowModeConfig(mode);
48661
+ if (config.allowedTools && config.allowedTools.length > 0) {
48662
+ return config.allowedTools.includes(tool);
48663
+ }
48664
+ if (config.blockedTools && config.blockedTools.length > 0) {
48665
+ return !config.blockedTools.includes(tool);
48666
+ }
48667
+ return true;
48668
+ }
48669
+ function isValidWorkflowMode(mode) {
48670
+ return mode in WORKFLOW_MODE_CONFIGS;
48671
+ }
48672
+ var WORKFLOW_MODES = WORKFLOW_MODE_CONFIGS;
48673
+
48674
+ // src/core/workflow/workflow-mode-manager.ts
48675
+ init_esm_shims();
48676
+ init_logger();
48677
+ var WorkflowModeManager = class {
48678
+ name = "workflow-mode";
48679
+ modeStack = [];
48680
+ transitionListeners = /* @__PURE__ */ new Set();
48681
+ turnCount = 0;
48682
+ constructor(initialMode = "default") {
48683
+ this.modeStack.push({
48684
+ mode: initialMode,
48685
+ enteredAt: Date.now(),
48686
+ enteredAtTurn: 0,
48687
+ reason: "initial"
48688
+ });
48689
+ logger.debug("WorkflowModeManager initialized", {
48690
+ initialMode
48691
+ });
48692
+ }
48693
+ /**
48694
+ * Get the current active mode
48695
+ */
48696
+ getCurrentMode() {
48697
+ const top = this.modeStack[this.modeStack.length - 1];
48698
+ return top?.mode ?? "default";
48699
+ }
48700
+ /**
48701
+ * Get the current mode configuration
48702
+ */
48703
+ getCurrentModeConfig() {
48704
+ const mode = this.getCurrentMode();
48705
+ const entry = this.modeStack[this.modeStack.length - 1];
48706
+ const baseConfig = getWorkflowModeConfig(mode);
48707
+ if (entry?.customConfig) {
48708
+ return {
48709
+ ...baseConfig,
48710
+ ...entry.customConfig,
48711
+ // Deep merge for nested objects
48712
+ autoExitConditions: {
48713
+ ...baseConfig.autoExitConditions,
48714
+ ...entry.customConfig.autoExitConditions
48715
+ }
48716
+ };
48717
+ }
48718
+ return baseConfig;
48719
+ }
48720
+ /**
48721
+ * Get the full mode stack
48722
+ */
48723
+ getModeStack() {
48724
+ return [...this.modeStack];
48725
+ }
48726
+ /**
48727
+ * Get the current stack depth
48728
+ */
48729
+ getStackDepth() {
48730
+ return this.modeStack.length;
48731
+ }
48732
+ /**
48733
+ * Push a new mode onto the stack
48734
+ */
48735
+ pushMode(mode, options) {
48736
+ const currentConfig = this.getCurrentModeConfig();
48737
+ if (!currentConfig.allowNesting) {
48738
+ logger.warn("Cannot push mode: current mode does not allow nesting", {
48739
+ currentMode: this.getCurrentMode(),
48740
+ attemptedMode: mode
48741
+ });
48742
+ return false;
48743
+ }
48744
+ const maxDepth = currentConfig.maxNestingDepth ?? 3;
48745
+ if (this.modeStack.length >= maxDepth) {
48746
+ logger.warn("Cannot push mode: max nesting depth reached", {
48747
+ currentDepth: this.modeStack.length,
48748
+ maxDepth
48749
+ });
48750
+ return false;
48751
+ }
48752
+ const previousMode = this.getCurrentMode();
48753
+ this.modeStack.push({
48754
+ mode,
48755
+ enteredAt: Date.now(),
48756
+ enteredAtTurn: this.turnCount,
48757
+ customConfig: options?.customConfig,
48758
+ reason: options?.reason
48759
+ });
48760
+ this.emitTransition({
48761
+ from: previousMode,
48762
+ to: mode,
48763
+ type: "push",
48764
+ timestamp: Date.now(),
48765
+ reason: options?.reason
48766
+ });
48767
+ logger.info("Pushed workflow mode", {
48768
+ from: previousMode,
48769
+ to: mode,
48770
+ stackDepth: this.modeStack.length,
48771
+ reason: options?.reason
48772
+ });
48773
+ return true;
48774
+ }
48775
+ /**
48776
+ * Pop the current mode from the stack
48777
+ */
48778
+ popMode(reason) {
48779
+ if (this.modeStack.length <= 1) {
48780
+ logger.warn("Cannot pop mode: at base level");
48781
+ return null;
48782
+ }
48783
+ const popped = this.modeStack.pop();
48784
+ const newMode = this.getCurrentMode();
48785
+ if (popped) {
48786
+ this.emitTransition({
48787
+ from: popped.mode,
48788
+ to: newMode,
48789
+ type: "pop",
48790
+ timestamp: Date.now(),
48791
+ reason
48792
+ });
48793
+ logger.info("Popped workflow mode", {
48794
+ from: popped.mode,
48795
+ to: newMode,
48796
+ stackDepth: this.modeStack.length,
48797
+ reason
48798
+ });
48799
+ }
48800
+ return popped?.mode ?? null;
48801
+ }
48802
+ /**
48803
+ * Replace the current mode (pop then push)
48804
+ */
48805
+ replaceMode(mode, options) {
48806
+ const previousMode = this.getCurrentMode();
48807
+ if (this.modeStack.length === 1) {
48808
+ this.modeStack[0] = {
48809
+ mode,
48810
+ enteredAt: Date.now(),
48811
+ enteredAtTurn: this.turnCount,
48812
+ customConfig: options?.customConfig,
48813
+ reason: options?.reason
48814
+ };
48815
+ } else {
48816
+ this.modeStack.pop();
48817
+ this.modeStack.push({
48818
+ mode,
48819
+ enteredAt: Date.now(),
48820
+ enteredAtTurn: this.turnCount,
48821
+ customConfig: options?.customConfig,
48822
+ reason: options?.reason
48823
+ });
48824
+ }
48825
+ this.emitTransition({
48826
+ from: previousMode,
48827
+ to: mode,
48828
+ type: "replace",
48829
+ timestamp: Date.now(),
48830
+ reason: options?.reason
48831
+ });
48832
+ logger.info("Replaced workflow mode", {
48833
+ from: previousMode,
48834
+ to: mode,
48835
+ reason: options?.reason
48836
+ });
48837
+ return true;
48838
+ }
48839
+ /**
48840
+ * Set mode directly (clears stack and sets new base mode)
48841
+ */
48842
+ setMode(mode, options) {
48843
+ const previousMode = this.getCurrentMode();
48844
+ this.modeStack = [{
48845
+ mode,
48846
+ enteredAt: Date.now(),
48847
+ enteredAtTurn: this.turnCount,
48848
+ customConfig: options?.customConfig,
48849
+ reason: options?.reason
48850
+ }];
48851
+ this.emitTransition({
48852
+ from: previousMode,
48853
+ to: mode,
48854
+ type: "replace",
48855
+ timestamp: Date.now(),
48856
+ reason: options?.reason
48857
+ });
48858
+ logger.info("Set workflow mode", {
48859
+ from: previousMode,
48860
+ to: mode,
48861
+ reason: options?.reason
48862
+ });
48863
+ }
48864
+ /**
48865
+ * Check if a tool is allowed in the current mode
48866
+ */
48867
+ isToolAllowed(tool) {
48868
+ return isToolAllowedInMode(tool, this.getCurrentMode());
48869
+ }
48870
+ /**
48871
+ * Get list of blocked tools in current mode
48872
+ */
48873
+ getBlockedTools() {
48874
+ const config = this.getCurrentModeConfig();
48875
+ return config.blockedTools || [];
48876
+ }
48877
+ /**
48878
+ * Filter a list of tools based on current mode
48879
+ */
48880
+ filterTools(tools) {
48881
+ return tools.filter((tool) => this.isToolAllowed(tool.name));
48882
+ }
48883
+ /**
48884
+ * Update turn count (for auto-exit tracking)
48885
+ */
48886
+ updateTurnCount(turn) {
48887
+ this.turnCount = turn;
48888
+ this.checkAutoExit();
48889
+ }
48890
+ /**
48891
+ * Check and handle auto-exit conditions
48892
+ */
48893
+ checkAutoExit() {
48894
+ const config = this.getCurrentModeConfig();
48895
+ const entry = this.modeStack[this.modeStack.length - 1];
48896
+ if (!config.autoExitConditions || !entry) return;
48897
+ if (config.autoExitConditions.maxTurns) {
48898
+ const turnsInMode = this.turnCount - entry.enteredAtTurn;
48899
+ if (turnsInMode >= config.autoExitConditions.maxTurns) {
48900
+ logger.info("Auto-exiting mode due to max turns", {
48901
+ mode: this.getCurrentMode(),
48902
+ turnsInMode,
48903
+ maxTurns: config.autoExitConditions.maxTurns
48904
+ });
48905
+ this.popMode("max_turns_reached");
48906
+ }
48907
+ }
48908
+ }
48909
+ /**
48910
+ * Notify that a tool was used (for auto-exit on tool use)
48911
+ */
48912
+ notifyToolUsed(tool) {
48913
+ const config = this.getCurrentModeConfig();
48914
+ if (config.autoExitConditions?.onToolUse?.includes(tool)) {
48915
+ logger.info("Auto-exiting mode due to tool use", {
48916
+ mode: this.getCurrentMode(),
48917
+ tool
48918
+ });
48919
+ this.popMode(`tool_used:${tool}`);
48920
+ }
48921
+ }
48922
+ /**
48923
+ * Add a mode transition listener
48924
+ */
48925
+ onTransition(listener) {
48926
+ this.transitionListeners.add(listener);
48927
+ return () => this.transitionListeners.delete(listener);
48928
+ }
48929
+ /**
48930
+ * Emit a transition event to all listeners
48931
+ */
48932
+ emitTransition(event) {
48933
+ for (const listener of this.transitionListeners) {
48934
+ try {
48935
+ listener(event);
48936
+ } catch (error) {
48937
+ logger.error("Mode transition listener error", {
48938
+ error: error instanceof Error ? error.message : String(error)
48939
+ });
48940
+ }
48941
+ }
48942
+ }
48943
+ // InstructionProvider implementation
48944
+ /**
48945
+ * Check if mode instructions should be generated
48946
+ */
48947
+ shouldGenerate(context) {
48948
+ return this.getCurrentMode() !== "default";
48949
+ }
48950
+ /**
48951
+ * Get mode-specific instructions
48952
+ */
48953
+ async getInstructions(context) {
48954
+ const config = this.getCurrentModeConfig();
48955
+ const instructions = [];
48956
+ if (config.systemInstructions && config.systemInstructions.length > 0) {
48957
+ instructions.push({
48958
+ type: "mode",
48959
+ priority: "high",
48960
+ content: config.systemInstructions,
48961
+ source: "automatosx",
48962
+ createdAt: Date.now(),
48963
+ id: `mode-${config.name}-${Date.now()}`
48964
+ });
48965
+ }
48966
+ if (config.blockedTools && config.blockedTools.length > 0) {
48967
+ instructions.push({
48968
+ type: "mode",
48969
+ priority: "critical",
48970
+ content: `**Tool Restrictions:** The following tools are NOT available in ${config.displayName}: ${config.blockedTools.join(", ")}`,
48971
+ source: "automatosx",
48972
+ createdAt: Date.now(),
48973
+ id: `mode-blocked-tools-${Date.now()}`
48974
+ });
48975
+ }
48976
+ return instructions;
48977
+ }
48978
+ /**
48979
+ * Reset to default state
48980
+ */
48981
+ reset() {
48982
+ const previousMode = this.getCurrentMode();
48983
+ this.modeStack = [{
48984
+ mode: "default",
48985
+ enteredAt: Date.now(),
48986
+ enteredAtTurn: 0,
48987
+ reason: "reset"
48988
+ }];
48989
+ this.turnCount = 0;
48990
+ if (previousMode !== "default") {
48991
+ this.emitTransition({
48992
+ from: previousMode,
48993
+ to: "default",
48994
+ type: "replace",
48995
+ timestamp: Date.now(),
48996
+ reason: "reset"
48997
+ });
48998
+ }
48999
+ logger.debug("WorkflowModeManager reset");
49000
+ }
49001
+ /**
49002
+ * Get status information for debugging
49003
+ */
49004
+ getStatus() {
49005
+ return {
49006
+ currentMode: this.getCurrentMode(),
49007
+ stackDepth: this.modeStack.length,
49008
+ stack: this.modeStack.map((entry) => ({
49009
+ mode: entry.mode,
49010
+ enteredAt: entry.enteredAt,
49011
+ reason: entry.reason
49012
+ })),
49013
+ blockedTools: this.getBlockedTools(),
49014
+ turnCount: this.turnCount
49015
+ };
49016
+ }
49017
+ };
49018
+
49019
+ // src/cli/commands/mode.ts
49020
+ var modeCommand = {
49021
+ command: "mode [mode]",
49022
+ describe: "Manage workflow modes for embedded instructions (v11.3.0)",
49023
+ builder: (yargs2) => {
49024
+ return yargs2.positional("mode", {
49025
+ describe: "Workflow mode to set (default, plan, iterate, review)",
49026
+ type: "string"
49027
+ }).option("list", {
49028
+ alias: "l",
49029
+ describe: "List available workflow modes",
49030
+ type: "boolean",
49031
+ default: false
49032
+ }).option("status", {
49033
+ alias: "s",
49034
+ describe: "Show current workflow mode status",
49035
+ type: "boolean",
49036
+ default: false
49037
+ }).example("$0 mode plan", "Enter plan mode (restricts code-modifying tools)").example("$0 mode iterate", "Enter iterate mode (for autonomous execution)").example("$0 mode default", "Return to default mode").example("$0 mode --list", "List all available modes").example("$0 mode --status", "Show current mode status");
49038
+ },
49039
+ handler: async (argv) => {
49040
+ try {
49041
+ if (argv.list) {
49042
+ displayModeList();
49043
+ return;
49044
+ }
49045
+ if (argv.status || !argv.mode) {
49046
+ displayModeStatus();
49047
+ return;
49048
+ }
49049
+ const modeName = argv.mode.toLowerCase();
49050
+ if (!isValidWorkflowMode(modeName)) {
49051
+ console.error(chalk5.red.bold(`
49052
+ \u274C Invalid workflow mode: ${argv.mode}
49053
+ `));
49054
+ console.log(chalk5.gray("Available modes:"));
49055
+ Object.keys(WORKFLOW_MODES).forEach((mode) => {
49056
+ console.log(chalk5.cyan(` \u2022 ${mode}`));
49057
+ });
49058
+ console.log();
49059
+ process.exit(1);
49060
+ }
49061
+ const modeConfig = WORKFLOW_MODES[modeName];
49062
+ console.log(chalk5.green.bold(`
49063
+ \u2705 Workflow mode set to: ${modeName}
49064
+ `));
49065
+ console.log(chalk5.gray(`Description: ${modeConfig.description}`));
49066
+ if (modeConfig.blockedTools && modeConfig.blockedTools.length > 0) {
49067
+ console.log(chalk5.yellow("\nRestricted tools in this mode:"));
49068
+ modeConfig.blockedTools.forEach((tool) => {
49069
+ console.log(chalk5.yellow(` \u2022 ${tool}`));
49070
+ });
49071
+ }
49072
+ if (modeConfig.allowedTools && modeConfig.allowedTools.length > 0) {
49073
+ console.log(chalk5.cyan("\nAllowed tools in this mode:"));
49074
+ modeConfig.allowedTools.forEach((tool) => {
49075
+ console.log(chalk5.cyan(` \u2022 ${tool}`));
49076
+ });
49077
+ }
49078
+ console.log();
49079
+ console.log(chalk5.gray("Note: Mode setting applies to the current session."));
49080
+ console.log(chalk5.gray("Use with --iterate flag in ax run for persistent mode.\n"));
49081
+ logger.info("Workflow mode set", { mode: modeName });
49082
+ } catch (error) {
49083
+ const err = error instanceof Error ? error : new Error(String(error));
49084
+ console.error(chalk5.red.bold(`
49085
+ \u274C Error: ${err.message}
49086
+ `));
49087
+ logger.error("Mode command failed", { error: err.message });
49088
+ process.exit(1);
49089
+ }
49090
+ }
49091
+ };
49092
+ function displayModeList() {
49093
+ console.log(chalk5.blue.bold("\n\u{1F4CB} Available Workflow Modes\n"));
49094
+ console.log(chalk5.dim("\u2500".repeat(60)));
49095
+ for (const [name, config] of Object.entries(WORKFLOW_MODES)) {
49096
+ console.log();
49097
+ console.log(chalk5.cyan.bold(` ${name}`));
49098
+ console.log(chalk5.gray(` ${config.description}`));
49099
+ if (config.blockedTools && config.blockedTools.length > 0) {
49100
+ console.log(chalk5.yellow(` Blocked: ${config.blockedTools.join(", ")}`));
49101
+ }
49102
+ if (config.maxNestingDepth !== void 0) {
49103
+ console.log(chalk5.gray(` Max nesting depth: ${config.maxNestingDepth}`));
49104
+ }
49105
+ }
49106
+ console.log();
49107
+ console.log(chalk5.dim("\u2500".repeat(60)));
49108
+ console.log(chalk5.gray("\nUsage: ax mode <mode-name>"));
49109
+ console.log(chalk5.gray("Example: ax mode plan\n"));
49110
+ }
49111
+ function displayModeStatus() {
49112
+ const currentMode = "default";
49113
+ const modeConfig = WORKFLOW_MODES[currentMode];
49114
+ console.log(chalk5.blue.bold("\n\u{1F4CA} Workflow Mode Status\n"));
49115
+ console.log(chalk5.dim("\u2500".repeat(50)));
49116
+ console.log(` Current mode: ${chalk5.cyan.bold(currentMode)}`);
49117
+ console.log(` Description: ${chalk5.gray(modeConfig.description)}`);
49118
+ if (modeConfig.blockedTools && modeConfig.blockedTools.length > 0) {
49119
+ console.log(` Blocked tools: ${chalk5.yellow(modeConfig.blockedTools.length)}`);
49120
+ } else {
49121
+ console.log(` Blocked tools: ${chalk5.green("none")}`);
49122
+ }
49123
+ console.log(chalk5.dim("\u2500".repeat(50)));
49124
+ console.log();
49125
+ console.log(chalk5.gray("To change mode: ax mode <mode-name>"));
49126
+ console.log(chalk5.gray("To list modes: ax mode --list\n"));
49127
+ }
49128
+
49129
+ // src/cli/commands/debug-instructions.ts
49130
+ init_esm_shims();
49131
+ init_logger();
49132
+
49133
+ // src/core/orchestration/orchestration-service.ts
49134
+ init_esm_shims();
49135
+ init_logger();
49136
+
49137
+ // src/core/orchestration/types.ts
49138
+ init_esm_shims();
49139
+ z.object({
49140
+ type: z.enum(["task", "memory", "session", "delegation", "mode"]),
49141
+ priority: z.enum(["critical", "high", "normal", "low"]),
49142
+ content: z.string().min(1).max(5e3),
49143
+ source: z.literal("automatosx"),
49144
+ expiresAfter: z.number().int().positive().optional(),
49145
+ createdAt: z.number(),
49146
+ id: z.string().optional()
49147
+ });
49148
+ var TodoItemSchema = z.object({
49149
+ id: z.string(),
49150
+ content: z.string().min(1).max(1e3),
49151
+ status: z.enum(["pending", "in_progress", "completed"]),
49152
+ activeForm: z.string().min(1).max(1e3),
49153
+ createdAt: z.number(),
49154
+ updatedAt: z.number().optional(),
49155
+ metadata: z.record(z.string(), z.unknown()).optional()
49156
+ });
49157
+ z.object({
49158
+ name: z.enum(["default", "plan", "iterate", "review"]),
49159
+ description: z.string(),
49160
+ allowedTools: z.array(z.string()).optional(),
49161
+ blockedTools: z.array(z.string()).optional(),
49162
+ systemInstructions: z.string(),
49163
+ allowNesting: z.boolean()
49164
+ });
49165
+ z.object({
49166
+ todos: z.array(TodoItemSchema),
49167
+ currentTask: z.string().optional(),
49168
+ agentName: z.string().optional(),
49169
+ turnCount: z.number().int().nonnegative(),
49170
+ workflowMode: z.enum(["default", "plan", "iterate", "review"]),
49171
+ sessionId: z.string().optional(),
49172
+ parentAgent: z.string().optional(),
49173
+ memories: z.array(z.object({
49174
+ content: z.string(),
49175
+ relevance: z.number().min(0).max(1),
49176
+ agent: z.string().optional(),
49177
+ timestamp: z.number()
49178
+ })).optional()
49179
+ });
49180
+ var DEFAULT_TOKEN_BUDGET = {
49181
+ maxTotal: 2e3,
49182
+ perType: {
49183
+ task: 500,
49184
+ memory: 600,
49185
+ session: 300,
49186
+ delegation: 200,
49187
+ mode: 400
49188
+ },
49189
+ criticalReserve: 300
49190
+ };
49191
+ var TokenBudgetConfigSchema = z.object({
49192
+ maxTotal: z.number().int().positive().max(1e4),
49193
+ perType: z.record(
49194
+ z.enum(["task", "memory", "session", "delegation", "mode"]),
49195
+ z.number().int().nonnegative()
49196
+ ),
49197
+ criticalReserve: z.number().int().nonnegative()
49198
+ });
49199
+ var DEFAULT_ORCHESTRATION_CONFIG = {
49200
+ enabled: true,
49201
+ tokenBudget: DEFAULT_TOKEN_BUDGET,
49202
+ todoIntegration: {
49203
+ enabled: true,
49204
+ reminderFrequency: 3,
49205
+ compactMode: false
49206
+ },
49207
+ memoryIntegration: {
49208
+ enabled: true,
49209
+ maxEntries: 5,
49210
+ minRelevance: 0.5
49211
+ },
49212
+ sessionIntegration: {
49213
+ enabled: true,
49214
+ showCollaboration: true
49215
+ },
49216
+ agentTemplates: {
49217
+ enabled: true,
49218
+ reminderFrequency: 5
49219
+ }
49220
+ };
49221
+ z.object({
49222
+ enabled: z.boolean(),
49223
+ tokenBudget: TokenBudgetConfigSchema,
49224
+ todoIntegration: z.object({
49225
+ enabled: z.boolean(),
49226
+ reminderFrequency: z.number().int().positive(),
49227
+ compactMode: z.boolean()
49228
+ }),
49229
+ memoryIntegration: z.object({
49230
+ enabled: z.boolean(),
49231
+ maxEntries: z.number().int().nonnegative(),
49232
+ minRelevance: z.number().min(0).max(1)
49233
+ }),
49234
+ sessionIntegration: z.object({
49235
+ enabled: z.boolean(),
49236
+ showCollaboration: z.boolean()
49237
+ }),
49238
+ agentTemplates: z.object({
49239
+ enabled: z.boolean(),
49240
+ reminderFrequency: z.number().int().positive()
49241
+ })
49242
+ });
49243
+
49244
+ // src/core/orchestration/instruction-injector.ts
49245
+ init_esm_shims();
49246
+ init_logger();
49247
+
49248
+ // src/core/orchestration/token-budget.ts
49249
+ init_esm_shims();
49250
+ init_logger();
49251
+ var TokenBudgetManager = class _TokenBudgetManager {
49252
+ config;
49253
+ /** Characters per token estimate (conservative) */
49254
+ static CHARS_PER_TOKEN = 4;
49255
+ constructor(config) {
49256
+ this.config = {
49257
+ ...DEFAULT_TOKEN_BUDGET,
49258
+ ...config,
49259
+ perType: {
49260
+ ...DEFAULT_TOKEN_BUDGET.perType,
49261
+ ...config?.perType
49262
+ }
49263
+ };
49264
+ logger.debug("TokenBudgetManager initialized", {
49265
+ maxTotal: this.config.maxTotal,
49266
+ criticalReserve: this.config.criticalReserve
49267
+ });
49268
+ }
49269
+ /**
49270
+ * Estimate tokens for a string
49271
+ */
49272
+ estimateTokens(content) {
49273
+ const characters = content.length;
49274
+ const tokens = Math.ceil(characters / _TokenBudgetManager.CHARS_PER_TOKEN);
49275
+ return {
49276
+ tokens,
49277
+ characters,
49278
+ isEstimate: true
49279
+ };
49280
+ }
49281
+ /**
49282
+ * Estimate tokens for an instruction (including formatting overhead)
49283
+ */
49284
+ estimateInstructionTokens(instruction) {
49285
+ const overhead = 50;
49286
+ const contentTokens = this.estimateTokens(instruction.content).tokens;
49287
+ return contentTokens + overhead;
49288
+ }
49289
+ /**
49290
+ * Allocate budget for instructions
49291
+ *
49292
+ * Priority order:
49293
+ * 1. Critical instructions (always included, use reserve)
49294
+ * 2. High priority (included if budget allows)
49295
+ * 3. Normal priority (included if budget allows)
49296
+ * 4. Low priority (only if significant budget remains)
49297
+ */
49298
+ allocateBudget(instructions) {
49299
+ const included = [];
49300
+ const excluded = [];
49301
+ const perTypeUsage = {
49302
+ task: 0,
49303
+ memory: 0,
49304
+ session: 0,
49305
+ delegation: 0,
49306
+ mode: 0
49307
+ };
49308
+ let tokensUsed = 0;
49309
+ const availableBudget = this.config.maxTotal;
49310
+ const priorityOrder = {
49311
+ critical: 0,
49312
+ high: 1,
49313
+ normal: 2,
49314
+ low: 3
49315
+ };
49316
+ const sorted = [...instructions].sort((a, b) => {
49317
+ const aPriority = priorityOrder[a.priority] ?? 2;
49318
+ const bPriority = priorityOrder[b.priority] ?? 2;
49319
+ const priorityDiff = aPriority - bPriority;
49320
+ if (priorityDiff !== 0) return priorityDiff;
49321
+ return a.createdAt - b.createdAt;
49322
+ });
49323
+ for (const instruction of sorted) {
49324
+ const instructionTokens = this.estimateInstructionTokens(instruction);
49325
+ const typeLimit = this.config.perType[instruction.type] || 0;
49326
+ const currentTypeUsage = perTypeUsage[instruction.type] || 0;
49327
+ const wouldExceedTotal = tokensUsed + instructionTokens > availableBudget;
49328
+ const wouldExceedTypeLimit = currentTypeUsage + instructionTokens > typeLimit;
49329
+ if (instruction.priority === "critical") {
49330
+ const criticalBudget = availableBudget + this.config.criticalReserve;
49331
+ if (tokensUsed + instructionTokens <= criticalBudget) {
49332
+ included.push(instruction);
49333
+ tokensUsed += instructionTokens;
49334
+ perTypeUsage[instruction.type] = currentTypeUsage + instructionTokens;
49335
+ continue;
49336
+ }
49337
+ }
49338
+ if (!wouldExceedTotal && !wouldExceedTypeLimit) {
49339
+ included.push(instruction);
49340
+ tokensUsed += instructionTokens;
49341
+ perTypeUsage[instruction.type] = currentTypeUsage + instructionTokens;
49342
+ } else {
49343
+ excluded.push(instruction);
49344
+ logger.debug("Instruction excluded from budget", {
49345
+ type: instruction.type,
49346
+ priority: instruction.priority,
49347
+ tokens: instructionTokens,
49348
+ reason: wouldExceedTotal ? "total_limit" : "type_limit"
49349
+ });
49350
+ }
49351
+ }
49352
+ const result = {
49353
+ included,
49354
+ excluded,
49355
+ tokensUsed,
49356
+ remaining: availableBudget - tokensUsed,
49357
+ perTypeUsage
49358
+ };
49359
+ logger.debug("Budget allocation complete", {
49360
+ included: included.length,
49361
+ excluded: excluded.length,
49362
+ tokensUsed,
49363
+ remaining: result.remaining
49364
+ });
49365
+ return result;
49366
+ }
49367
+ /**
49368
+ * Check if an instruction fits within budget
49369
+ */
49370
+ fitsInBudget(instruction, currentUsage, typeUsage) {
49371
+ const instructionTokens = this.estimateInstructionTokens(instruction);
49372
+ const typeLimit = this.config.perType[instruction.type] || 0;
49373
+ const currentTypeUsage = typeUsage[instruction.type] || 0;
49374
+ if (instruction.priority === "critical") {
49375
+ return currentUsage + instructionTokens <= this.config.maxTotal + this.config.criticalReserve;
49376
+ }
49377
+ return currentUsage + instructionTokens <= this.config.maxTotal && currentTypeUsage + instructionTokens <= typeLimit;
49378
+ }
49379
+ /**
49380
+ * Get current configuration
49381
+ */
49382
+ getConfig() {
49383
+ return { ...this.config };
49384
+ }
49385
+ /**
49386
+ * Update configuration
49387
+ */
49388
+ updateConfig(updates) {
49389
+ this.config = {
49390
+ ...this.config,
49391
+ ...updates,
49392
+ perType: {
49393
+ ...this.config.perType,
49394
+ ...updates.perType
49395
+ }
49396
+ };
49397
+ logger.debug("TokenBudgetManager config updated", {
49398
+ maxTotal: this.config.maxTotal
49399
+ });
49400
+ }
49401
+ /**
49402
+ * Get remaining budget for a specific type
49403
+ */
49404
+ getRemainingTypeBudget(type, currentTypeUsage) {
49405
+ const limit = this.config.perType[type] || 0;
49406
+ const used = currentTypeUsage[type] || 0;
49407
+ return Math.max(0, limit - used);
49408
+ }
49409
+ /**
49410
+ * Format budget status for debugging
49411
+ */
49412
+ formatBudgetStatus(allocation) {
49413
+ const lines = [
49414
+ `Token Budget Status:`,
49415
+ ` Total: ${allocation.tokensUsed}/${this.config.maxTotal} (${allocation.remaining} remaining)`,
49416
+ ` Per-Type Usage:`
49417
+ ];
49418
+ for (const [type, used] of Object.entries(allocation.perTypeUsage)) {
49419
+ const limit = this.config.perType[type] || 0;
49420
+ lines.push(` ${type}: ${used}/${limit}`);
49421
+ }
49422
+ if (allocation.excluded.length > 0) {
49423
+ lines.push(` Excluded: ${allocation.excluded.length} instruction(s)`);
49424
+ }
49425
+ return lines.join("\n");
49426
+ }
49427
+ };
49428
+
49429
+ // src/core/orchestration/instruction-injector.ts
49430
+ var OrchestrationInstructionInjector = class {
49431
+ providers = /* @__PURE__ */ new Map();
49432
+ budgetManager;
49433
+ config;
49434
+ lastInjectionTime = 0;
49435
+ instructionCache = /* @__PURE__ */ new Map();
49436
+ constructor(config) {
49437
+ this.config = {
49438
+ ...DEFAULT_ORCHESTRATION_CONFIG,
49439
+ ...config
49440
+ };
49441
+ this.budgetManager = new TokenBudgetManager(this.config.tokenBudget);
49442
+ logger.debug("OrchestrationInstructionInjector initialized", {
49443
+ enabled: this.config.enabled,
49444
+ providers: this.providers.size
49445
+ });
49446
+ }
49447
+ /**
49448
+ * Register an instruction provider
49449
+ */
49450
+ registerProvider(provider) {
49451
+ if (this.providers.has(provider.name)) {
49452
+ logger.warn("Provider already registered, replacing", {
49453
+ name: provider.name
49454
+ });
49455
+ }
49456
+ this.providers.set(provider.name, provider);
49457
+ logger.debug("Instruction provider registered", {
49458
+ name: provider.name,
49459
+ totalProviders: this.providers.size
49460
+ });
49461
+ }
49462
+ /**
49463
+ * Unregister an instruction provider
49464
+ */
49465
+ unregisterProvider(name) {
49466
+ const removed = this.providers.delete(name);
49467
+ if (removed) {
49468
+ logger.debug("Instruction provider unregistered", { name });
49469
+ }
49470
+ return removed;
49471
+ }
49472
+ /**
49473
+ * Get all registered providers
49474
+ */
49475
+ getProviders() {
49476
+ return Array.from(this.providers.values());
49477
+ }
49478
+ /**
49479
+ * Generate and inject instructions based on context
49480
+ */
49481
+ async inject(context, options = {}) {
49482
+ if (!this.config.enabled) {
49483
+ return this.emptyResult();
49484
+ }
49485
+ const startTime = Date.now();
49486
+ const allInstructions = [];
49487
+ for (const provider of this.providers.values()) {
49488
+ try {
49489
+ if (!provider.shouldGenerate(context)) {
49490
+ continue;
49491
+ }
49492
+ const instructions = await provider.getInstructions(context);
49493
+ let filtered = instructions;
49494
+ if (options.includeTypes) {
49495
+ filtered = filtered.filter((i) => options.includeTypes.includes(i.type));
49496
+ }
49497
+ if (options.excludeTypes) {
49498
+ filtered = filtered.filter((i) => !options.excludeTypes.includes(i.type));
49499
+ }
49500
+ allInstructions.push(...filtered);
49501
+ } catch (error) {
49502
+ logger.error("Provider failed to generate instructions", {
49503
+ provider: provider.name,
49504
+ error: error instanceof Error ? error.message : String(error)
49505
+ });
49506
+ }
49507
+ }
49508
+ const activeInstructions = this.filterExpiredInstructions(
49509
+ allInstructions,
49510
+ context.turnCount
49511
+ );
49512
+ let allocation;
49513
+ if (options.skipBudget) {
49514
+ allocation = {
49515
+ included: activeInstructions,
49516
+ excluded: [],
49517
+ tokensUsed: activeInstructions.reduce(
49518
+ (sum, i) => sum + this.budgetManager.estimateInstructionTokens(i),
49519
+ 0
49520
+ ),
49521
+ remaining: 0,
49522
+ perTypeUsage: this.calculateTypeUsage(activeInstructions)
49523
+ };
49524
+ } else {
49525
+ allocation = this.budgetManager.allocateBudget(activeInstructions);
49526
+ }
49527
+ const formattedText = this.formatInstructions(allocation.included);
49528
+ this.lastInjectionTime = Date.now();
49529
+ const duration = Date.now() - startTime;
49530
+ logger.debug("Instruction injection complete", {
49531
+ providers: this.providers.size,
49532
+ instructionsGenerated: allInstructions.length,
49533
+ instructionsIncluded: allocation.included.length,
49534
+ tokensUsed: allocation.tokensUsed,
49535
+ durationMs: duration
49536
+ });
49537
+ return {
49538
+ formattedText,
49539
+ instructions: allocation.included,
49540
+ allocation,
49541
+ hasInstructions: allocation.included.length > 0
49542
+ };
49543
+ }
49544
+ /**
49545
+ * Format instructions as system reminder tags
49546
+ */
49547
+ formatInstructions(instructions) {
49548
+ if (instructions.length === 0) {
49549
+ return "";
49550
+ }
49551
+ const grouped = /* @__PURE__ */ new Map();
49552
+ for (const instruction of instructions) {
49553
+ const existing = grouped.get(instruction.type) || [];
49554
+ existing.push(instruction);
49555
+ grouped.set(instruction.type, existing);
49556
+ }
49557
+ const parts = [];
49558
+ const typeOrder = ["mode", "task", "memory", "session", "delegation"];
49559
+ for (const type of typeOrder) {
49560
+ const typeInstructions = grouped.get(type);
49561
+ if (!typeInstructions || typeInstructions.length === 0) continue;
49562
+ for (const instruction of typeInstructions) {
49563
+ parts.push(this.formatSingleInstruction(instruction));
49564
+ }
49565
+ }
49566
+ return parts.join("\n");
49567
+ }
49568
+ /**
49569
+ * Format a single instruction as a system reminder
49570
+ */
49571
+ formatSingleInstruction(instruction) {
49572
+ return `<system-reminder>
49573
+ ${instruction.content}
49574
+ </system-reminder>`;
49575
+ }
49576
+ /**
49577
+ * Filter out expired instructions
49578
+ */
49579
+ filterExpiredInstructions(instructions, currentTurn) {
49580
+ return instructions.filter((instruction) => {
49581
+ if (instruction.expiresAfter === void 0) {
49582
+ return true;
49583
+ }
49584
+ const turnsSinceCreation = currentTurn;
49585
+ return turnsSinceCreation < instruction.expiresAfter;
49586
+ });
49587
+ }
49588
+ /**
49589
+ * Calculate per-type token usage
49590
+ */
49591
+ calculateTypeUsage(instructions) {
49592
+ const usage = {
49593
+ task: 0,
49594
+ memory: 0,
49595
+ session: 0,
49596
+ delegation: 0,
49597
+ mode: 0
49598
+ };
49599
+ for (const instruction of instructions) {
49600
+ const tokens = this.budgetManager.estimateInstructionTokens(instruction);
49601
+ usage[instruction.type] = (usage[instruction.type] || 0) + tokens;
49602
+ }
49603
+ return usage;
49604
+ }
49605
+ /**
49606
+ * Create an empty result
49607
+ */
49608
+ emptyResult() {
49609
+ return {
49610
+ formattedText: "",
49611
+ instructions: [],
49612
+ allocation: {
49613
+ included: [],
49614
+ excluded: [],
49615
+ tokensUsed: 0,
49616
+ remaining: this.budgetManager.getConfig().maxTotal,
49617
+ perTypeUsage: {
49618
+ task: 0,
49619
+ memory: 0,
49620
+ session: 0,
49621
+ delegation: 0,
49622
+ mode: 0
49623
+ }
49624
+ },
49625
+ hasInstructions: false
49626
+ };
49627
+ }
49628
+ /**
49629
+ * Clear instruction cache
49630
+ */
49631
+ clearCache() {
49632
+ this.instructionCache.clear();
49633
+ logger.debug("Instruction cache cleared");
49634
+ }
49635
+ /**
49636
+ * Get current configuration
49637
+ */
49638
+ getConfig() {
49639
+ return { ...this.config };
49640
+ }
49641
+ /**
49642
+ * Update configuration
49643
+ */
49644
+ updateConfig(updates) {
49645
+ this.config = {
49646
+ ...this.config,
49647
+ ...updates
49648
+ };
49649
+ if (updates.tokenBudget) {
49650
+ this.budgetManager.updateConfig(updates.tokenBudget);
49651
+ }
49652
+ logger.debug("OrchestrationInstructionInjector config updated", {
49653
+ enabled: this.config.enabled
49654
+ });
49655
+ }
49656
+ /**
49657
+ * Get budget manager for direct access
49658
+ */
49659
+ getBudgetManager() {
49660
+ return this.budgetManager;
49661
+ }
49662
+ /**
49663
+ * Check if orchestration is enabled
49664
+ */
49665
+ isEnabled() {
49666
+ return this.config.enabled;
49667
+ }
49668
+ /**
49669
+ * Enable or disable orchestration
49670
+ */
49671
+ setEnabled(enabled) {
49672
+ this.config.enabled = enabled;
49673
+ logger.debug("Orchestration enabled state changed", { enabled });
49674
+ }
49675
+ };
49676
+
49677
+ // src/core/orchestration/todo-instruction-provider.ts
49678
+ init_esm_shims();
49679
+ init_logger();
49680
+ var DEFAULT_TODO_CONFIG = {
49681
+ enabled: true,
49682
+ reminderFrequency: 3,
49683
+ compactMode: false,
49684
+ maxCompactItems: 5,
49685
+ showCompleted: false
49686
+ };
49687
+ var TodoInstructionProvider = class {
49688
+ name = "todo";
49689
+ config;
49690
+ lastStateHash = "";
49691
+ lastReminderTurn = 0;
49692
+ constructor(config) {
49693
+ this.config = {
49694
+ ...DEFAULT_TODO_CONFIG,
49695
+ ...config
49696
+ };
49697
+ logger.debug("TodoInstructionProvider initialized", {
49698
+ enabled: this.config.enabled,
49699
+ reminderFrequency: this.config.reminderFrequency
49700
+ });
49701
+ }
49702
+ /**
49703
+ * Check if provider should generate instructions
49704
+ */
49705
+ shouldGenerate(context) {
49706
+ if (!this.config.enabled) {
49707
+ return false;
49708
+ }
49709
+ if (!context.todos || context.todos.length === 0) {
49710
+ return false;
49711
+ }
49712
+ const currentHash = this.computeStateHash(context.todos);
49713
+ const stateChanged = currentHash !== this.lastStateHash;
49714
+ const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
49715
+ const reminderDue = turnsSinceReminder >= this.config.reminderFrequency;
49716
+ return stateChanged || reminderDue;
49717
+ }
49718
+ /**
49719
+ * Generate instructions based on todo state
49720
+ */
49721
+ async getInstructions(context) {
49722
+ const instructions = [];
49723
+ if (!context.todos || context.todos.length === 0) {
49724
+ return instructions;
49725
+ }
49726
+ const currentHash = this.computeStateHash(context.todos);
49727
+ const stateChanged = currentHash !== this.lastStateHash;
49728
+ const activeTodos = context.todos.filter(
49729
+ (todo) => todo.status !== "completed" || this.config.showCompleted
49730
+ );
49731
+ const inProgressTasks = activeTodos.filter((todo) => todo.status === "in_progress");
49732
+ const pendingTasks = activeTodos.filter((todo) => todo.status === "pending");
49733
+ const completedTasks = context.todos.filter((todo) => todo.status === "completed");
49734
+ let content;
49735
+ let priority;
49736
+ if (stateChanged) {
49737
+ content = this.formatFullTodoList(inProgressTasks, pendingTasks, completedTasks);
49738
+ priority = "high";
49739
+ } else if (this.config.compactMode) {
49740
+ content = this.formatCompactReminder(inProgressTasks, pendingTasks);
49741
+ priority = "normal";
49742
+ } else {
49743
+ content = this.formatStandardReminder(inProgressTasks, pendingTasks);
49744
+ priority = "normal";
49745
+ }
49746
+ instructions.push({
49747
+ type: "task",
49748
+ priority,
49749
+ content,
49750
+ source: "automatosx",
49751
+ createdAt: Date.now(),
49752
+ expiresAfter: this.config.reminderFrequency + 1,
49753
+ id: `todo-${currentHash.substring(0, 8)}`
49754
+ });
49755
+ this.lastStateHash = currentHash;
49756
+ this.lastReminderTurn = context.turnCount;
49757
+ logger.debug("Todo instructions generated", {
49758
+ inProgress: inProgressTasks.length,
49759
+ pending: pendingTasks.length,
49760
+ completed: completedTasks.length,
49761
+ stateChanged
49762
+ });
49763
+ return instructions;
49764
+ }
49765
+ /**
49766
+ * Format full todo list (used when state changes)
49767
+ */
49768
+ formatFullTodoList(inProgress, pending, completed) {
49769
+ const lines = [
49770
+ "## Current Task List"
49771
+ ];
49772
+ if (inProgress.length > 0) {
49773
+ lines.push("");
49774
+ lines.push("### Currently Working On:");
49775
+ for (const task of inProgress) {
49776
+ lines.push(`- **${task.activeForm}**`);
49777
+ }
49778
+ }
49779
+ if (pending.length > 0) {
49780
+ lines.push("");
49781
+ lines.push("### Pending Tasks:");
49782
+ for (const task of pending) {
49783
+ lines.push(`- [ ] ${task.content}`);
49784
+ }
49785
+ }
49786
+ if (this.config.showCompleted && completed.length > 0) {
49787
+ lines.push("");
49788
+ lines.push("### Completed:");
49789
+ for (const task of completed.slice(-3)) {
49790
+ lines.push(`- [x] ${task.content}`);
49791
+ }
49792
+ }
49793
+ lines.push("");
49794
+ lines.push("**Remember:** Complete the current in-progress task before starting new ones.");
49795
+ lines.push("Mark tasks as completed as soon as they are done.");
49796
+ return lines.join("\n");
49797
+ }
49798
+ /**
49799
+ * Format standard reminder
49800
+ */
49801
+ formatStandardReminder(inProgress, pending) {
49802
+ const lines = [];
49803
+ if (inProgress.length > 0) {
49804
+ lines.push(`**Current Task:** ${inProgress[0].activeForm}`);
49805
+ }
49806
+ if (pending.length > 0) {
49807
+ lines.push(`**Next:** ${pending[0].content}`);
49808
+ if (pending.length > 1) {
49809
+ lines.push(`(${pending.length - 1} more tasks pending)`);
49810
+ }
49811
+ }
49812
+ return lines.join("\n");
49813
+ }
49814
+ /**
49815
+ * Format compact reminder (minimal tokens)
49816
+ */
49817
+ formatCompactReminder(inProgress, pending) {
49818
+ const parts = [];
49819
+ if (inProgress.length > 0) {
49820
+ parts.push(`Doing: ${inProgress[0].activeForm}`);
49821
+ }
49822
+ if (pending.length > 0) {
49823
+ const count = Math.min(pending.length, this.config.maxCompactItems);
49824
+ parts.push(`Next: ${pending.slice(0, count).map((t) => t.content).join(", ")}`);
49825
+ }
49826
+ return parts.join(" | ");
49827
+ }
49828
+ /**
49829
+ * Compute hash of todo state for change detection
49830
+ */
49831
+ computeStateHash(todos) {
49832
+ const stateString = todos.map((t) => `${t.id}:${t.status}:${t.content}`).sort().join("|");
49833
+ return crypto2.createHash("sha256").update(stateString).digest("hex").substring(0, 16);
49834
+ }
49835
+ /**
49836
+ * Get current configuration
49837
+ */
49838
+ getConfig() {
49839
+ return { ...this.config };
49840
+ }
49841
+ /**
49842
+ * Update configuration
49843
+ */
49844
+ updateConfig(updates) {
49845
+ this.config = {
49846
+ ...this.config,
49847
+ ...updates
49848
+ };
49849
+ logger.debug("TodoInstructionProvider config updated", {
49850
+ enabled: this.config.enabled,
49851
+ compactMode: this.config.compactMode
49852
+ });
49853
+ }
49854
+ /**
49855
+ * Reset state tracking (useful for testing)
49856
+ */
49857
+ reset() {
49858
+ this.lastStateHash = "";
49859
+ this.lastReminderTurn = 0;
49860
+ logger.debug("TodoInstructionProvider state reset");
49861
+ }
49862
+ };
49863
+
49864
+ // src/core/orchestration/memory-instruction-provider.ts
49865
+ init_esm_shims();
49866
+ init_logger();
49867
+ var DEFAULT_MEMORY_CONFIG = {
49868
+ enabled: true,
49869
+ maxEntries: 5,
49870
+ minRelevance: 0.5,
49871
+ searchFrequency: 3,
49872
+ maxAge: 0,
49873
+ // No limit by default
49874
+ includeMetadata: true,
49875
+ cacheTTL: 6e4
49876
+ // 1 minute
49877
+ };
49878
+ var MemoryInstructionProvider = class {
49879
+ name = "memory";
49880
+ config;
49881
+ searchProvider;
49882
+ cache;
49883
+ lastSearchTurn = 0;
49884
+ constructor(searchProvider, config) {
49885
+ this.config = {
49886
+ ...DEFAULT_MEMORY_CONFIG,
49887
+ ...config
49888
+ };
49889
+ this.searchProvider = searchProvider;
49890
+ logger.debug("MemoryInstructionProvider initialized", {
49891
+ enabled: this.config.enabled,
49892
+ maxEntries: this.config.maxEntries,
49893
+ hasSearchProvider: !!searchProvider
49894
+ });
49895
+ }
49896
+ /**
49897
+ * Set the memory search provider
49898
+ */
49899
+ setSearchProvider(provider) {
49900
+ this.searchProvider = provider;
49901
+ this.clearCache();
49902
+ logger.debug("Memory search provider set");
49903
+ }
49904
+ /**
49905
+ * Check if provider should generate instructions
49906
+ */
49907
+ shouldGenerate(context) {
49908
+ if (!this.config.enabled) {
49909
+ return false;
49910
+ }
49911
+ if (!this.searchProvider) {
49912
+ return false;
49913
+ }
49914
+ if (!context.currentTask && context.todos.length === 0) {
49915
+ return false;
49916
+ }
49917
+ const turnsSinceSearch = context.turnCount - this.lastSearchTurn;
49918
+ const searchDue = turnsSinceSearch >= this.config.searchFrequency;
49919
+ const cacheValid = this.cache && Date.now() - this.cache.timestamp < this.config.cacheTTL;
49920
+ return searchDue || !cacheValid;
49921
+ }
49922
+ /**
49923
+ * Generate instructions based on relevant memories
49924
+ */
49925
+ async getInstructions(context) {
49926
+ const instructions = [];
49927
+ if (!this.searchProvider) {
49928
+ return instructions;
49929
+ }
49930
+ const searchQuery = this.buildSearchQuery(context);
49931
+ if (!searchQuery) {
49932
+ return instructions;
49933
+ }
49934
+ try {
49935
+ const memories = await this.searchMemories(searchQuery, context);
49936
+ if (memories.length === 0) {
49937
+ return instructions;
49938
+ }
49939
+ this.lastSearchTurn = context.turnCount;
49940
+ const content = this.formatMemories(memories);
49941
+ instructions.push({
49942
+ type: "memory",
49943
+ priority: "normal",
49944
+ content,
49945
+ source: "automatosx",
49946
+ createdAt: Date.now(),
49947
+ expiresAfter: this.config.searchFrequency + 1,
49948
+ id: `memory-${Date.now()}`
49949
+ });
49950
+ logger.debug("Memory instructions generated", {
49951
+ memoriesFound: memories.length,
49952
+ query: searchQuery.substring(0, 50)
49953
+ });
49954
+ } catch (error) {
49955
+ logger.error("Failed to search memories", {
49956
+ error: error instanceof Error ? error.message : String(error)
49957
+ });
49958
+ }
49959
+ return instructions;
49960
+ }
49961
+ /**
49962
+ * Build search query from context
49963
+ */
49964
+ buildSearchQuery(context) {
49965
+ const parts = [];
49966
+ if (context.currentTask) {
49967
+ parts.push(context.currentTask);
49968
+ }
49969
+ const inProgressTodos = context.todos.filter((t) => t.status === "in_progress");
49970
+ for (const todo of inProgressTodos.slice(0, 2)) {
49971
+ parts.push(todo.content);
49972
+ }
49973
+ if (context.agentName) {
49974
+ parts.push(context.agentName);
49975
+ }
49976
+ if (parts.length === 0) {
49977
+ return null;
49978
+ }
49979
+ return parts.join(" ");
49980
+ }
49981
+ /**
49982
+ * Search for relevant memories
49983
+ */
49984
+ async searchMemories(query, context) {
49985
+ if (!this.searchProvider) {
49986
+ return [];
49987
+ }
49988
+ if (this.cache && this.cache.query === query) {
49989
+ const age = Date.now() - this.cache.timestamp;
49990
+ if (age < this.config.cacheTTL) {
49991
+ logger.debug("Using cached memory results", {
49992
+ cacheAge: age,
49993
+ resultCount: this.cache.results.length
49994
+ });
49995
+ return this.cache.results;
49996
+ }
49997
+ }
49998
+ const results = await this.searchProvider.search({
49999
+ text: query,
50000
+ limit: this.config.maxEntries * 2,
50001
+ // Get extra in case some are filtered
50002
+ filters: context.agentName ? { agentId: context.agentName } : void 0
50003
+ });
50004
+ const filtered = results.filter((r) => r.score >= this.config.minRelevance).filter((r) => this.isWithinMaxAge(r.createdAt)).slice(0, this.config.maxEntries);
50005
+ const memories = filtered.map((r) => ({
50006
+ content: r.content,
50007
+ relevance: r.score,
50008
+ agent: r.metadata?.agentId,
50009
+ timestamp: r.createdAt.getTime()
50010
+ }));
50011
+ this.cache = {
50012
+ query,
50013
+ results: memories,
50014
+ timestamp: Date.now()
50015
+ };
50016
+ return memories;
50017
+ }
50018
+ /**
50019
+ * Check if memory is within max age limit
50020
+ */
50021
+ isWithinMaxAge(createdAt) {
50022
+ if (this.config.maxAge === 0) {
50023
+ return true;
50024
+ }
50025
+ const age = Date.now() - createdAt.getTime();
50026
+ return age <= this.config.maxAge;
50027
+ }
50028
+ /**
50029
+ * Format memories into instruction content
50030
+ */
50031
+ formatMemories(memories) {
50032
+ const lines = [
50033
+ "## Relevant Context from Memory",
50034
+ ""
50035
+ ];
50036
+ for (let i = 0; i < memories.length; i++) {
50037
+ const memory = memories[i];
50038
+ if (!memory) continue;
50039
+ const relevancePercent = Math.round(memory.relevance * 100);
50040
+ if (this.config.includeMetadata && memory.agent) {
50041
+ lines.push(`### Memory ${i + 1} (${relevancePercent}% relevant, from ${memory.agent})`);
50042
+ } else {
50043
+ lines.push(`### Memory ${i + 1} (${relevancePercent}% relevant)`);
50044
+ }
50045
+ const maxLength = 500;
50046
+ const content = memory.content.length > maxLength ? memory.content.substring(0, maxLength) + "..." : memory.content;
50047
+ lines.push(content);
50048
+ lines.push("");
50049
+ }
50050
+ lines.push("**Note:** Use this context to inform your decisions, but verify current state.");
50051
+ return lines.join("\n");
50052
+ }
50053
+ /**
50054
+ * Clear the memory cache
50055
+ */
50056
+ clearCache() {
50057
+ this.cache = void 0;
50058
+ logger.debug("Memory cache cleared");
50059
+ }
50060
+ /**
50061
+ * Get current configuration
50062
+ */
50063
+ getConfig() {
50064
+ return { ...this.config };
50065
+ }
50066
+ /**
50067
+ * Update configuration
50068
+ */
50069
+ updateConfig(updates) {
50070
+ this.config = {
50071
+ ...this.config,
50072
+ ...updates
50073
+ };
50074
+ if (updates.minRelevance !== void 0 || updates.maxEntries !== void 0) {
50075
+ this.clearCache();
50076
+ }
50077
+ logger.debug("MemoryInstructionProvider config updated", {
50078
+ enabled: this.config.enabled,
50079
+ maxEntries: this.config.maxEntries
50080
+ });
50081
+ }
50082
+ /**
50083
+ * Reset state
50084
+ */
50085
+ reset() {
50086
+ this.cache = void 0;
50087
+ this.lastSearchTurn = 0;
50088
+ logger.debug("MemoryInstructionProvider reset");
50089
+ }
50090
+ /**
50091
+ * Check if search provider is configured
50092
+ */
50093
+ hasSearchProvider() {
50094
+ return !!this.searchProvider;
50095
+ }
50096
+ };
50097
+
50098
+ // src/core/orchestration/session-instruction-provider.ts
50099
+ init_esm_shims();
50100
+ init_logger();
50101
+ var DEFAULT_SESSION_CONFIG = {
50102
+ enabled: true,
50103
+ showCollaboration: true,
50104
+ showProgress: true,
50105
+ reminderFrequency: 5,
50106
+ showHandoffContext: true
50107
+ };
50108
+ var SessionInstructionProvider = class {
50109
+ name = "session";
50110
+ config;
50111
+ stateProvider;
50112
+ lastReminderTurn = 0;
50113
+ cachedState;
50114
+ cacheExpiry = 0;
50115
+ CACHE_TTL = 3e4;
50116
+ // 30 seconds
50117
+ constructor(stateProvider, config) {
50118
+ this.config = {
50119
+ ...DEFAULT_SESSION_CONFIG,
50120
+ ...config
50121
+ };
50122
+ this.stateProvider = stateProvider;
50123
+ logger.debug("SessionInstructionProvider initialized", {
50124
+ enabled: this.config.enabled,
50125
+ hasStateProvider: !!stateProvider
50126
+ });
50127
+ }
50128
+ /**
50129
+ * Set the session state provider
50130
+ */
50131
+ setStateProvider(provider) {
50132
+ this.stateProvider = provider;
50133
+ this.clearCache();
50134
+ logger.debug("Session state provider set");
50135
+ }
50136
+ /**
50137
+ * Check if provider should generate instructions
50138
+ */
50139
+ shouldGenerate(context) {
50140
+ if (!this.config.enabled) {
50141
+ return false;
50142
+ }
50143
+ if (!context.sessionId && !this.stateProvider) {
50144
+ return false;
50145
+ }
50146
+ const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
50147
+ return turnsSinceReminder >= this.config.reminderFrequency;
50148
+ }
50149
+ /**
50150
+ * Generate instructions based on session state
50151
+ */
50152
+ async getInstructions(context) {
50153
+ const instructions = [];
50154
+ const state = await this.getSessionState(context);
50155
+ if (!state && !context.sessionId) {
50156
+ return instructions;
50157
+ }
50158
+ const content = this.formatSessionContext(context, state);
50159
+ if (content) {
50160
+ instructions.push({
50161
+ type: "session",
50162
+ priority: "normal",
50163
+ content,
50164
+ source: "automatosx",
50165
+ createdAt: Date.now(),
50166
+ expiresAfter: this.config.reminderFrequency,
50167
+ id: `session-${context.sessionId || "default"}-${Date.now()}`
50168
+ });
50169
+ }
50170
+ this.lastReminderTurn = context.turnCount;
50171
+ logger.debug("Session instructions generated", {
50172
+ sessionId: context.sessionId,
50173
+ hasState: !!state
50174
+ });
50175
+ return instructions;
50176
+ }
50177
+ /**
50178
+ * Get session state from provider or cache
50179
+ */
50180
+ async getSessionState(context) {
50181
+ if (!context.sessionId) {
50182
+ return null;
50183
+ }
50184
+ if (this.cachedState && this.cachedState.id === context.sessionId && Date.now() < this.cacheExpiry) {
50185
+ return this.cachedState;
50186
+ }
50187
+ if (!this.stateProvider) {
50188
+ return null;
50189
+ }
50190
+ try {
50191
+ const state = await this.stateProvider.getSessionState(context.sessionId);
50192
+ if (state) {
50193
+ this.cachedState = state;
50194
+ this.cacheExpiry = Date.now() + this.CACHE_TTL;
50195
+ }
50196
+ return state;
50197
+ } catch (error) {
50198
+ logger.error("Failed to get session state", {
50199
+ sessionId: context.sessionId,
50200
+ error: error instanceof Error ? error.message : String(error)
50201
+ });
50202
+ return null;
50203
+ }
50204
+ }
50205
+ /**
50206
+ * Format session context into instruction content
50207
+ */
50208
+ formatSessionContext(context, state) {
50209
+ const lines = [];
50210
+ if (context.sessionId) {
50211
+ lines.push("## Session Context");
50212
+ lines.push("");
50213
+ }
50214
+ if (this.config.showCollaboration && state && state.participants.length > 1) {
50215
+ lines.push("### Multi-Agent Collaboration");
50216
+ lines.push(`- **Session:** ${state.id.substring(0, 8)}...`);
50217
+ lines.push(`- **Participants:** ${state.participants.join(", ")}`);
50218
+ if (state.activeAgent) {
50219
+ lines.push(`- **Currently Active:** ${state.activeAgent}`);
50220
+ }
50221
+ lines.push("");
50222
+ }
50223
+ if (this.config.showProgress && state) {
50224
+ const totalTasks = state.completedTasks + state.remainingTasks;
50225
+ if (totalTasks > 0) {
50226
+ const progress = Math.round(state.completedTasks / totalTasks * 100);
50227
+ lines.push("### Session Progress");
50228
+ lines.push(`- Completed: ${state.completedTasks}/${totalTasks} (${progress}%)`);
50229
+ if (state.remainingTasks > 0) {
50230
+ lines.push(`- Remaining: ${state.remainingTasks} task(s)`);
50231
+ }
50232
+ lines.push("");
50233
+ }
50234
+ }
50235
+ if (this.config.showHandoffContext && context.parentAgent) {
50236
+ lines.push("### Delegation Context");
50237
+ lines.push(`- **Delegated from:** ${context.parentAgent}`);
50238
+ if (context.currentTask) {
50239
+ lines.push(`- **Task:** ${context.currentTask}`);
50240
+ }
50241
+ lines.push("");
50242
+ lines.push("**Note:** Complete this task and return control to the parent agent.");
50243
+ lines.push("");
50244
+ }
50245
+ if (context.agentName && !context.parentAgent) {
50246
+ lines.push(`**Current Agent:** ${context.agentName}`);
50247
+ lines.push("");
50248
+ }
50249
+ if (lines.length <= 2) {
50250
+ return null;
50251
+ }
50252
+ return lines.join("\n");
50253
+ }
50254
+ /**
50255
+ * Clear cached state
50256
+ */
50257
+ clearCache() {
50258
+ this.cachedState = void 0;
50259
+ this.cacheExpiry = 0;
50260
+ logger.debug("Session cache cleared");
50261
+ }
50262
+ /**
50263
+ * Get current configuration
50264
+ */
50265
+ getConfig() {
50266
+ return { ...this.config };
50267
+ }
50268
+ /**
50269
+ * Update configuration
50270
+ */
50271
+ updateConfig(updates) {
50272
+ this.config = {
50273
+ ...this.config,
50274
+ ...updates
50275
+ };
50276
+ logger.debug("SessionInstructionProvider config updated", {
50277
+ enabled: this.config.enabled
50278
+ });
50279
+ }
50280
+ /**
50281
+ * Reset state
50282
+ */
50283
+ reset() {
50284
+ this.lastReminderTurn = 0;
50285
+ this.clearCache();
50286
+ logger.debug("SessionInstructionProvider reset");
50287
+ }
50288
+ /**
50289
+ * Check if state provider is configured
50290
+ */
50291
+ hasStateProvider() {
50292
+ return !!this.stateProvider;
50293
+ }
50294
+ };
50295
+
50296
+ // src/agents/agent-instruction-injector.ts
50297
+ init_esm_shims();
50298
+ init_logger();
50299
+
50300
+ // src/agents/instruction-templates.ts
50301
+ init_esm_shims();
50302
+ var BACKEND_TEMPLATE = {
50303
+ domain: "backend",
50304
+ displayName: "Backend Engineer",
50305
+ domainReminders: [
50306
+ "Follow RESTful API design principles",
50307
+ "Use proper HTTP status codes",
50308
+ "Implement input validation at API boundaries",
50309
+ "Consider database query performance",
50310
+ "Handle errors gracefully with meaningful messages"
50311
+ ],
50312
+ qualityChecklist: [
50313
+ "API endpoints follow REST conventions",
50314
+ "Database queries are optimized (no N+1)",
50315
+ "Input is validated before processing",
50316
+ "Errors are logged with context",
50317
+ "Sensitive data is not exposed in responses"
50318
+ ],
50319
+ delegationTriggers: [
50320
+ {
50321
+ keywords: ["security", "authentication", "authorization", "OWASP", "vulnerability"],
50322
+ suggestedAgent: "security",
50323
+ reason: "Security-related tasks benefit from specialized security review"
50324
+ },
50325
+ {
50326
+ keywords: ["frontend", "UI", "React", "CSS", "component"],
50327
+ suggestedAgent: "frontend",
50328
+ reason: "Frontend implementation should be handled by frontend specialist"
50329
+ },
50330
+ {
50331
+ keywords: ["test", "testing", "unit test", "integration test"],
50332
+ suggestedAgent: "quality",
50333
+ reason: "Testing strategy benefits from QA expertise"
50334
+ }
50335
+ ],
50336
+ antiPatterns: [
50337
+ "Avoid SQL injection by using parameterized queries",
50338
+ "Don't expose internal error details to clients",
50339
+ "Avoid synchronous blocking operations",
50340
+ "Don't hardcode configuration values"
50341
+ ],
50342
+ bestPractices: [
50343
+ "Use prepared statements for database queries",
50344
+ "Implement proper logging with correlation IDs",
50345
+ "Use dependency injection for testability",
50346
+ "Follow the principle of least privilege"
50347
+ ]
50348
+ };
50349
+ var FRONTEND_TEMPLATE = {
50350
+ domain: "frontend",
50351
+ displayName: "Frontend Engineer",
50352
+ domainReminders: [
50353
+ "Ensure accessibility (WCAG compliance)",
50354
+ "Optimize for performance (Core Web Vitals)",
50355
+ "Handle loading and error states",
50356
+ "Implement responsive design",
50357
+ "Consider keyboard navigation"
50358
+ ],
50359
+ qualityChecklist: [
50360
+ "Components are accessible (ARIA labels, roles)",
50361
+ "Loading states are handled",
50362
+ "Error boundaries catch failures gracefully",
50363
+ "Forms have proper validation feedback",
50364
+ "Images have alt text"
50365
+ ],
50366
+ delegationTriggers: [
50367
+ {
50368
+ keywords: ["API", "endpoint", "database", "backend", "server"],
50369
+ suggestedAgent: "backend",
50370
+ reason: "Backend changes should be handled by backend specialist"
50371
+ },
50372
+ {
50373
+ keywords: ["security", "XSS", "CSRF", "sanitize"],
50374
+ suggestedAgent: "security",
50375
+ reason: "Security concerns require specialized review"
50376
+ }
50377
+ ],
50378
+ antiPatterns: [
50379
+ "Avoid inline styles for reusable components",
50380
+ "Don't mutate state directly",
50381
+ "Avoid excessive re-renders",
50382
+ "Don't ignore accessibility requirements"
50383
+ ],
50384
+ bestPractices: [
50385
+ "Use semantic HTML elements",
50386
+ "Implement proper form validation",
50387
+ "Optimize bundle size",
50388
+ "Use React.memo for expensive components"
50389
+ ]
50390
+ };
50391
+ var SECURITY_TEMPLATE = {
50392
+ domain: "security",
50393
+ displayName: "Security Engineer",
50394
+ domainReminders: [
50395
+ "Apply OWASP Top 10 security guidelines",
50396
+ "Validate and sanitize ALL user input",
50397
+ "Use parameterized queries to prevent SQL injection",
50398
+ "Implement proper authentication and authorization",
50399
+ "Never expose sensitive data in logs or responses"
50400
+ ],
50401
+ qualityChecklist: [
50402
+ "Input validation is present at all entry points",
50403
+ "Authentication tokens are handled securely",
50404
+ "Sensitive data is encrypted at rest and in transit",
50405
+ "Error messages don't leak implementation details",
50406
+ "Dependencies are checked for known vulnerabilities"
50407
+ ],
50408
+ delegationTriggers: [
50409
+ {
50410
+ keywords: ["performance", "optimization", "speed", "latency"],
50411
+ suggestedAgent: "backend",
50412
+ reason: "Performance optimization is a backend concern"
50413
+ }
50414
+ ],
50415
+ antiPatterns: [
50416
+ "Never trust user input without validation",
50417
+ "Don't store passwords in plain text",
50418
+ "Avoid security through obscurity",
50419
+ "Don't disable security features for convenience"
50420
+ ],
50421
+ bestPractices: [
50422
+ "Follow the principle of least privilege",
50423
+ "Implement defense in depth",
50424
+ "Use secure defaults",
50425
+ "Fail securely (deny by default)"
50426
+ ]
50427
+ };
50428
+ var QUALITY_TEMPLATE = {
50429
+ domain: "quality",
50430
+ displayName: "Quality Assurance Engineer",
50431
+ domainReminders: [
50432
+ "Write tests that verify behavior, not implementation",
50433
+ "Cover edge cases and error scenarios",
50434
+ "Ensure test isolation (no shared state)",
50435
+ "Use meaningful test descriptions",
50436
+ "Follow the Arrange-Act-Assert pattern"
50437
+ ],
50438
+ qualityChecklist: [
50439
+ "Unit tests cover critical paths",
50440
+ "Integration tests verify component interactions",
50441
+ "Edge cases are tested",
50442
+ "Error handling is verified",
50443
+ "Tests are maintainable and readable"
50444
+ ],
50445
+ delegationTriggers: [
50446
+ {
50447
+ keywords: ["implement", "build", "create", "develop"],
50448
+ suggestedAgent: "backend",
50449
+ reason: "Implementation tasks should go to domain specialists"
50450
+ },
50451
+ {
50452
+ keywords: ["security", "vulnerability", "penetration"],
50453
+ suggestedAgent: "security",
50454
+ reason: "Security testing requires specialized expertise"
50455
+ }
50456
+ ],
50457
+ antiPatterns: [
50458
+ "Avoid testing implementation details",
50459
+ "Don't use flaky tests",
50460
+ "Avoid excessive mocking",
50461
+ "Don't ignore failing tests"
50462
+ ],
50463
+ bestPractices: [
50464
+ "Test behavior, not implementation",
50465
+ "Use descriptive test names",
50466
+ "Keep tests independent",
50467
+ "Follow the testing pyramid"
50468
+ ]
50469
+ };
50470
+ var ARCHITECTURE_TEMPLATE = {
50471
+ domain: "architecture",
50472
+ displayName: "Software Architect",
50473
+ domainReminders: [
50474
+ "Consider scalability implications",
50475
+ "Document architectural decisions (ADRs)",
50476
+ "Evaluate trade-offs explicitly",
50477
+ "Design for maintainability",
50478
+ "Consider operational concerns"
50479
+ ],
50480
+ qualityChecklist: [
50481
+ "Architecture supports future scaling",
50482
+ "Components have clear boundaries",
50483
+ "Dependencies are managed properly",
50484
+ "System is observable (logging, metrics)",
50485
+ "Failure modes are handled"
50486
+ ],
50487
+ delegationTriggers: [
50488
+ {
50489
+ keywords: ["implement", "code", "fix", "bug"],
50490
+ suggestedAgent: "backend",
50491
+ reason: "Implementation details should be handled by domain specialists"
50492
+ },
50493
+ {
50494
+ keywords: ["security", "compliance", "audit"],
50495
+ suggestedAgent: "security",
50496
+ reason: "Security architecture needs specialized review"
50497
+ }
50498
+ ],
50499
+ antiPatterns: [
50500
+ "Avoid premature optimization",
50501
+ "Don't over-engineer solutions",
50502
+ "Avoid tight coupling between components",
50503
+ "Don't ignore non-functional requirements"
50504
+ ],
50505
+ bestPractices: [
50506
+ "Design for change",
50507
+ "Use well-known patterns",
50508
+ "Document decisions and rationale",
50509
+ "Consider operational requirements"
50510
+ ]
50511
+ };
50512
+ var DEVOPS_TEMPLATE = {
50513
+ domain: "devops",
50514
+ displayName: "DevOps Engineer",
50515
+ domainReminders: [
50516
+ "Automate repetitive tasks",
50517
+ "Implement proper monitoring and alerting",
50518
+ "Follow infrastructure as code principles",
50519
+ "Consider disaster recovery",
50520
+ "Optimize for reliability and cost"
50521
+ ],
50522
+ qualityChecklist: [
50523
+ "Deployments are automated and repeatable",
50524
+ "Monitoring covers key metrics",
50525
+ "Alerts are actionable",
50526
+ "Backups are tested",
50527
+ "Security is integrated into CI/CD"
50528
+ ],
50529
+ delegationTriggers: [
50530
+ {
50531
+ keywords: ["code", "feature", "bug", "implement"],
50532
+ suggestedAgent: "backend",
50533
+ reason: "Application code changes should go to developers"
50534
+ },
50535
+ {
50536
+ keywords: ["security", "credentials", "secrets"],
50537
+ suggestedAgent: "security",
50538
+ reason: "Security-sensitive changes need security review"
50539
+ }
50540
+ ],
50541
+ antiPatterns: [
50542
+ "Avoid manual deployments",
50543
+ "Don't store secrets in code",
50544
+ "Avoid single points of failure",
50545
+ "Don't ignore monitoring gaps"
50546
+ ],
50547
+ bestPractices: [
50548
+ "Use infrastructure as code",
50549
+ "Implement CI/CD pipelines",
50550
+ "Follow GitOps practices",
50551
+ "Use immutable infrastructure"
50552
+ ]
50553
+ };
50554
+ var WRITER_TEMPLATE = {
50555
+ domain: "writer",
50556
+ displayName: "Technical Writer",
50557
+ domainReminders: [
50558
+ "Write for the target audience",
50559
+ "Use clear, concise language",
50560
+ "Include practical examples",
50561
+ "Structure content logically",
50562
+ "Keep documentation up to date"
50563
+ ],
50564
+ qualityChecklist: [
50565
+ "Documentation matches current code",
50566
+ "Examples are working and tested",
50567
+ "Content is well-organized",
50568
+ "Technical terms are explained",
50569
+ "Links and references are valid"
50570
+ ],
50571
+ delegationTriggers: [
50572
+ {
50573
+ keywords: ["implement", "code", "fix", "develop"],
50574
+ suggestedAgent: "backend",
50575
+ reason: "Code changes should be handled by developers"
50576
+ }
50577
+ ],
50578
+ antiPatterns: [
50579
+ "Avoid jargon without explanation",
50580
+ "Don't assume reader knowledge",
50581
+ "Avoid outdated examples",
50582
+ "Don't ignore code comments"
50583
+ ],
50584
+ bestPractices: [
50585
+ "Use consistent terminology",
50586
+ "Include code examples",
50587
+ "Keep documentation near code",
50588
+ "Update docs with code changes"
50589
+ ]
50590
+ };
50591
+ var STANDARD_TEMPLATE = {
50592
+ domain: "standard",
50593
+ displayName: "General Assistant",
50594
+ domainReminders: [
50595
+ "Understand the task before starting",
50596
+ "Ask clarifying questions when needed",
50597
+ "Break complex tasks into smaller steps",
50598
+ "Verify your work before completing",
50599
+ "Document your changes"
50600
+ ],
50601
+ qualityChecklist: [
50602
+ "Task requirements are understood",
50603
+ "Changes are tested",
50604
+ "Code follows project conventions",
50605
+ "Documentation is updated",
50606
+ "No regressions introduced"
50607
+ ],
50608
+ delegationTriggers: [
50609
+ {
50610
+ keywords: ["security", "vulnerability", "authentication"],
50611
+ suggestedAgent: "security",
50612
+ reason: "Security tasks need specialized attention"
50613
+ },
50614
+ {
50615
+ keywords: ["test", "testing", "QA", "quality"],
50616
+ suggestedAgent: "quality",
50617
+ reason: "Testing benefits from QA expertise"
50618
+ },
50619
+ {
50620
+ keywords: ["architecture", "design", "scalability"],
50621
+ suggestedAgent: "architecture",
50622
+ reason: "Architectural decisions need careful consideration"
50623
+ }
50624
+ ],
50625
+ antiPatterns: [
50626
+ "Avoid making changes without understanding context",
50627
+ "Don't skip testing",
50628
+ "Avoid large, monolithic changes",
50629
+ "Don't ignore existing patterns"
50630
+ ],
50631
+ bestPractices: [
50632
+ "Follow existing code conventions",
50633
+ "Write self-documenting code",
50634
+ "Test your changes",
50635
+ "Keep changes focused"
50636
+ ]
50637
+ };
50638
+ var AGENT_TEMPLATES = {
50639
+ backend: BACKEND_TEMPLATE,
50640
+ frontend: FRONTEND_TEMPLATE,
50641
+ fullstack: { ...BACKEND_TEMPLATE, domain: "fullstack", displayName: "Fullstack Engineer" },
50642
+ security: SECURITY_TEMPLATE,
50643
+ quality: QUALITY_TEMPLATE,
50644
+ architecture: ARCHITECTURE_TEMPLATE,
50645
+ devops: DEVOPS_TEMPLATE,
50646
+ data: { ...BACKEND_TEMPLATE, domain: "data", displayName: "Data Engineer" },
50647
+ mobile: { ...FRONTEND_TEMPLATE, domain: "mobile", displayName: "Mobile Engineer" },
50648
+ writer: WRITER_TEMPLATE,
50649
+ researcher: { ...STANDARD_TEMPLATE, domain: "researcher", displayName: "Researcher" },
50650
+ standard: STANDARD_TEMPLATE
50651
+ };
50652
+ function getAgentTemplate(domain) {
50653
+ return AGENT_TEMPLATES[domain] || STANDARD_TEMPLATE;
50654
+ }
50655
+ function isValidAgentDomain(domain) {
50656
+ return domain in AGENT_TEMPLATES;
50657
+ }
50658
+ function getDelegationSuggestions(text, currentDomain) {
50659
+ const template = getAgentTemplate(currentDomain);
50660
+ const suggestions = [];
50661
+ const textLower = text.toLowerCase();
50662
+ for (const trigger of template.delegationTriggers) {
50663
+ const matchedKeywords = trigger.keywords.filter(
50664
+ (kw) => textLower.includes(kw.toLowerCase())
50665
+ );
50666
+ if (matchedKeywords.length > 0) {
50667
+ suggestions.push({
50668
+ agent: trigger.suggestedAgent,
50669
+ reason: trigger.reason,
50670
+ keywords: matchedKeywords
50671
+ });
50672
+ }
50673
+ }
50674
+ return suggestions;
50675
+ }
50676
+
50677
+ // src/agents/agent-instruction-injector.ts
50678
+ var DEFAULT_AGENT_CONFIG = {
50679
+ enabled: true,
50680
+ reminderFrequency: 5,
50681
+ delegationDetection: true,
50682
+ minDelegationKeywords: 1,
50683
+ includeQualityChecklist: true,
50684
+ qualityChecklistFrequency: 10,
50685
+ includeAntiPatterns: true
50686
+ };
50687
+ var AgentInstructionInjector = class {
50688
+ name = "agent-template";
50689
+ config;
50690
+ lastReminderTurn = 0;
50691
+ lastQualityCheckTurn = 0;
50692
+ currentDomain;
50693
+ recentTaskText = "";
50694
+ constructor(config) {
50695
+ this.config = {
50696
+ ...DEFAULT_AGENT_CONFIG,
50697
+ ...config
50698
+ };
50699
+ logger.debug("AgentInstructionInjector initialized", {
50700
+ enabled: this.config.enabled,
50701
+ reminderFrequency: this.config.reminderFrequency
50702
+ });
50703
+ }
50704
+ /**
50705
+ * Set the current agent domain
50706
+ */
50707
+ setDomain(domain) {
50708
+ if (isValidAgentDomain(domain)) {
50709
+ this.currentDomain = domain;
50710
+ logger.debug("Agent domain set", { domain });
50711
+ } else {
50712
+ this.currentDomain = "standard";
50713
+ logger.debug("Unknown domain, using standard", { domain });
50714
+ }
50715
+ }
50716
+ /**
50717
+ * Get the current domain
50718
+ */
50719
+ getDomain() {
50720
+ return this.currentDomain;
50721
+ }
50722
+ /**
50723
+ * Check if provider should generate instructions
50724
+ */
50725
+ shouldGenerate(context) {
50726
+ if (!this.config.enabled) {
50727
+ return false;
50728
+ }
50729
+ const domain = this.resolveDomain(context);
50730
+ if (!domain) {
50731
+ return false;
50732
+ }
50733
+ const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
50734
+ const reminderDue = turnsSinceReminder >= this.config.reminderFrequency;
50735
+ const turnsSinceQuality = context.turnCount - this.lastQualityCheckTurn;
50736
+ const qualityDue = this.config.includeQualityChecklist && turnsSinceQuality >= this.config.qualityChecklistFrequency;
50737
+ const hasDelegationTriggers = this.config.delegationDetection && this.checkDelegationTriggers(context);
50738
+ return reminderDue || qualityDue || hasDelegationTriggers;
50739
+ }
50740
+ /**
50741
+ * Generate instructions based on agent domain
50742
+ */
50743
+ async getInstructions(context) {
50744
+ const instructions = [];
50745
+ const domain = this.resolveDomain(context);
50746
+ if (!domain) {
50747
+ return instructions;
50748
+ }
50749
+ const template = getAgentTemplate(domain);
50750
+ const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
50751
+ const turnsSinceQuality = context.turnCount - this.lastQualityCheckTurn;
50752
+ if (turnsSinceReminder >= this.config.reminderFrequency) {
50753
+ const reminderContent = this.formatDomainReminders(template);
50754
+ instructions.push({
50755
+ type: "delegation",
50756
+ priority: "normal",
50757
+ content: reminderContent,
50758
+ source: "automatosx",
50759
+ createdAt: Date.now(),
50760
+ expiresAfter: this.config.reminderFrequency,
50761
+ id: `agent-reminder-${domain}-${Date.now()}`
50762
+ });
50763
+ this.lastReminderTurn = context.turnCount;
50764
+ }
50765
+ if (this.config.includeQualityChecklist && turnsSinceQuality >= this.config.qualityChecklistFrequency) {
50766
+ const checklistContent = this.formatQualityChecklist(template);
50767
+ instructions.push({
50768
+ type: "delegation",
50769
+ priority: "normal",
50770
+ content: checklistContent,
50771
+ source: "automatosx",
50772
+ createdAt: Date.now(),
50773
+ expiresAfter: this.config.qualityChecklistFrequency,
50774
+ id: `agent-quality-${domain}-${Date.now()}`
50775
+ });
50776
+ this.lastQualityCheckTurn = context.turnCount;
50777
+ }
50778
+ if (this.config.delegationDetection) {
50779
+ const taskText = this.extractTaskText(context);
50780
+ if (taskText !== this.recentTaskText) {
50781
+ this.recentTaskText = taskText;
50782
+ const delegationContent = this.checkAndFormatDelegation(template, taskText);
50783
+ if (delegationContent) {
50784
+ instructions.push({
50785
+ type: "delegation",
50786
+ priority: "high",
50787
+ content: delegationContent,
50788
+ source: "automatosx",
50789
+ createdAt: Date.now(),
50790
+ expiresAfter: 3,
50791
+ id: `agent-delegation-${Date.now()}`
50792
+ });
50793
+ }
50794
+ }
50795
+ }
50796
+ logger.debug("Agent instructions generated", {
50797
+ domain,
50798
+ instructionCount: instructions.length
50799
+ });
50800
+ return instructions;
50801
+ }
50802
+ /**
50803
+ * Resolve domain from context or current setting
50804
+ */
50805
+ resolveDomain(context) {
50806
+ if (context.agentName && isValidAgentDomain(context.agentName)) {
50807
+ return context.agentName;
50808
+ }
50809
+ return this.currentDomain;
50810
+ }
50811
+ /**
50812
+ * Extract task text from context for delegation detection
50813
+ */
50814
+ extractTaskText(context) {
50815
+ const parts = [];
50816
+ if (context.currentTask) {
50817
+ parts.push(context.currentTask);
50818
+ }
50819
+ for (const todo of context.todos.filter((t) => t.status === "in_progress")) {
50820
+ parts.push(todo.content);
50821
+ }
50822
+ return parts.join(" ");
50823
+ }
50824
+ /**
50825
+ * Check if delegation triggers are present
50826
+ */
50827
+ checkDelegationTriggers(context) {
50828
+ const domain = this.resolveDomain(context);
50829
+ if (!domain) return false;
50830
+ const taskText = this.extractTaskText(context);
50831
+ if (!taskText) return false;
50832
+ const suggestions = getDelegationSuggestions(taskText, domain);
50833
+ return suggestions.some((s) => s.keywords.length >= this.config.minDelegationKeywords);
50834
+ }
50835
+ /**
50836
+ * Format domain reminders
50837
+ */
50838
+ formatDomainReminders(template) {
50839
+ const lines = [
50840
+ `## ${template.displayName} Reminders`,
50841
+ ""
50842
+ ];
50843
+ for (const reminder of template.domainReminders) {
50844
+ lines.push(`- ${reminder}`);
50845
+ }
50846
+ if (this.config.includeAntiPatterns && template.antiPatterns.length > 0) {
50847
+ lines.push("");
50848
+ lines.push("**Avoid:**");
50849
+ for (const antiPattern of template.antiPatterns.slice(0, 3)) {
50850
+ lines.push(`- ${antiPattern}`);
50851
+ }
50852
+ }
50853
+ return lines.join("\n");
50854
+ }
50855
+ /**
50856
+ * Format quality checklist
50857
+ */
50858
+ formatQualityChecklist(template) {
50859
+ const lines = [
50860
+ `## Quality Checklist (${template.displayName})`,
50861
+ "",
50862
+ "Before completing, verify:"
50863
+ ];
50864
+ for (const item of template.qualityChecklist) {
50865
+ lines.push(`- [ ] ${item}`);
50866
+ }
50867
+ return lines.join("\n");
50868
+ }
50869
+ /**
50870
+ * Check for delegation triggers and format suggestion
50871
+ */
50872
+ checkAndFormatDelegation(template, taskText) {
50873
+ const suggestions = getDelegationSuggestions(taskText, template.domain);
50874
+ const relevantSuggestions = suggestions.filter(
50875
+ (s) => s.keywords.length >= this.config.minDelegationKeywords
50876
+ );
50877
+ if (relevantSuggestions.length === 0) {
50878
+ return null;
50879
+ }
50880
+ const lines = [
50881
+ "## Delegation Suggestion",
50882
+ ""
50883
+ ];
50884
+ for (const suggestion of relevantSuggestions) {
50885
+ lines.push(`**Consider delegating to @${suggestion.agent}**`);
50886
+ lines.push(`- Reason: ${suggestion.reason}`);
50887
+ lines.push(`- Triggered by: ${suggestion.keywords.join(", ")}`);
50888
+ lines.push("");
50889
+ }
50890
+ lines.push("Use `DELEGATE TO @agent: task` or `@agent task` syntax to delegate.");
50891
+ return lines.join("\n");
50892
+ }
50893
+ /**
50894
+ * Get current configuration
50895
+ */
50896
+ getConfig() {
50897
+ return { ...this.config };
50898
+ }
50899
+ /**
50900
+ * Update configuration
50901
+ */
50902
+ updateConfig(updates) {
50903
+ this.config = {
50904
+ ...this.config,
50905
+ ...updates
50906
+ };
50907
+ logger.debug("AgentInstructionInjector config updated", {
50908
+ enabled: this.config.enabled
50909
+ });
50910
+ }
50911
+ /**
50912
+ * Reset state
50913
+ */
50914
+ reset() {
50915
+ this.lastReminderTurn = 0;
50916
+ this.lastQualityCheckTurn = 0;
50917
+ this.recentTaskText = "";
50918
+ logger.debug("AgentInstructionInjector reset");
50919
+ }
50920
+ };
50921
+
50922
+ // src/core/orchestration/orchestration-service.ts
50923
+ var OrchestrationService = class {
50924
+ config;
50925
+ injector;
50926
+ tokenBudgetManager;
50927
+ workflowModeManager;
50928
+ agentInjector;
50929
+ todoProvider;
50930
+ memoryProvider;
50931
+ sessionProvider;
50932
+ turnCount = 0;
50933
+ currentTodos = [];
50934
+ constructor(serviceConfig = {}) {
50935
+ this.config = {
50936
+ ...DEFAULT_ORCHESTRATION_CONFIG,
50937
+ ...serviceConfig
50938
+ };
50939
+ this.injector = new OrchestrationInstructionInjector(this.config);
50940
+ this.tokenBudgetManager = new TokenBudgetManager(this.config.tokenBudget);
50941
+ this.workflowModeManager = new WorkflowModeManager();
50942
+ this.agentInjector = new AgentInstructionInjector({
50943
+ enabled: this.config.agentTemplates?.enabled ?? true,
50944
+ reminderFrequency: this.config.agentTemplates?.reminderFrequency ?? 5
50945
+ });
50946
+ this.initializeProviders(serviceConfig);
50947
+ logger.debug("OrchestrationService initialized", {
50948
+ todoEnabled: this.config.todoIntegration?.enabled,
50949
+ memoryEnabled: this.config.memoryIntegration?.enabled,
50950
+ sessionEnabled: this.config.sessionIntegration?.enabled,
50951
+ agentTemplatesEnabled: this.config.agentTemplates?.enabled
50952
+ });
50953
+ }
50954
+ /**
50955
+ * Initialize instruction providers
50956
+ */
50957
+ initializeProviders(serviceConfig) {
50958
+ if (this.config.todoIntegration?.enabled !== false) {
50959
+ this.todoProvider = new TodoInstructionProvider({
50960
+ enabled: true,
50961
+ reminderFrequency: this.config.todoIntegration?.reminderFrequency ?? 3,
50962
+ compactMode: this.config.todoIntegration?.compactMode ?? false
50963
+ });
50964
+ this.injector.registerProvider(this.todoProvider);
50965
+ }
50966
+ if (this.config.memoryIntegration?.enabled !== false && serviceConfig.memorySearchProvider) {
50967
+ this.memoryProvider = new MemoryInstructionProvider(
50968
+ serviceConfig.memorySearchProvider,
50969
+ {
50970
+ enabled: true,
50971
+ maxEntries: this.config.memoryIntegration?.maxEntries ?? 5,
50972
+ minRelevance: this.config.memoryIntegration?.minRelevance ?? 0.5
50973
+ }
50974
+ );
50975
+ this.injector.registerProvider(this.memoryProvider);
50976
+ }
50977
+ if (this.config.sessionIntegration?.enabled !== false) {
50978
+ this.sessionProvider = new SessionInstructionProvider(
50979
+ serviceConfig.sessionStateProvider,
50980
+ {
50981
+ enabled: true,
50982
+ showCollaboration: this.config.sessionIntegration?.showCollaboration ?? true,
50983
+ showProgress: true,
50984
+ reminderFrequency: 5,
50985
+ showHandoffContext: true
50986
+ }
50987
+ );
50988
+ this.injector.registerProvider(this.sessionProvider);
50989
+ }
50990
+ if (this.config.agentTemplates?.enabled !== false) {
50991
+ if (serviceConfig.agentDomain) {
50992
+ this.agentInjector.setDomain(serviceConfig.agentDomain);
50993
+ }
50994
+ this.injector.registerProvider(this.agentInjector);
50995
+ }
50996
+ }
50997
+ /**
50998
+ * Set the current agent domain for agent-specific instructions
50999
+ */
51000
+ setAgentDomain(domain) {
51001
+ this.agentInjector.setDomain(domain);
51002
+ logger.debug("Agent domain set", { domain });
51003
+ }
51004
+ /**
51005
+ * Set the memory search provider
51006
+ */
51007
+ setMemoryProvider(provider) {
51008
+ if (this.memoryProvider) {
51009
+ this.memoryProvider.setSearchProvider(provider);
51010
+ } else if (this.config.memoryIntegration?.enabled !== false) {
51011
+ this.memoryProvider = new MemoryInstructionProvider(provider, {
51012
+ enabled: true,
51013
+ maxEntries: this.config.memoryIntegration?.maxEntries ?? 5,
51014
+ minRelevance: this.config.memoryIntegration?.minRelevance ?? 0.5
51015
+ });
51016
+ this.injector.registerProvider(this.memoryProvider);
51017
+ }
51018
+ }
51019
+ /**
51020
+ * Set the session state provider
51021
+ */
51022
+ setSessionProvider(provider) {
51023
+ if (this.sessionProvider) {
51024
+ this.sessionProvider.setStateProvider(provider);
51025
+ }
51026
+ }
51027
+ /**
51028
+ * Update the current todo list
51029
+ */
51030
+ updateTodos(todos) {
51031
+ this.currentTodos = todos;
51032
+ }
51033
+ /**
51034
+ * Set the workflow mode
51035
+ */
51036
+ setWorkflowMode(mode) {
51037
+ this.workflowModeManager.setMode(mode);
51038
+ logger.debug("Workflow mode set", { mode });
51039
+ }
51040
+ /**
51041
+ * Get current workflow mode
51042
+ */
51043
+ getWorkflowMode() {
51044
+ return this.workflowModeManager.getCurrentMode();
51045
+ }
51046
+ /**
51047
+ * Check if a tool is allowed in current workflow mode
51048
+ */
51049
+ isToolAllowed(toolName) {
51050
+ return this.workflowModeManager.isToolAllowed(toolName);
51051
+ }
51052
+ /**
51053
+ * Filter tools based on current workflow mode
51054
+ */
51055
+ filterTools(tools) {
51056
+ return this.workflowModeManager.filterTools(tools);
51057
+ }
51058
+ /**
51059
+ * Increment turn count (called after each agent response)
51060
+ */
51061
+ incrementTurn() {
51062
+ this.turnCount++;
51063
+ }
51064
+ /**
51065
+ * Get current turn count
51066
+ */
51067
+ getTurnCount() {
51068
+ return this.turnCount;
51069
+ }
51070
+ /**
51071
+ * Generate and inject instructions for the current context
51072
+ */
51073
+ async injectInstructions(options = {}) {
51074
+ const context = {
51075
+ todos: this.currentTodos,
51076
+ turnCount: this.turnCount,
51077
+ workflowMode: this.workflowModeManager.getCurrentMode(),
51078
+ currentTask: options.task,
51079
+ agentName: options.agentName,
51080
+ sessionId: options.sessionId,
51081
+ parentAgent: options.parentAgent
51082
+ };
51083
+ const result = await this.injector.inject(context);
51084
+ logger.debug("Instructions injected", {
51085
+ instructionCount: result.instructions.length,
51086
+ tokensUsed: result.allocation.tokensUsed,
51087
+ hasInstructions: result.hasInstructions
51088
+ });
51089
+ return {
51090
+ content: result.formattedText,
51091
+ instructions: result.instructions,
51092
+ tokenCount: result.allocation.tokensUsed,
51093
+ applied: result.hasInstructions
51094
+ };
51095
+ }
51096
+ /**
51097
+ * Format instructions as system reminder tags
51098
+ */
51099
+ formatAsSystemReminder(content) {
51100
+ if (!content || content.trim().length === 0) {
51101
+ return "";
51102
+ }
51103
+ return `<system-reminder>
51104
+ ${content}
51105
+ </system-reminder>`;
51106
+ }
51107
+ /**
51108
+ * Get debug information about current orchestration state
51109
+ */
51110
+ getDebugInfo() {
51111
+ const budgetConfig = this.tokenBudgetManager.getConfig();
51112
+ const providers = this.injector.getProviders().map((p) => p.name);
51113
+ return {
51114
+ turnCount: this.turnCount,
51115
+ workflowMode: this.workflowModeManager.getCurrentMode(),
51116
+ todoCount: this.currentTodos.length,
51117
+ providers,
51118
+ tokenBudget: {
51119
+ used: 0,
51120
+ // Would need to track this
51121
+ total: budgetConfig.maxTotal,
51122
+ remaining: budgetConfig.maxTotal
51123
+ }
51124
+ };
51125
+ }
51126
+ /**
51127
+ * Reset all state (for new conversations)
51128
+ */
51129
+ reset() {
51130
+ this.turnCount = 0;
51131
+ this.currentTodos = [];
51132
+ this.workflowModeManager.reset();
51133
+ this.agentInjector.reset();
51134
+ this.injector.clearCache();
51135
+ if (this.todoProvider) {
51136
+ this.todoProvider.reset();
51137
+ }
51138
+ if (this.memoryProvider) {
51139
+ this.memoryProvider.clearCache();
51140
+ }
51141
+ if (this.sessionProvider) {
51142
+ this.sessionProvider.reset();
51143
+ }
51144
+ logger.debug("OrchestrationService reset");
51145
+ }
51146
+ /**
51147
+ * Update configuration
51148
+ */
51149
+ updateConfig(updates) {
51150
+ this.config = {
51151
+ ...this.config,
51152
+ ...updates
51153
+ };
51154
+ if (updates.tokenBudget) {
51155
+ this.tokenBudgetManager = new TokenBudgetManager(updates.tokenBudget);
51156
+ }
51157
+ logger.debug("OrchestrationService config updated", { updates });
51158
+ }
51159
+ /**
51160
+ * Get current configuration
51161
+ */
51162
+ getConfig() {
51163
+ return { ...this.config };
51164
+ }
51165
+ };
51166
+
51167
+ // src/cli/commands/debug-instructions.ts
51168
+ var debugInstructionsCommand = {
51169
+ command: "debug:instructions",
51170
+ describe: "Show current embedded instructions state (v11.3.0)",
51171
+ builder: (yargs2) => {
51172
+ return yargs2.option("tokens", {
51173
+ alias: "t",
51174
+ describe: "Show token budget details",
51175
+ type: "boolean",
51176
+ default: false
51177
+ }).option("providers", {
51178
+ alias: "p",
51179
+ describe: "Show registered instruction providers",
51180
+ type: "boolean",
51181
+ default: false
51182
+ }).option("templates", {
51183
+ describe: "Show available agent templates",
51184
+ type: "boolean",
51185
+ default: false
51186
+ }).option("agent", {
51187
+ alias: "a",
51188
+ describe: "Show template for specific agent domain",
51189
+ type: "string"
51190
+ }).option("verbose", {
51191
+ alias: "v",
51192
+ describe: "Show verbose output",
51193
+ type: "boolean",
51194
+ default: false
51195
+ }).example("$0 debug:instructions", "Show overall instruction state").example("$0 debug:instructions --tokens", "Show token budget details").example("$0 debug:instructions --providers", "List instruction providers").example("$0 debug:instructions --templates", "List agent templates").example("$0 debug:instructions --agent backend", "Show backend agent template");
51196
+ },
51197
+ handler: async (argv) => {
51198
+ try {
51199
+ if (argv.tokens) {
51200
+ displayTokenBudget(argv.verbose);
51201
+ return;
51202
+ }
51203
+ if (argv.providers) {
51204
+ displayProviders(argv.verbose);
51205
+ return;
51206
+ }
51207
+ if (argv.templates) {
51208
+ displayAgentTemplates(argv.verbose);
51209
+ return;
51210
+ }
51211
+ if (argv.agent) {
51212
+ displayAgentTemplate(argv.agent, argv.verbose);
51213
+ return;
51214
+ }
51215
+ displayOverallState(argv.verbose);
51216
+ } catch (error) {
51217
+ const err = error instanceof Error ? error : new Error(String(error));
51218
+ console.error(chalk5.red.bold(`
51219
+ \u274C Error: ${err.message}
51220
+ `));
51221
+ logger.error("Debug instructions command failed", { error: err.message });
51222
+ process.exit(1);
51223
+ }
51224
+ }
51225
+ };
51226
+ function displayOverallState(verbose) {
51227
+ console.log(chalk5.blue.bold("\n\u{1F50D} Embedded Instructions Debug Info\n"));
51228
+ console.log(chalk5.dim("\u2550".repeat(60)));
51229
+ const service = new OrchestrationService();
51230
+ const debugInfo = service.getDebugInfo();
51231
+ console.log(chalk5.cyan("\n\u{1F4CA} Current State"));
51232
+ console.log(chalk5.dim("\u2500".repeat(40)));
51233
+ console.log(` Turn count: ${chalk5.yellow(debugInfo.turnCount)}`);
51234
+ console.log(` Workflow mode: ${chalk5.cyan(debugInfo.workflowMode)}`);
51235
+ console.log(` Active todos: ${chalk5.yellow(debugInfo.todoCount)}`);
51236
+ console.log(` Registered providers: ${chalk5.green(debugInfo.providers.length)}`);
51237
+ console.log(chalk5.cyan("\n\u{1F4B0} Token Budget"));
51238
+ console.log(chalk5.dim("\u2500".repeat(40)));
51239
+ console.log(` Used: ${chalk5.yellow(debugInfo.tokenBudget.used)} / ${debugInfo.tokenBudget.total}`);
51240
+ const usagePercent = Math.round(debugInfo.tokenBudget.used / debugInfo.tokenBudget.total * 100);
51241
+ const barLength = 30;
51242
+ const filledLength = Math.round(usagePercent / 100 * barLength);
51243
+ const bar = "\u2588".repeat(filledLength) + "\u2591".repeat(barLength - filledLength);
51244
+ const barColor = usagePercent > 80 ? chalk5.red : usagePercent > 50 ? chalk5.yellow : chalk5.green;
51245
+ console.log(` ${barColor(bar)} ${usagePercent}%`);
51246
+ if (debugInfo.providers.length > 0) {
51247
+ console.log(chalk5.cyan("\n\u{1F50C} Active Providers"));
51248
+ console.log(chalk5.dim("\u2500".repeat(40)));
51249
+ debugInfo.providers.forEach((provider, index) => {
51250
+ console.log(` ${index + 1}. ${chalk5.green(provider)}`);
51251
+ });
51252
+ }
51253
+ console.log(chalk5.cyan("\n\u{1F504} Workflow Modes"));
51254
+ console.log(chalk5.dim("\u2500".repeat(40)));
51255
+ Object.keys(WORKFLOW_MODES).forEach((mode) => {
51256
+ const isCurrent = mode === debugInfo.workflowMode;
51257
+ const prefix = isCurrent ? chalk5.green("\u25BA") : " ";
51258
+ const modeText = isCurrent ? chalk5.green.bold(mode) : chalk5.gray(mode);
51259
+ console.log(` ${prefix} ${modeText}`);
51260
+ });
51261
+ console.log(chalk5.dim("\n" + "\u2550".repeat(60)));
51262
+ console.log(chalk5.gray("\nUse --tokens, --providers, or --templates for detailed info.\n"));
51263
+ }
51264
+ function displayTokenBudget(verbose) {
51265
+ console.log(chalk5.blue.bold("\n\u{1F4B0} Token Budget Details\n"));
51266
+ console.log(chalk5.dim("\u2500".repeat(50)));
51267
+ const budgetManager = new TokenBudgetManager();
51268
+ const config = budgetManager.getConfig();
51269
+ console.log(`
51270
+ Total budget: ${chalk5.cyan(config.maxTotal)} tokens`);
51271
+ console.log(` Critical reserve: ${chalk5.yellow(config.criticalReserve)} tokens`);
51272
+ console.log(` Available: ${chalk5.green(config.maxTotal - config.criticalReserve)} tokens`);
51273
+ console.log(chalk5.cyan("\n Per-Type Allocations:"));
51274
+ const typeAllocations = [
51275
+ { type: "task", budget: 500, description: "Todo/task reminders" },
51276
+ { type: "memory", budget: 400, description: "Memory context" },
51277
+ { type: "session", budget: 300, description: "Session state" },
51278
+ { type: "delegation", budget: 300, description: "Agent delegation hints" },
51279
+ { type: "mode", budget: 200, description: "Workflow mode instructions" }
51280
+ ];
51281
+ typeAllocations.forEach(({ type, budget, description }) => {
51282
+ console.log(` \u2022 ${chalk5.cyan(type)}: ${budget} tokens`);
51283
+ if (verbose) {
51284
+ console.log(chalk5.gray(` ${description}`));
51285
+ }
51286
+ });
51287
+ console.log(chalk5.cyan("\n Token Estimation:"));
51288
+ console.log(chalk5.gray(" ~4 characters = 1 token (approximation)"));
51289
+ console.log(chalk5.gray(" Actual usage may vary by content"));
51290
+ console.log(chalk5.dim("\n\u2500".repeat(50)));
51291
+ console.log();
51292
+ }
51293
+ function displayProviders(verbose) {
51294
+ console.log(chalk5.blue.bold("\n\u{1F50C} Instruction Providers\n"));
51295
+ console.log(chalk5.dim("\u2500".repeat(50)));
51296
+ const providers = [
51297
+ {
51298
+ name: "TodoInstructionProvider",
51299
+ description: "Generates task reminders from todo list",
51300
+ triggers: "Todo state changes, periodic reminders",
51301
+ priority: "high"
51302
+ },
51303
+ {
51304
+ name: "MemoryInstructionProvider",
51305
+ description: "Injects relevant context from memory",
51306
+ triggers: "Task keywords, memory relevance",
51307
+ priority: "normal"
51308
+ },
51309
+ {
51310
+ name: "SessionInstructionProvider",
51311
+ description: "Shows multi-agent collaboration state",
51312
+ triggers: "Session changes, periodic reminders",
51313
+ priority: "normal"
51314
+ },
51315
+ {
51316
+ name: "AgentInstructionInjector",
51317
+ description: "Domain-specific reminders and delegation hints",
51318
+ triggers: "Agent domain, task keywords",
51319
+ priority: "normal"
51320
+ },
51321
+ {
51322
+ name: "WorkflowModeManager",
51323
+ description: "Mode-specific instructions and tool filtering",
51324
+ triggers: "Mode changes",
51325
+ priority: "high"
51326
+ }
51327
+ ];
51328
+ providers.forEach((provider, index) => {
51329
+ console.log(`
51330
+ ${index + 1}. ${chalk5.cyan.bold(provider.name)}`);
51331
+ console.log(chalk5.gray(` ${provider.description}`));
51332
+ if (verbose) {
51333
+ console.log(` Triggers: ${chalk5.yellow(provider.triggers)}`);
51334
+ console.log(` Priority: ${chalk5.green(provider.priority)}`);
51335
+ }
51336
+ });
51337
+ console.log(chalk5.dim("\n\u2500".repeat(50)));
51338
+ console.log();
51339
+ }
51340
+ function displayAgentTemplates(verbose) {
51341
+ console.log(chalk5.blue.bold("\n\u{1F4CB} Agent Instruction Templates\n"));
51342
+ console.log(chalk5.dim("\u2500".repeat(50)));
51343
+ for (const [domain, template] of Object.entries(AGENT_TEMPLATES)) {
51344
+ console.log(`
51345
+ ${chalk5.cyan.bold(template.displayName)} (${domain})`);
51346
+ if (verbose) {
51347
+ console.log(chalk5.gray(` Reminders: ${template.domainReminders.length}`));
51348
+ console.log(chalk5.gray(` Checklist items: ${template.qualityChecklist.length}`));
51349
+ console.log(chalk5.gray(` Delegation triggers: ${template.delegationTriggers.length}`));
51350
+ console.log(chalk5.gray(` Anti-patterns: ${template.antiPatterns.length}`));
51351
+ console.log(chalk5.gray(` Best practices: ${template.bestPractices.length}`));
51352
+ }
51353
+ }
51354
+ console.log(chalk5.dim("\n\u2500".repeat(50)));
51355
+ console.log(chalk5.gray("\nUse --agent <domain> to see template details.\n"));
51356
+ }
51357
+ function displayAgentTemplate(domain, verbose) {
51358
+ const template = AGENT_TEMPLATES[domain];
51359
+ if (!template) {
51360
+ console.error(chalk5.red.bold(`
51361
+ \u274C Unknown agent domain: ${domain}
51362
+ `));
51363
+ console.log(chalk5.gray("Available domains:"));
51364
+ Object.keys(AGENT_TEMPLATES).forEach((d) => {
51365
+ console.log(chalk5.cyan(` \u2022 ${d}`));
51366
+ });
51367
+ console.log();
51368
+ process.exit(1);
51369
+ }
51370
+ console.log(chalk5.blue.bold(`
51371
+ \u{1F4CB} ${template.displayName} Agent Template
51372
+ `));
51373
+ console.log(chalk5.dim("\u2550".repeat(60)));
51374
+ console.log(chalk5.cyan("\n\u{1F514} Domain Reminders:"));
51375
+ template.domainReminders.forEach((reminder, i) => {
51376
+ console.log(` ${i + 1}. ${reminder}`);
51377
+ });
51378
+ console.log(chalk5.cyan("\n\u2705 Quality Checklist:"));
51379
+ template.qualityChecklist.forEach((item, i) => {
51380
+ console.log(` ${i + 1}. ${item}`);
51381
+ });
51382
+ if (template.delegationTriggers.length > 0) {
51383
+ console.log(chalk5.cyan("\n\u{1F500} Delegation Triggers:"));
51384
+ template.delegationTriggers.forEach((trigger, i) => {
51385
+ console.log(` ${i + 1}. \u2192 ${chalk5.yellow(trigger.suggestedAgent)}`);
51386
+ console.log(chalk5.gray(` Keywords: ${trigger.keywords.join(", ")}`));
51387
+ if (verbose) {
51388
+ console.log(chalk5.gray(` Reason: ${trigger.reason}`));
51389
+ }
51390
+ });
51391
+ }
51392
+ if (verbose && template.antiPatterns.length > 0) {
51393
+ console.log(chalk5.red("\n\u26A0\uFE0F Anti-Patterns to Avoid:"));
51394
+ template.antiPatterns.forEach((pattern, i) => {
51395
+ console.log(` ${i + 1}. ${pattern}`);
51396
+ });
51397
+ }
51398
+ if (verbose && template.bestPractices.length > 0) {
51399
+ console.log(chalk5.green("\n\u2728 Best Practices:"));
51400
+ template.bestPractices.forEach((practice, i) => {
51401
+ console.log(` ${i + 1}. ${practice}`);
51402
+ });
51403
+ }
51404
+ console.log(chalk5.dim("\n\u2550".repeat(60)));
51405
+ console.log();
51406
+ }
51407
+
48513
51408
  // src/cli/index.ts
48514
51409
  installExitHandlers();
48515
51410
  var VERSION2 = getVersion();
@@ -48532,7 +51427,7 @@ globalTracker.mark("cli_start");
48532
51427
  type: "string",
48533
51428
  description: "Path to custom config file",
48534
51429
  global: true
48535
- }).command(setupCommand).command(initCommand).command(configureCommand).command(cliCommand).command(agentCommand).command(listCommand).command(runCommand).command(resumeCommand).command(runsCommand).command(sessionCommand).command(workspaceCommand).command(cacheCommand).command(configCommand).command(statusCommand4).command(doctorCommand2).command(cleanupCommand2).command(analyticsCommand).command(memoryCommand).command(mcpCommand).command(geminiCommand).command(providerLimitsCommand).command(providersCommand).command(flagsCommand).command(specCommand).command(genCommand).command(updateCommand).command(uninstallCommand).demandCommand(1, "You must provide a command. Run --help for usage.").help().version(VERSION2).alias("h", "help").alias("v", "version").strict().wrap(Math.min(120, yargs().terminalWidth())).parse();
51430
+ }).command(setupCommand).command(initCommand).command(configureCommand).command(cliCommand).command(agentCommand).command(listCommand).command(runCommand).command(resumeCommand).command(runsCommand).command(sessionCommand).command(workspaceCommand).command(cacheCommand).command(configCommand).command(statusCommand4).command(doctorCommand2).command(cleanupCommand2).command(analyticsCommand).command(memoryCommand).command(mcpCommand).command(geminiCommand).command(providerLimitsCommand).command(providersCommand).command(flagsCommand).command(specCommand).command(genCommand).command(updateCommand).command(uninstallCommand).command(modeCommand).command(debugInstructionsCommand).demandCommand(1, "You must provide a command. Run --help for usage.").help().version(VERSION2).alias("h", "help").alias("v", "version").strict().wrap(Math.min(120, yargs().terminalWidth())).parse();
48536
51431
  globalTracker.mark("yargs_parse_end");
48537
51432
  globalTracker.measure("yargs_parsing", "yargs_parse_start", "yargs_parse_end");
48538
51433
  globalTracker.mark("options_setup_start");