funolio-agent 1.0.47 → 1.0.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/dist/agent-config.d.ts +9 -1
  2. package/dist/agent-config.d.ts.map +1 -1
  3. package/dist/agent-config.js +4 -1
  4. package/dist/agent-config.js.map +1 -1
  5. package/dist/auth/auto-detect.d.ts +1 -0
  6. package/dist/auth/auto-detect.d.ts.map +1 -1
  7. package/dist/auth/auto-detect.js +16 -13
  8. package/dist/auth/auto-detect.js.map +1 -1
  9. package/dist/auto-organizer.d.ts.map +1 -1
  10. package/dist/auto-organizer.js +4 -3
  11. package/dist/auto-organizer.js.map +1 -1
  12. package/dist/backfill.d.ts.map +1 -1
  13. package/dist/backfill.js +3 -2
  14. package/dist/backfill.js.map +1 -1
  15. package/dist/bot-manager.d.ts +8 -23
  16. package/dist/bot-manager.d.ts.map +1 -1
  17. package/dist/bot-manager.js +61 -388
  18. package/dist/bot-manager.js.map +1 -1
  19. package/dist/clerk-model.d.ts +5 -1
  20. package/dist/clerk-model.d.ts.map +1 -1
  21. package/dist/clerk-model.js +40 -28
  22. package/dist/clerk-model.js.map +1 -1
  23. package/dist/cli-session-epoch.d.ts +10 -0
  24. package/dist/cli-session-epoch.d.ts.map +1 -0
  25. package/dist/cli-session-epoch.js +61 -0
  26. package/dist/cli-session-epoch.js.map +1 -0
  27. package/dist/commands/init.d.ts.map +1 -1
  28. package/dist/commands/init.js +30 -1
  29. package/dist/commands/init.js.map +1 -1
  30. package/dist/commands/pool.js +1 -1
  31. package/dist/commands/pool.js.map +1 -1
  32. package/dist/commands/setup.d.ts +37 -0
  33. package/dist/commands/setup.d.ts.map +1 -1
  34. package/dist/commands/setup.js +154 -43
  35. package/dist/commands/setup.js.map +1 -1
  36. package/dist/commands/start.d.ts.map +1 -1
  37. package/dist/commands/start.js +195 -164
  38. package/dist/commands/start.js.map +1 -1
  39. package/dist/config-cleanup.d.ts.map +1 -1
  40. package/dist/config-cleanup.js +2 -1
  41. package/dist/config-cleanup.js.map +1 -1
  42. package/dist/config.d.ts +6 -9
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +8 -30
  45. package/dist/config.js.map +1 -1
  46. package/dist/context-window.d.ts +33 -5
  47. package/dist/context-window.d.ts.map +1 -1
  48. package/dist/context-window.js +121 -20
  49. package/dist/context-window.js.map +1 -1
  50. package/dist/eval/orchestrator-front-door-replay.js +1 -1
  51. package/dist/eval/orchestrator-front-door-replay.js.map +1 -1
  52. package/dist/eval/policy-detection-replay.js +1 -1
  53. package/dist/eval/policy-detection-replay.js.map +1 -1
  54. package/dist/integration-tokens.d.ts +1 -6
  55. package/dist/integration-tokens.d.ts.map +1 -1
  56. package/dist/integration-tokens.js +38 -40
  57. package/dist/integration-tokens.js.map +1 -1
  58. package/dist/local-cli-pty-manager.d.ts +50 -0
  59. package/dist/local-cli-pty-manager.d.ts.map +1 -0
  60. package/dist/local-cli-pty-manager.js +645 -0
  61. package/dist/local-cli-pty-manager.js.map +1 -0
  62. package/dist/local-data.d.ts +30 -0
  63. package/dist/local-data.d.ts.map +1 -1
  64. package/dist/local-data.js +56 -1
  65. package/dist/local-data.js.map +1 -1
  66. package/dist/local-db.d.ts.map +1 -1
  67. package/dist/local-db.js +54 -1
  68. package/dist/local-db.js.map +1 -1
  69. package/dist/local-funnel.d.ts.map +1 -1
  70. package/dist/local-funnel.js +3 -2
  71. package/dist/local-funnel.js.map +1 -1
  72. package/dist/local-memory-search.d.ts +1 -0
  73. package/dist/local-memory-search.d.ts.map +1 -1
  74. package/dist/local-memory-search.js +101 -18
  75. package/dist/local-memory-search.js.map +1 -1
  76. package/dist/local-server.d.ts +0 -16
  77. package/dist/local-server.d.ts.map +1 -1
  78. package/dist/local-server.js +339 -287
  79. package/dist/local-server.js.map +1 -1
  80. package/dist/mcp/bridge-server.d.ts.map +1 -1
  81. package/dist/mcp/bridge-server.js +2 -1
  82. package/dist/mcp/bridge-server.js.map +1 -1
  83. package/dist/mcp/local-memory-server.d.ts +5 -0
  84. package/dist/mcp/local-memory-server.d.ts.map +1 -1
  85. package/dist/mcp/local-memory-server.js +15 -2
  86. package/dist/mcp/local-memory-server.js.map +1 -1
  87. package/dist/mcp/manager.d.ts +3 -22
  88. package/dist/mcp/manager.d.ts.map +1 -1
  89. package/dist/mcp/manager.js +66 -388
  90. package/dist/mcp/manager.js.map +1 -1
  91. package/dist/memory-extraction.d.ts +2 -0
  92. package/dist/memory-extraction.d.ts.map +1 -1
  93. package/dist/memory-extraction.js +3 -1
  94. package/dist/memory-extraction.js.map +1 -1
  95. package/dist/message-loop.d.ts +10 -6
  96. package/dist/message-loop.d.ts.map +1 -1
  97. package/dist/message-loop.js +241 -540
  98. package/dist/message-loop.js.map +1 -1
  99. package/dist/mqtt-client.d.ts +2 -31
  100. package/dist/mqtt-client.d.ts.map +1 -1
  101. package/dist/mqtt-client.js +2 -2
  102. package/dist/mqtt-client.js.map +1 -1
  103. package/dist/oauth.d.ts +6 -0
  104. package/dist/oauth.d.ts.map +1 -1
  105. package/dist/oauth.js +91 -0
  106. package/dist/oauth.js.map +1 -1
  107. package/dist/orchestration/front-door-policy.d.ts +5 -2
  108. package/dist/orchestration/front-door-policy.d.ts.map +1 -1
  109. package/dist/orchestration/front-door-policy.js +25 -28
  110. package/dist/orchestration/front-door-policy.js.map +1 -1
  111. package/dist/orchestration/orchestrator-blocked-prompt.js +1 -1
  112. package/dist/orchestration/orchestrator-final-response-prompt.js +1 -1
  113. package/dist/orchestration/orchestrator-operating-prompt.d.ts +11 -0
  114. package/dist/orchestration/orchestrator-operating-prompt.d.ts.map +1 -1
  115. package/dist/orchestration/orchestrator-operating-prompt.js +67 -44
  116. package/dist/orchestration/orchestrator-operating-prompt.js.map +1 -1
  117. package/dist/orchestration/worker-operating-prompt.js +3 -3
  118. package/dist/orchestration/worker-operating-prompt.js.map +1 -1
  119. package/dist/orchestrator.d.ts +5 -1
  120. package/dist/orchestrator.d.ts.map +1 -1
  121. package/dist/orchestrator.js +141 -81
  122. package/dist/orchestrator.js.map +1 -1
  123. package/dist/prompt-template.js +3 -3
  124. package/dist/prompt-template.js.map +1 -1
  125. package/dist/providers/claude-cli-prompt.d.ts.map +1 -1
  126. package/dist/providers/claude-cli-prompt.js +22 -6
  127. package/dist/providers/claude-cli-prompt.js.map +1 -1
  128. package/dist/providers/claude-cli.d.ts.map +1 -1
  129. package/dist/providers/claude-cli.js +20 -2
  130. package/dist/providers/claude-cli.js.map +1 -1
  131. package/dist/providers/codex-cli.d.ts.map +1 -1
  132. package/dist/providers/codex-cli.js +71 -16
  133. package/dist/providers/codex-cli.js.map +1 -1
  134. package/dist/providers/index.d.ts +11 -0
  135. package/dist/providers/index.d.ts.map +1 -1
  136. package/dist/providers/index.js.map +1 -1
  137. package/dist/runtime-context.d.ts +10 -0
  138. package/dist/runtime-context.d.ts.map +1 -0
  139. package/dist/runtime-context.js +30 -0
  140. package/dist/runtime-context.js.map +1 -0
  141. package/dist/subagent/queue.d.ts.map +1 -1
  142. package/dist/subagent/queue.js +1 -0
  143. package/dist/subagent/queue.js.map +1 -1
  144. package/dist/summarization-pipeline.d.ts +1 -0
  145. package/dist/summarization-pipeline.d.ts.map +1 -1
  146. package/dist/summarization-pipeline.js +94 -25
  147. package/dist/summarization-pipeline.js.map +1 -1
  148. package/dist/tool-permissions.d.ts +2 -0
  149. package/dist/tool-permissions.d.ts.map +1 -0
  150. package/dist/tool-permissions.js +25 -0
  151. package/dist/tool-permissions.js.map +1 -0
  152. package/dist/tools/index.d.ts +7 -8
  153. package/dist/tools/index.d.ts.map +1 -1
  154. package/dist/tools/index.js +70 -60
  155. package/dist/tools/index.js.map +1 -1
  156. package/dist/tools/search-memory.d.ts.map +1 -1
  157. package/dist/tools/search-memory.js +9 -3
  158. package/dist/tools/search-memory.js.map +1 -1
  159. package/dist/tools/spawn-subagent.d.ts.map +1 -1
  160. package/dist/tools/spawn-subagent.js +1 -0
  161. package/dist/tools/spawn-subagent.js.map +1 -1
  162. package/dist/types.d.ts +3 -0
  163. package/dist/types.d.ts.map +1 -1
  164. package/dist/types.js +0 -3
  165. package/dist/types.js.map +1 -1
  166. package/dist/wizard-support.d.ts.map +1 -1
  167. package/dist/wizard-support.js +8 -6
  168. package/dist/wizard-support.js.map +1 -1
  169. package/dist/workflow-engine.d.ts +6 -2
  170. package/dist/workflow-engine.d.ts.map +1 -1
  171. package/dist/workflow-engine.js +254 -77
  172. package/dist/workflow-engine.js.map +1 -1
  173. package/package.json +2 -1
@@ -11,6 +11,7 @@
11
11
  * No Redis required — runs entirely in-process on the user's machine.
12
12
  */
13
13
  import { EventEmitter } from 'events';
14
+ import { AgentRuntimeMode } from './runtime-context';
14
15
  export type WorkflowStepStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped';
15
16
  export interface WorkflowStep {
16
17
  id: string;
@@ -99,11 +100,14 @@ interface WorkflowRunOptions {
99
100
  workerMode?: boolean;
100
101
  stepDescription?: string;
101
102
  disallowCliRuntime?: boolean;
103
+ runtimeMode?: AgentRuntimeMode;
102
104
  }
103
105
  export declare class WorkflowEngine extends EventEmitter {
104
106
  private projectDir;
107
+ private runtimeMode;
105
108
  private activeWorkflows;
106
- constructor(projectDir: string);
109
+ constructor(projectDir: string, runtimeMode?: AgentRuntimeMode);
110
+ getRuntimeMode(): AgentRuntimeMode;
107
111
  /**
108
112
  * Execute a workflow: decompose a prompt into steps, route, and execute.
109
113
  * For simple prompts (single step), runs directly without decomposition.
@@ -173,6 +177,6 @@ export declare class WorkflowEngine extends EventEmitter {
173
177
  /** Cancel an active workflow */
174
178
  cancel(workflowId: string): boolean;
175
179
  }
176
- export declare function getWorkflowEngine(projectDir?: string): WorkflowEngine;
180
+ export declare function getWorkflowEngine(projectDir?: string, runtimeMode?: AgentRuntimeMode): WorkflowEngine;
177
181
  export {};
178
182
  //# sourceMappingURL=workflow-engine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-engine.d.ts","sourceRoot":"","sources":["../src/workflow-engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow-engine.d.ts","sourceRoot":"","sources":["../src/workflow-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAoBtC,OAAO,EAAE,gBAAgB,EAA+C,MAAM,mBAAmB,CAAC;AAMlG,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE5F,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,uBAAuB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC3C,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,cAAc,GAAG,eAAe,GAAG,gBAAgB,GAAG,aAAa,CAAC;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,GAAG,kBAAkB,GAAG,oBAAoB,CAAC;IACtI,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC3C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,sEAAsE;IACtE,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,CAAC,EAAE,uBAAuB,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC;AAmDD,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,eAAe,CAA0C;gBAErD,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,gBAAgB;IAM9D,cAAc,IAAI,gBAAgB;IAIlC;;;OAGG;IACG,OAAO,CACX,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,kBAAkB,GACxB,OAAO,CAAC,cAAc,CAAC;IAsK1B,OAAO,CAAC,sBAAsB;IAuBxB,mBAAmB,CACvB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,IAAI,CAAC,EAAE,kBAAkB,GACxB,OAAO,CAAC,cAAc,CAAC;IAoL1B;;OAEG;YACW,aAAa;IA8E3B,OAAO,CAAC,qBAAqB;IAU7B,OAAO,CAAC,sBAAsB;IAqB9B,OAAO,CAAC,4BAA4B;IAiCpC,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,aAAa;IAgErB,OAAO,CAAC,+BAA+B;IAgCvC,OAAO,CAAC,uCAAuC;IAwB/C,OAAO,CAAC,kCAAkC;IAe1C,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,qBAAqB;IA2B7B,OAAO,CAAC,gBAAgB;IAqBxB,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,wBAAwB;IA+BhC,OAAO,CAAC,wBAAwB;IAQhC,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,oBAAoB;IAc5B;;;OAGG;YACW,YAAY;IAif1B;;OAEG;YACW,WAAW;IAsiBzB,OAAO,CAAC,iCAAiC;IA2BzC,OAAO,CAAC,8BAA8B;IAKtC,OAAO,CAAC,gCAAgC;IAaxC,OAAO,CAAC,4BAA4B;IAWpC,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,aAAa;YAWP,kBAAkB;YA+DlB,4BAA4B;YAwD5B,2BAA2B;YA4D3B,0BAA0B;IAkCxC,OAAO,CAAC,YAAY;IA8CpB,oEAAoE;IACpE,OAAO,CAAC,YAAY;IAUpB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,yBAAyB;IAYjC;;;OAGG;YACW,oBAAoB;IAkFlC,kDAAkD;IAClD,kBAAkB,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;IAIlE,gCAAgC;IAChC,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;CAWpC;AAMD,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,gBAAgB,GAAG,cAAc,CAiBrG"}
@@ -62,18 +62,47 @@ const safeguards_1 = require("./orchestration/safeguards");
62
62
  const data = __importStar(require("./local-data"));
63
63
  const orchestrator_profile_1 = require("./orchestrator-profile");
64
64
  const subscription_runtime_1 = require("./auth/subscription-runtime");
65
+ const runtime_context_1 = require("./runtime-context");
66
+ const local_cli_pty_manager_1 = require("./local-cli-pty-manager");
67
+ const cli_session_epoch_1 = require("./cli-session-epoch");
65
68
  // ─── Workflow Engine ─────────────────────────────────────────────
66
69
  const MAX_STEP_ATTEMPTS = safeguards_1.SAFEGUARDS.MAX_AGENT_ATTEMPTS;
67
70
  const MAX_STEPS = safeguards_1.SAFEGUARDS.MAX_WORKFLOW_STEPS;
68
71
  function isInteractiveAuthFailure(text) {
69
72
  return /\b(not logged in|please run \/login|unauthorized|invalid api key|authentication required)\b/i.test(text);
70
73
  }
74
+ const LOCAL_WORKFLOW_RUNTIME_RETRY_LIMIT = 2;
75
+ function shouldRetrySelectedWorkflowRuntime(err) {
76
+ const text = String(err?.message || err || '').toLowerCase();
77
+ if (!text)
78
+ return false;
79
+ if (/\b(no api key|configure one in settings|not available on this machine|not installed|please run \/login|not logged in|invalid api key)\b/i.test(text)) {
80
+ return false;
81
+ }
82
+ return /\b(429|rate limit|timeout|timed out|temporar|temporarily|econnreset|etimedout|enotfound|econnrefused|socket hang up|network|try again|overloaded|busy)\b/i.test(text);
83
+ }
84
+ async function pauseWorkflowRuntimeRetry(attempt) {
85
+ const delayMs = attempt <= 1 ? 750 : 1500;
86
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
87
+ }
88
+ function buildWorkflowPtyConversationKey(conversationId, step, workflowContext) {
89
+ if (conversationId)
90
+ return conversationId;
91
+ if (workflowContext?.workflowId)
92
+ return `workflow:${workflowContext.workflowId}`;
93
+ return `adhoc:${step.agentId}:${step.id}`;
94
+ }
71
95
  class WorkflowEngine extends events_1.EventEmitter {
72
96
  projectDir;
97
+ runtimeMode;
73
98
  activeWorkflows = new Map();
74
- constructor(projectDir) {
99
+ constructor(projectDir, runtimeMode) {
75
100
  super();
76
101
  this.projectDir = projectDir;
102
+ this.runtimeMode = (0, runtime_context_1.normalizeRuntimeMode)(runtimeMode || (0, runtime_context_1.getDefaultRuntimeMode)());
103
+ }
104
+ getRuntimeMode() {
105
+ return this.runtimeMode;
77
106
  }
78
107
  /**
79
108
  * Execute a workflow: decompose a prompt into steps, route, and execute.
@@ -82,7 +111,8 @@ class WorkflowEngine extends events_1.EventEmitter {
82
111
  async execute(prompt, conversationId, agentId, opts) {
83
112
  const workflowId = crypto.randomUUID();
84
113
  const startedAt = Date.now();
85
- const clerk = (0, clerk_model_1.getClerk)();
114
+ const effectiveRuntimeMode = (0, runtime_context_1.normalizeRuntimeMode)(opts?.runtimeMode || this.runtimeMode);
115
+ const clerk = (0, clerk_model_1.getClerk)({ runtimeMode: effectiveRuntimeMode });
86
116
  const allProfiles = data.listAgentProfiles();
87
117
  // Filter out orchestrator profiles by default, but allow explicitly assigned specialists
88
118
  // and the selected agent back into the planning pool when needed.
@@ -283,7 +313,7 @@ class WorkflowEngine extends events_1.EventEmitter {
283
313
  `TODO ITEM #${task.id}: ${task.title}`,
284
314
  task.details ? `Task details:\n${task.details}` : '',
285
315
  'Work only on this TODO item. Do not mark any other item complete.',
286
- 'When your stage is complete, return the structured footer Funolio requires so routing can continue automatically.',
316
+ 'When your stage is complete, return the structured footer required below so routing can continue automatically.',
287
317
  ].filter(Boolean).join('\n\n');
288
318
  const steps = template.steps
289
319
  .sort((a, b) => a.order_index - b.order_index)
@@ -635,7 +665,7 @@ class WorkflowEngine extends events_1.EventEmitter {
635
665
  ? 'Include REASON only when STATUS is FAIL.'
636
666
  : 'Include REASON only when STATUS is BLOCKED.';
637
667
  return [
638
- `You are ${profile?.name || 'a Funolio workflow worker'}.`,
668
+ `You are ${profile?.name || 'a workflow worker'}.`,
639
669
  'Complete only the assigned workflow step.',
640
670
  roleLine,
641
671
  'Use available tools when the task requires creating, changing, or verifying files.',
@@ -656,8 +686,8 @@ class WorkflowEngine extends events_1.EventEmitter {
656
686
  ? 'Your role is QA. Verify the delivered work, then complete the TODO through the worker tool or create the next fix handoff.'
657
687
  : 'Your role is implementer. Do the assigned work, then complete the TODO through the worker tool.';
658
688
  return [
659
- `You are ${profile?.name || 'a Funolio workflow worker'}.`,
660
- 'You are executing one orchestrated TODO task inside Funolio.',
689
+ `You are ${profile?.name || 'a workflow worker'}.`,
690
+ 'You are executing one orchestrated TODO task.',
661
691
  roleLine,
662
692
  'Follow the assignment in the user message exactly.',
663
693
  'Use available tools when needed.',
@@ -833,6 +863,7 @@ class WorkflowEngine extends events_1.EventEmitter {
833
863
  * Handles checkpoint loop-back and footer-driven retry/failure logic.
834
864
  */
835
865
  async executeSteps(workflowId, steps, conversationId, opts) {
866
+ const effectiveRuntimeMode = (0, runtime_context_1.normalizeRuntimeMode)(opts?.runtimeMode || this.runtimeMode);
836
867
  const completed = new Set();
837
868
  const failed = new Set();
838
869
  const allowMissingFooterForDirectStep = !opts?.isOrchestrated && !!opts?.disableDecomposition && steps.length === 1;
@@ -1115,7 +1146,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1115
1146
  && !hasFutureQaStep
1116
1147
  && !opts?.isOrchestrated;
1117
1148
  if (shouldRunClerkVerification) {
1118
- const verifyClerk = (0, clerk_model_1.getClerk)();
1149
+ const verifyClerk = (0, clerk_model_1.getClerk)({ runtimeMode: effectiveRuntimeMode });
1119
1150
  if (verifyClerk) {
1120
1151
  try {
1121
1152
  const verification = await verifyClerk.verifyStepOutput(step.description, step.expectedOutput, result);
@@ -1286,7 +1317,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1286
1317
  }
1287
1318
  else if (step.attempts < step.maxAttempts) {
1288
1319
  // Nudge on retry — generate adjusted prompt
1289
- const nudgeClerk = (0, clerk_model_1.getClerk)();
1320
+ const nudgeClerk = (0, clerk_model_1.getClerk)({ runtimeMode: effectiveRuntimeMode });
1290
1321
  if (nudgeClerk) {
1291
1322
  try {
1292
1323
  const nudge = await nudgeClerk.generateNudge(step.description, step.prompt, err.message);
@@ -1327,12 +1358,14 @@ class WorkflowEngine extends events_1.EventEmitter {
1327
1358
  * Execute a single workflow step: call LLM with tools, agentic loop.
1328
1359
  */
1329
1360
  async executeStep(step, prompt, conversationId, opts, apiKey, workflowContext) {
1361
+ const effectiveRuntimeMode = (0, runtime_context_1.normalizeRuntimeMode)(opts?.runtimeMode || this.runtimeMode);
1330
1362
  const profile = data.getAgentProfile(step.agentId);
1331
1363
  const runtime = await this.resolveStepRuntime(step, profile, apiKey, opts);
1332
1364
  let activeRuntime = runtime;
1333
1365
  let llm = (0, index_1.createProvider)(activeRuntime.providerName, {
1334
1366
  apiKey: activeRuntime.apiKey,
1335
1367
  model: activeRuntime.model,
1368
+ runtimeMode: effectiveRuntimeMode,
1336
1369
  ...(activeRuntime.requestShape ? { requestShape: activeRuntime.requestShape } : {}),
1337
1370
  ...(activeRuntime.baseUrl ? { baseUrl: activeRuntime.baseUrl } : {}),
1338
1371
  ...(activeRuntime.apiQuery ? { apiQuery: activeRuntime.apiQuery } : {}),
@@ -1344,7 +1377,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1344
1377
  ...(opts?.isOrchestrated ? { toolProjectId: opts?.projectId ?? null } : {}),
1345
1378
  ...(opts?.isOrchestrated ? { currentTodoTaskId: opts?.taskId } : {}),
1346
1379
  });
1347
- const toolDefs = (0, index_2.getAllToolDefinitions)();
1380
+ const toolDefs = (0, index_2.getAllToolDefinitions)(effectiveRuntimeMode);
1348
1381
  const workspacePath = opts?.workspacePath?.trim();
1349
1382
  const effectiveProjectDir = workspacePath || this.projectDir;
1350
1383
  const unrestrictedCliProvider = index_1.CLI_PROVIDERS.has(step.provider);
@@ -1353,12 +1386,13 @@ class WorkflowEngine extends events_1.EventEmitter {
1353
1386
  currentTodoTaskId: opts?.taskId,
1354
1387
  actorType: 'llm',
1355
1388
  actorId: step.agentName || step.agentId,
1389
+ runtimeMode: effectiveRuntimeMode,
1356
1390
  restrictFileAccessToProject: unrestrictedCliProvider ? false : undefined,
1357
1391
  });
1358
1392
  const isWorkflowWorker = opts?.workerMode !== false;
1359
1393
  let systemPrompt = profile?.soul_md
1360
- || 'You are a Funolio AI agent working on a specific task step.';
1361
- const clerk = (0, clerk_model_1.getClerk)();
1394
+ || 'You are an AI assistant working on a specific task step.';
1395
+ const clerk = (0, clerk_model_1.getClerk)({ runtimeMode: effectiveRuntimeMode });
1362
1396
  if (opts?.systemPromptOverride?.trim()) {
1363
1397
  systemPrompt = opts.systemPromptOverride.trim();
1364
1398
  }
@@ -1393,11 +1427,23 @@ class WorkflowEngine extends events_1.EventEmitter {
1393
1427
  const messages = [{ role: 'user', content: effectivePrompt }];
1394
1428
  const promptChars = effectivePrompt.length;
1395
1429
  const systemChars = systemPrompt.length;
1430
+ const isLocalCliSession = effectiveRuntimeMode === 'local_desktop'
1431
+ && (activeRuntime.providerName === 'claude-cli' || activeRuntime.providerName === 'codex-cli');
1432
+ const hasPersistentConversation = isLocalCliSession && !!conversationId;
1433
+ const cliSessionEpochPlan = hasPersistentConversation
1434
+ ? (0, cli_session_epoch_1.selectCliSessionEpoch)(conversationId, step.agentId, activeRuntime.providerName)
1435
+ : { existing: undefined, resumeSessionId: null, resetReason: null };
1436
+ let activeCliSessionId = cliSessionEpochPlan.resumeSessionId;
1437
+ const cliEpochStartedAt = cliSessionEpochPlan.resumeSessionId
1438
+ ? (cliSessionEpochPlan.existing?.epoch_started_at || (0, cli_session_epoch_1.localTimestamp)())
1439
+ : (0, cli_session_epoch_1.localTimestamp)();
1440
+ const ptyConversationKey = buildWorkflowPtyConversationKey(conversationId, step, workflowContext);
1396
1441
  console.info(`[workflow-engine] step runtime: agent=${step.agentName} provider=${activeRuntime.providerName} model=${activeRuntime.model} runtime=${activeRuntime.runtimeLabel || 'unknown'} promptChars=${promptChars} systemChars=${systemChars} tools=${opts?.disableTools ? 0 : toolDefs.length}`);
1397
1442
  // Agentic loop
1398
1443
  let iteration = 0;
1399
1444
  const MAX_ITERATIONS = safeguards_1.SAFEGUARDS.MAX_WORKFLOW_ITERATIONS;
1400
1445
  let incompleteExecutionRecoveries = 0;
1446
+ let selectedRuntimeRetryCount = 0;
1401
1447
  while (iteration < MAX_ITERATIONS) {
1402
1448
  if (opts?.isOrchestrated && this.orchestratedTodoHandled(opts.taskId)) {
1403
1449
  return this.buildOrchestratedTodoHandledResult(opts.taskId);
@@ -1418,70 +1464,155 @@ class WorkflowEngine extends events_1.EventEmitter {
1418
1464
  : 'auto';
1419
1465
  let response;
1420
1466
  try {
1421
- response = await llm.chat({
1422
- messages,
1423
- system: systemPrompt,
1424
- stream: true,
1425
- toolChoice,
1426
- onChunk: async (chunk) => {
1427
- streamedContent += chunk;
1428
- // Forward chunks to onWorkerChunk with 150ms/80-char buffer
1429
- if (opts?.onWorkerChunk) {
1430
- chunkBuffer += chunk;
1431
- const now2 = Date.now();
1432
- if (chunkBuffer.length >= 80 || now2 - lastChunkForwardAt >= 150) {
1433
- opts.onWorkerChunk({
1434
- type: opts?.isOrchestrated ? 'worker_chunk' : 'chunk',
1435
- stepId: step.id,
1436
- agentName: step.agentName,
1437
- description: step.description,
1438
- stepIndex: workflowContext?.stepIndex ?? 0,
1439
- totalSteps: workflowContext?.totalSteps ?? 1,
1440
- text: chunkBuffer,
1441
- });
1442
- chunkBuffer = '';
1443
- lastChunkForwardAt = now2;
1467
+ if (isLocalCliSession) {
1468
+ if (cliSessionEpochPlan.resetReason && iteration === 1 && opts?.onWorkerChunk) {
1469
+ const resetDetail = cliSessionEpochPlan.resetReason === 'turn_limit'
1470
+ ? 'Resetting CLI session after reaching the turn limit.'
1471
+ : cliSessionEpochPlan.resetReason === 'token_limit'
1472
+ ? 'Resetting CLI session after reaching the context budget.'
1473
+ : 'Resetting CLI session because the runtime changed.';
1474
+ opts.onWorkerChunk({
1475
+ type: opts?.isOrchestrated ? 'worker_chunk' : 'chunk',
1476
+ stepId: step.id,
1477
+ agentName: step.agentName,
1478
+ description: step.description,
1479
+ stepIndex: workflowContext?.stepIndex ?? 0,
1480
+ totalSteps: workflowContext?.totalSteps ?? 1,
1481
+ text: resetDetail,
1482
+ });
1483
+ }
1484
+ const ptyManager = (0, local_cli_pty_manager_1.getLocalCliPtySessionManager)();
1485
+ let ptyAttempt = 0;
1486
+ while (true) {
1487
+ ptyAttempt++;
1488
+ try {
1489
+ const ptyResult = await ptyManager.runTurn({
1490
+ conversationId: ptyConversationKey,
1491
+ botId: step.agentId,
1492
+ provider: activeRuntime.providerName,
1493
+ cwd: effectiveProjectDir,
1494
+ systemPrompt,
1495
+ messages,
1496
+ forceFreshSession: !hasPersistentConversation || (iteration === 1 && !cliSessionEpochPlan.resumeSessionId),
1497
+ onDetail: async (detail) => {
1498
+ streamedContent += streamedContent ? `\n${detail}` : detail;
1499
+ if (opts?.onWorkerChunk) {
1500
+ opts.onWorkerChunk({
1501
+ type: opts?.isOrchestrated ? 'worker_chunk' : 'chunk',
1502
+ stepId: step.id,
1503
+ agentName: step.agentName,
1504
+ description: step.description,
1505
+ stepIndex: workflowContext?.stepIndex ?? 0,
1506
+ totalSteps: workflowContext?.totalSteps ?? 1,
1507
+ text: detail,
1508
+ });
1509
+ }
1510
+ const now = Date.now();
1511
+ if (now - lastChunkProgressAt < 8000)
1512
+ return;
1513
+ lastChunkProgressAt = now;
1514
+ const activeSteps = workflowContext?.workflowId
1515
+ ? this.getActiveWorkflows().find((w) => w.id === workflowContext.workflowId)?.steps || [step]
1516
+ : [step];
1517
+ this.emitProgress(workflowContext?.workflowId || 'workflow', step, activeSteps, 'step-progress', opts?.onProgress, `${step.agentName} is still working on ${step.description}`);
1518
+ },
1519
+ });
1520
+ if (ptyResult.sessionId) {
1521
+ activeCliSessionId = ptyResult.sessionId;
1444
1522
  }
1523
+ response = {
1524
+ content: ptyResult.content || '',
1525
+ usage: ptyResult.usage,
1526
+ };
1527
+ break;
1445
1528
  }
1446
- // Existing 8-second heartbeat for backward compat
1447
- const now = Date.now();
1448
- if (now - lastChunkProgressAt < 8000)
1449
- return;
1450
- lastChunkProgressAt = now;
1451
- const compact = chunk.replace(/\s+/g, ' ').trim();
1452
- if (!compact && emittedChunkHeartbeat)
1453
- return;
1454
- emittedChunkHeartbeat = true;
1455
- const preview = `${step.agentName} is still working on ${step.description}`;
1456
- const activeSteps = workflowContext?.workflowId
1457
- ? this.getActiveWorkflows().find((w) => w.id === workflowContext.workflowId)?.steps || [step]
1458
- : [step];
1459
- this.emitProgress(workflowContext?.workflowId || 'workflow', step, activeSteps, 'step-progress', opts?.onProgress, preview);
1460
- },
1461
- tools: opts?.disableTools ? undefined : toolDefs,
1462
- cwd: effectiveProjectDir,
1463
- });
1464
- // Flush remaining chunk buffer
1465
- if (opts?.onWorkerChunk && chunkBuffer) {
1466
- opts.onWorkerChunk({
1467
- type: opts?.isOrchestrated ? 'worker_chunk' : 'chunk',
1468
- stepId: step.id,
1469
- agentName: step.agentName,
1470
- description: step.description,
1471
- stepIndex: workflowContext?.stepIndex ?? 0,
1472
- totalSteps: workflowContext?.totalSteps ?? 1,
1473
- text: chunkBuffer,
1529
+ catch (ptyErr) {
1530
+ if (ptyAttempt >= LOCAL_WORKFLOW_RUNTIME_RETRY_LIMIT
1531
+ || !shouldRetrySelectedWorkflowRuntime(ptyErr)) {
1532
+ throw ptyErr;
1533
+ }
1534
+ console.warn(`[workflow-engine] ${step.agentName} selected runtime failed, retrying the same connection (${ptyAttempt + 1}/${LOCAL_WORKFLOW_RUNTIME_RETRY_LIMIT})`);
1535
+ await pauseWorkflowRuntimeRetry(ptyAttempt);
1536
+ }
1537
+ }
1538
+ }
1539
+ else {
1540
+ response = await llm.chat({
1541
+ messages,
1542
+ system: systemPrompt,
1543
+ stream: true,
1544
+ toolChoice,
1545
+ onChunk: async (chunk) => {
1546
+ streamedContent += chunk;
1547
+ // Forward chunks to onWorkerChunk with 150ms/80-char buffer
1548
+ if (opts?.onWorkerChunk) {
1549
+ chunkBuffer += chunk;
1550
+ const now2 = Date.now();
1551
+ if (chunkBuffer.length >= 80 || now2 - lastChunkForwardAt >= 150) {
1552
+ opts.onWorkerChunk({
1553
+ type: opts?.isOrchestrated ? 'worker_chunk' : 'chunk',
1554
+ stepId: step.id,
1555
+ agentName: step.agentName,
1556
+ description: step.description,
1557
+ stepIndex: workflowContext?.stepIndex ?? 0,
1558
+ totalSteps: workflowContext?.totalSteps ?? 1,
1559
+ text: chunkBuffer,
1560
+ });
1561
+ chunkBuffer = '';
1562
+ lastChunkForwardAt = now2;
1563
+ }
1564
+ }
1565
+ // Existing 8-second heartbeat for backward compat
1566
+ const now = Date.now();
1567
+ if (now - lastChunkProgressAt < 8000)
1568
+ return;
1569
+ lastChunkProgressAt = now;
1570
+ const compact = chunk.replace(/\s+/g, ' ').trim();
1571
+ if (!compact && emittedChunkHeartbeat)
1572
+ return;
1573
+ emittedChunkHeartbeat = true;
1574
+ const preview = `${step.agentName} is still working on ${step.description}`;
1575
+ const activeSteps = workflowContext?.workflowId
1576
+ ? this.getActiveWorkflows().find((w) => w.id === workflowContext.workflowId)?.steps || [step]
1577
+ : [step];
1578
+ this.emitProgress(workflowContext?.workflowId || 'workflow', step, activeSteps, 'step-progress', opts?.onProgress, preview);
1579
+ },
1580
+ tools: opts?.disableTools ? undefined : toolDefs,
1581
+ cwd: effectiveProjectDir,
1474
1582
  });
1475
- chunkBuffer = '';
1583
+ // Flush remaining chunk buffer
1584
+ if (opts?.onWorkerChunk && chunkBuffer) {
1585
+ opts.onWorkerChunk({
1586
+ type: opts?.isOrchestrated ? 'worker_chunk' : 'chunk',
1587
+ stepId: step.id,
1588
+ agentName: step.agentName,
1589
+ description: step.description,
1590
+ stepIndex: workflowContext?.stepIndex ?? 0,
1591
+ totalSteps: workflowContext?.totalSteps ?? 1,
1592
+ text: chunkBuffer,
1593
+ });
1594
+ chunkBuffer = '';
1595
+ }
1476
1596
  }
1597
+ selectedRuntimeRetryCount = 0;
1477
1598
  }
1478
1599
  catch (err) {
1479
1600
  console.warn(`[workflow-engine] step error: agent=${step.agentName} provider=${activeRuntime.providerName} model=${activeRuntime.model} runtime=${activeRuntime.runtimeLabel || 'unknown'} iteration=${iteration} message=${err?.message || err}`);
1480
- if (activeRuntime.fallback) {
1601
+ if (effectiveRuntimeMode === 'local_desktop'
1602
+ && selectedRuntimeRetryCount < (LOCAL_WORKFLOW_RUNTIME_RETRY_LIMIT - 1)
1603
+ && shouldRetrySelectedWorkflowRuntime(err)) {
1604
+ selectedRuntimeRetryCount++;
1605
+ console.warn(`[workflow-engine] ${step.agentName} selected runtime failed, retrying the same connection (${selectedRuntimeRetryCount + 1}/${LOCAL_WORKFLOW_RUNTIME_RETRY_LIMIT})`);
1606
+ await pauseWorkflowRuntimeRetry(selectedRuntimeRetryCount);
1607
+ iteration--;
1608
+ continue;
1609
+ }
1610
+ if (effectiveRuntimeMode !== 'local_desktop' && activeRuntime.fallback) {
1481
1611
  activeRuntime = activeRuntime.fallback;
1482
1612
  llm = (0, index_1.createProvider)(activeRuntime.providerName, {
1483
1613
  apiKey: activeRuntime.apiKey,
1484
1614
  model: activeRuntime.model,
1615
+ runtimeMode: effectiveRuntimeMode,
1485
1616
  ...(activeRuntime.requestShape ? { requestShape: activeRuntime.requestShape } : {}),
1486
1617
  ...(activeRuntime.baseUrl ? { baseUrl: activeRuntime.baseUrl } : {}),
1487
1618
  ...(activeRuntime.apiQuery ? { apiQuery: activeRuntime.apiQuery } : {}),
@@ -1499,6 +1630,23 @@ class WorkflowEngine extends events_1.EventEmitter {
1499
1630
  }
1500
1631
  throw err;
1501
1632
  }
1633
+ if (hasPersistentConversation && activeCliSessionId && !response.toolCalls?.length) {
1634
+ const nextEpochTurnCount = cliSessionEpochPlan.resumeSessionId
1635
+ ? ((cliSessionEpochPlan.existing?.epoch_turn_count || 0) + 1)
1636
+ : 1;
1637
+ data.upsertCliSessionEpoch({
1638
+ conversationId: conversationId,
1639
+ botId: step.agentId,
1640
+ provider: activeRuntime.providerName,
1641
+ sessionId: activeCliSessionId,
1642
+ epochTurnCount: nextEpochTurnCount,
1643
+ lastInputTokens: response.usage?.inputTokens ?? null,
1644
+ lastOutputTokens: response.usage?.outputTokens ?? null,
1645
+ resetReason: cliSessionEpochPlan.resetReason,
1646
+ epochStartedAt: cliEpochStartedAt,
1647
+ lastUsedAt: (0, cli_session_epoch_1.localTimestamp)(),
1648
+ });
1649
+ }
1502
1650
  if (response.toolCalls && response.toolCalls.length > 0) {
1503
1651
  messages.push({
1504
1652
  role: 'assistant',
@@ -1610,12 +1758,15 @@ class WorkflowEngine extends events_1.EventEmitter {
1610
1758
  this.emitProgress(workflowContext?.workflowId || 'workflow', step, activeSteps, 'step-progress', opts?.onProgress, `${step.agentName} described intended work instead of executing it. Retrying with an explicit tool-use correction.`);
1611
1759
  continue;
1612
1760
  }
1613
- if (activeRuntime.fallback && activeRuntime.providerName !== activeRuntime.fallback.providerName) {
1761
+ if (effectiveRuntimeMode !== 'local_desktop'
1762
+ && activeRuntime.fallback
1763
+ && activeRuntime.providerName !== activeRuntime.fallback.providerName) {
1614
1764
  console.warn(`[workflow-engine] forcing runtime fallback after repeated incomplete execution: agent=${step.agentName} from=${activeRuntime.providerName} to=${activeRuntime.fallback.providerName}`);
1615
1765
  activeRuntime = activeRuntime.fallback;
1616
1766
  llm = (0, index_1.createProvider)(activeRuntime.providerName, {
1617
1767
  apiKey: activeRuntime.apiKey,
1618
1768
  model: activeRuntime.model,
1769
+ runtimeMode: effectiveRuntimeMode,
1619
1770
  ...(activeRuntime.requestShape ? { requestShape: activeRuntime.requestShape } : {}),
1620
1771
  ...(activeRuntime.baseUrl ? { baseUrl: activeRuntime.baseUrl } : {}),
1621
1772
  ...(activeRuntime.apiQuery ? { apiQuery: activeRuntime.apiQuery } : {}),
@@ -1747,11 +1898,12 @@ class WorkflowEngine extends events_1.EventEmitter {
1747
1898
  }
1748
1899
  }
1749
1900
  async resolveStepRuntime(step, profile, apiKey, opts) {
1901
+ const effectiveRuntimeMode = (0, runtime_context_1.normalizeRuntimeMode)(opts?.runtimeMode || this.runtimeMode);
1750
1902
  if (step.provider === 'claude-cli') {
1751
- return this.resolveClaudeWorkflowRuntime(step, profile, opts?.disallowCliRuntime === true);
1903
+ return this.resolveClaudeWorkflowRuntime(step, profile, opts?.disallowCliRuntime === true && effectiveRuntimeMode !== 'local_desktop', effectiveRuntimeMode);
1752
1904
  }
1753
1905
  if (step.provider === 'codex-cli') {
1754
- return this.resolveCodexWorkflowRuntime(step, profile, opts?.disallowCliRuntime === true);
1906
+ return this.resolveCodexWorkflowRuntime(step, profile, opts?.disallowCliRuntime === true && effectiveRuntimeMode !== 'local_desktop', effectiveRuntimeMode);
1755
1907
  }
1756
1908
  const profileConnection = profile?.provider_connection_id
1757
1909
  ? data.getProviderConnection(profile.provider_connection_id)
@@ -1760,7 +1912,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1760
1912
  || profileConnection?.api_key_enc
1761
1913
  || apiKey
1762
1914
  || this.resolveApiKey(step.provider);
1763
- if (!resolvedKey && step.provider === 'openai') {
1915
+ if (effectiveRuntimeMode !== 'local_desktop' && !resolvedKey && step.provider === 'openai') {
1764
1916
  const preferredModel = (0, subscription_runtime_1.resolveSubscriptionApiModel)(step.model || profile?.model, data.findProviderConnection('openai')?.default_model || undefined) || (step.model || profile?.model || 'default').trim() || 'default';
1765
1917
  const subscriptionRuntime = await (0, subscription_runtime_1.resolveCodexSubscriptionRuntime)({
1766
1918
  preferredModel,
@@ -1786,7 +1938,15 @@ class WorkflowEngine extends events_1.EventEmitter {
1786
1938
  runtimeLabel: 'API Key',
1787
1939
  };
1788
1940
  }
1789
- async resolveClaudeWorkflowRuntime(step, profile, disallowCliRuntime = false) {
1941
+ async resolveClaudeWorkflowRuntime(step, profile, disallowCliRuntime = false, runtimeMode = this.runtimeMode) {
1942
+ if (runtimeMode === 'local_desktop') {
1943
+ return {
1944
+ providerName: 'claude-cli',
1945
+ apiKey: 'cli-auth',
1946
+ model: (step.model || profile?.model || 'default').trim() || 'default',
1947
+ runtimeLabel: 'Subscription CLI',
1948
+ };
1949
+ }
1790
1950
  const preferredModel = (0, subscription_runtime_1.resolveSubscriptionApiModel)(step.model || profile?.model, data.findProviderConnection('anthropic')?.default_model || data.findProviderConnection('claude-cli')?.default_model || undefined) || (step.model || profile?.model || 'default').trim() || 'default';
1791
1951
  const apiKeyFallback = data.findProviderConnection('anthropic')?.api_key_enc || process.env.ANTHROPIC_API_KEY;
1792
1952
  const apiFallbackConfig = apiKeyFallback
@@ -1826,7 +1986,15 @@ class WorkflowEngine extends events_1.EventEmitter {
1826
1986
  };
1827
1987
  return cliFallbackConfig;
1828
1988
  }
1829
- async resolveCodexWorkflowRuntime(step, profile, disallowCliRuntime = false) {
1989
+ async resolveCodexWorkflowRuntime(step, profile, disallowCliRuntime = false, runtimeMode = this.runtimeMode) {
1990
+ if (runtimeMode === 'local_desktop') {
1991
+ return {
1992
+ providerName: 'codex-cli',
1993
+ apiKey: 'cli-auth',
1994
+ model: (step.model || profile?.model || 'default').trim() || 'default',
1995
+ runtimeLabel: 'Subscription CLI',
1996
+ };
1997
+ }
1830
1998
  const preferredModel = (0, subscription_runtime_1.resolveSubscriptionApiModel)(step.model || profile?.model, data.findProviderConnection('openai')?.default_model || data.findProviderConnection('codex-cli')?.default_model || undefined)
1831
1999
  || (step.model || profile?.model || 'default').trim()
1832
2000
  || 'default';
@@ -1979,7 +2147,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1979
2147
  async replanRemainingSteps(steps, failedStep, agents, defaultProfile) {
1980
2148
  if (steps.length <= 1)
1981
2149
  return null;
1982
- const clerk = (0, clerk_model_1.getClerk)();
2150
+ const clerk = (0, clerk_model_1.getClerk)({ runtimeMode: this.runtimeMode });
1983
2151
  if (!clerk)
1984
2152
  return null;
1985
2153
  const completedSummary = steps
@@ -2070,15 +2238,24 @@ Rules:
2070
2238
  }
2071
2239
  exports.WorkflowEngine = WorkflowEngine;
2072
2240
  // ─── Singleton ───────────────────────────────────────────────────
2073
- let _engine = null;
2074
- function getWorkflowEngine(projectDir) {
2075
- if (!_engine && projectDir) {
2076
- _engine = new WorkflowEngine(projectDir);
2241
+ const _workflowEngines = new Map();
2242
+ function getWorkflowEngine(projectDir, runtimeMode) {
2243
+ const effectiveRuntimeMode = (0, runtime_context_1.normalizeRuntimeMode)(runtimeMode || (0, runtime_context_1.getDefaultRuntimeMode)());
2244
+ const existing = _workflowEngines.get(effectiveRuntimeMode);
2245
+ if (existing) {
2246
+ if (!projectDir || existing.projectDir === projectDir) {
2247
+ return existing;
2248
+ }
2249
+ }
2250
+ if (projectDir) {
2251
+ const engine = new WorkflowEngine(projectDir, effectiveRuntimeMode);
2252
+ _workflowEngines.set(effectiveRuntimeMode, engine);
2253
+ return engine;
2077
2254
  }
2078
- if (!_engine) {
2255
+ if (!_workflowEngines.size) {
2079
2256
  throw new Error('Workflow engine not initialized. Call getWorkflowEngine(projectDir) first.');
2080
2257
  }
2081
- return _engine;
2258
+ throw new Error(`Workflow engine not initialized for runtime ${effectiveRuntimeMode}. Call getWorkflowEngine(projectDir, runtimeMode) first.`);
2082
2259
  }
2083
2260
  // ─── JSON Parsing Helper ─────────────────────────────────────────
2084
2261
  function parseJsonResponse(text) {