fixo-cli 1.0.4 → 2.0.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.

Potentially problematic release.


This version of fixo-cli might be problematic. Click here for more details.

Files changed (199) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +18 -14
  3. package/dist/agent/agent-client.d.ts +28 -6
  4. package/dist/agent/agent-client.d.ts.map +1 -1
  5. package/dist/agent/agent-client.js +118 -39
  6. package/dist/agent/agent-client.js.map +1 -1
  7. package/dist/agent/agent-pool.d.ts +55 -6
  8. package/dist/agent/agent-pool.d.ts.map +1 -1
  9. package/dist/agent/agent-pool.js +120 -20
  10. package/dist/agent/agent-pool.js.map +1 -1
  11. package/dist/agent/auto-verifier.d.ts +55 -0
  12. package/dist/agent/auto-verifier.d.ts.map +1 -0
  13. package/dist/agent/auto-verifier.js +50 -0
  14. package/dist/agent/auto-verifier.js.map +1 -0
  15. package/dist/agent/command-parser.d.ts.map +1 -1
  16. package/dist/agent/command-parser.js +176 -0
  17. package/dist/agent/command-parser.js.map +1 -1
  18. package/dist/agent/context-builder.d.ts +24 -0
  19. package/dist/agent/context-builder.d.ts.map +1 -0
  20. package/dist/agent/context-builder.js +197 -0
  21. package/dist/agent/context-builder.js.map +1 -0
  22. package/dist/agent/conversation.d.ts +14 -1
  23. package/dist/agent/conversation.d.ts.map +1 -1
  24. package/dist/agent/conversation.js +53 -7
  25. package/dist/agent/conversation.js.map +1 -1
  26. package/dist/agent/mcp-bridge.js +1 -1
  27. package/dist/agent/mcp-bridge.js.map +1 -1
  28. package/dist/agent/orchestrator.d.ts +45 -0
  29. package/dist/agent/orchestrator.d.ts.map +1 -1
  30. package/dist/agent/orchestrator.js +140 -3
  31. package/dist/agent/orchestrator.js.map +1 -1
  32. package/dist/agent/parser-adapter.d.ts +17 -0
  33. package/dist/agent/parser-adapter.d.ts.map +1 -1
  34. package/dist/agent/parser-adapter.js +254 -2
  35. package/dist/agent/parser-adapter.js.map +1 -1
  36. package/dist/agent/predictive-gate.d.ts.map +1 -1
  37. package/dist/agent/predictive-gate.js +4 -1
  38. package/dist/agent/predictive-gate.js.map +1 -1
  39. package/dist/agent/providers-manager.d.ts +5 -0
  40. package/dist/agent/providers-manager.d.ts.map +1 -1
  41. package/dist/agent/providers-manager.js +119 -8
  42. package/dist/agent/providers-manager.js.map +1 -1
  43. package/dist/agent/repo-map.d.ts +18 -1
  44. package/dist/agent/repo-map.d.ts.map +1 -1
  45. package/dist/agent/repo-map.js +144 -54
  46. package/dist/agent/repo-map.js.map +1 -1
  47. package/dist/agent/retry.js +1 -2
  48. package/dist/agent/retry.js.map +1 -1
  49. package/dist/agent/single-agent.d.ts.map +1 -1
  50. package/dist/agent/single-agent.js +129 -22
  51. package/dist/agent/single-agent.js.map +1 -1
  52. package/dist/agent/skills.d.ts.map +1 -1
  53. package/dist/agent/skills.js +2 -1
  54. package/dist/agent/skills.js.map +1 -1
  55. package/dist/agent/subagent.js +2 -2
  56. package/dist/agent/subagent.js.map +1 -1
  57. package/dist/agent/task-router.d.ts +46 -0
  58. package/dist/agent/task-router.d.ts.map +1 -0
  59. package/dist/agent/task-router.js +352 -0
  60. package/dist/agent/task-router.js.map +1 -0
  61. package/dist/agent/telemetry.d.ts +29 -1
  62. package/dist/agent/telemetry.d.ts.map +1 -1
  63. package/dist/agent/telemetry.js +25 -10
  64. package/dist/agent/telemetry.js.map +1 -1
  65. package/dist/agent/tool-definitions.d.ts +3 -0
  66. package/dist/agent/tool-definitions.d.ts.map +1 -0
  67. package/dist/agent/tool-definitions.js +519 -0
  68. package/dist/agent/tool-definitions.js.map +1 -0
  69. package/dist/agent/tool-executor.d.ts +6 -1
  70. package/dist/agent/tool-executor.d.ts.map +1 -1
  71. package/dist/agent/tool-executor.js +99 -553
  72. package/dist/agent/tool-executor.js.map +1 -1
  73. package/dist/agent/tools/command-tools.d.ts +6 -0
  74. package/dist/agent/tools/command-tools.d.ts.map +1 -0
  75. package/dist/agent/tools/command-tools.js +104 -0
  76. package/dist/agent/tools/command-tools.js.map +1 -0
  77. package/dist/agent/tools/file-tools.d.ts +15 -0
  78. package/dist/agent/tools/file-tools.d.ts.map +1 -0
  79. package/dist/agent/tools/file-tools.js +551 -0
  80. package/dist/agent/tools/file-tools.js.map +1 -0
  81. package/dist/agent/tools/todo-tools.d.ts +3 -0
  82. package/dist/agent/tools/todo-tools.d.ts.map +1 -0
  83. package/dist/agent/tools/todo-tools.js +70 -0
  84. package/dist/agent/tools/todo-tools.js.map +1 -0
  85. package/dist/agent/web-impl.d.ts.map +1 -1
  86. package/dist/agent/web-impl.js +45 -0
  87. package/dist/agent/web-impl.js.map +1 -1
  88. package/dist/agent/worker-agent.d.ts +3 -1
  89. package/dist/agent/worker-agent.d.ts.map +1 -1
  90. package/dist/agent/worker-agent.js +51 -14
  91. package/dist/agent/worker-agent.js.map +1 -1
  92. package/dist/config.d.ts +242 -0
  93. package/dist/config.d.ts.map +1 -1
  94. package/dist/config.js +79 -0
  95. package/dist/config.js.map +1 -1
  96. package/dist/git/git-manager.d.ts +33 -2
  97. package/dist/git/git-manager.d.ts.map +1 -1
  98. package/dist/git/git-manager.js +111 -15
  99. package/dist/git/git-manager.js.map +1 -1
  100. package/dist/git/git-ops.d.ts.map +1 -1
  101. package/dist/git/git-ops.js +2 -1
  102. package/dist/git/git-ops.js.map +1 -1
  103. package/dist/index.js +85 -8
  104. package/dist/index.js.map +1 -1
  105. package/dist/lsp/lsp-manager.js +1 -1
  106. package/dist/lsp/lsp-manager.js.map +1 -1
  107. package/dist/model-outcomes.d.ts.map +1 -1
  108. package/dist/model-outcomes.js +2 -1
  109. package/dist/model-outcomes.js.map +1 -1
  110. package/dist/planner.d.ts +0 -9
  111. package/dist/planner.d.ts.map +1 -1
  112. package/dist/planner.js +0 -9
  113. package/dist/planner.js.map +1 -1
  114. package/dist/project-memory.d.ts +12 -1
  115. package/dist/project-memory.d.ts.map +1 -1
  116. package/dist/project-memory.js +8 -6
  117. package/dist/project-memory.js.map +1 -1
  118. package/dist/runtime/loop-mitigation.d.ts +78 -7
  119. package/dist/runtime/loop-mitigation.d.ts.map +1 -1
  120. package/dist/runtime/loop-mitigation.js +122 -9
  121. package/dist/runtime/loop-mitigation.js.map +1 -1
  122. package/dist/runtime/os-sandbox.d.ts +100 -0
  123. package/dist/runtime/os-sandbox.d.ts.map +1 -0
  124. package/dist/runtime/os-sandbox.js +246 -0
  125. package/dist/runtime/os-sandbox.js.map +1 -0
  126. package/dist/runtime/run-inventory.d.ts +17 -0
  127. package/dist/runtime/run-inventory.d.ts.map +1 -0
  128. package/dist/runtime/run-inventory.js +49 -0
  129. package/dist/runtime/run-inventory.js.map +1 -0
  130. package/dist/runtime/staging.d.ts.map +1 -1
  131. package/dist/runtime/staging.js +4 -1
  132. package/dist/runtime/staging.js.map +1 -1
  133. package/dist/runtime/task-session.d.ts +14 -0
  134. package/dist/runtime/task-session.d.ts.map +1 -1
  135. package/dist/runtime/task-session.js +26 -0
  136. package/dist/runtime/task-session.js.map +1 -1
  137. package/dist/setup-wizard.d.ts +11 -3
  138. package/dist/setup-wizard.d.ts.map +1 -1
  139. package/dist/setup-wizard.js +113 -15
  140. package/dist/setup-wizard.js.map +1 -1
  141. package/dist/types.d.ts +8 -0
  142. package/dist/types.d.ts.map +1 -1
  143. package/dist/ui/commands/context-commands.d.ts +7 -0
  144. package/dist/ui/commands/context-commands.d.ts.map +1 -0
  145. package/dist/ui/commands/context-commands.js +241 -0
  146. package/dist/ui/commands/context-commands.js.map +1 -0
  147. package/dist/ui/commands/index.d.ts +3 -0
  148. package/dist/ui/commands/index.d.ts.map +1 -0
  149. package/dist/ui/commands/index.js +46 -0
  150. package/dist/ui/commands/index.js.map +1 -0
  151. package/dist/ui/commands/info-commands.d.ts +15 -0
  152. package/dist/ui/commands/info-commands.d.ts.map +1 -0
  153. package/dist/ui/commands/info-commands.js +122 -0
  154. package/dist/ui/commands/info-commands.js.map +1 -0
  155. package/dist/ui/commands/model-commands.d.ts +5 -0
  156. package/dist/ui/commands/model-commands.d.ts.map +1 -0
  157. package/dist/ui/commands/model-commands.js +417 -0
  158. package/dist/ui/commands/model-commands.js.map +1 -0
  159. package/dist/ui/commands/session-commands.d.ts +5 -0
  160. package/dist/ui/commands/session-commands.d.ts.map +1 -0
  161. package/dist/ui/commands/session-commands.js +154 -0
  162. package/dist/ui/commands/session-commands.js.map +1 -0
  163. package/dist/ui/commands/task-commands.d.ts +8 -0
  164. package/dist/ui/commands/task-commands.d.ts.map +1 -0
  165. package/dist/ui/commands/task-commands.js +152 -0
  166. package/dist/ui/commands/task-commands.js.map +1 -0
  167. package/dist/ui/commands/types.d.ts +46 -0
  168. package/dist/ui/commands/types.d.ts.map +1 -0
  169. package/dist/ui/commands/types.js +2 -0
  170. package/dist/ui/commands/types.js.map +1 -0
  171. package/dist/ui/commands/workspace-commands.d.ts +8 -0
  172. package/dist/ui/commands/workspace-commands.d.ts.map +1 -0
  173. package/dist/ui/commands/workspace-commands.js +131 -0
  174. package/dist/ui/commands/workspace-commands.js.map +1 -0
  175. package/dist/ui/loading-animation.d.ts +24 -0
  176. package/dist/ui/loading-animation.d.ts.map +1 -0
  177. package/dist/ui/loading-animation.js +123 -0
  178. package/dist/ui/loading-animation.js.map +1 -0
  179. package/dist/ui/markdown-stream.js +2 -2
  180. package/dist/ui/markdown-stream.js.map +1 -1
  181. package/dist/ui/prompt.d.ts +7 -0
  182. package/dist/ui/prompt.d.ts.map +1 -1
  183. package/dist/ui/prompt.js +435 -1214
  184. package/dist/ui/prompt.js.map +1 -1
  185. package/dist/ui/render-primitives.d.ts +6 -0
  186. package/dist/ui/render-primitives.d.ts.map +1 -1
  187. package/dist/ui/render-primitives.js +30 -13
  188. package/dist/ui/render-primitives.js.map +1 -1
  189. package/dist/ui/render.d.ts.map +1 -1
  190. package/dist/ui/render.js +2 -0
  191. package/dist/ui/render.js.map +1 -1
  192. package/package.json +17 -3
  193. package/scripts/check-vendor-wasm.js +11 -0
  194. package/vendor/tree-sitter-go.wasm +0 -0
  195. package/vendor/tree-sitter-javascript.wasm +0 -0
  196. package/vendor/tree-sitter-python.wasm +0 -0
  197. package/vendor/tree-sitter-rust.wasm +0 -0
  198. package/vendor/tree-sitter-tsx.wasm +0 -0
  199. package/vendor/tree-sitter-typescript.wasm +0 -0
package/dist/config.d.ts CHANGED
@@ -1,5 +1,18 @@
1
1
  import type { PolicyProfile } from './runtime/policy.js';
2
2
  export declare const DEFAULT_API_URL = "https://freellm-liart.vercel.app/v1";
3
+ /**
4
+ * How the CLI authenticates against an LLM backend.
5
+ *
6
+ * - `direct` — Requests go straight to a provider (OpenAI, Anthropic,
7
+ * Groq, etc.) using a key the user pasted at setup. Zero
8
+ * traffic to the FreeLLMAPI proxy. This is the default
9
+ * for fresh installs starting with v1.1.
10
+ * - `proxy` — Requests transit the FreeLLMAPI proxy at
11
+ * {@link DEFAULT_API_URL} (or a custom URL). Opt-in
12
+ * convenience for users who want load-balanced failover
13
+ * across free-tier providers without managing keys.
14
+ */
15
+ export type ProviderMode = 'direct' | 'proxy';
3
16
  /** Stream-resume policy. */
4
17
  export type StreamResumePolicy = 'auto' | 'never';
5
18
  /**
@@ -73,6 +86,25 @@ export interface ToolCallBudgetPolicy {
73
86
  }
74
87
  /** Pre-save gate severity. */
75
88
  export type LspPreSaveMode = 'off' | 'warn' | 'block' | 'sandbox-mock';
89
+ /**
90
+ * Sandbox mode for `run_command` execution.
91
+ *
92
+ * - `guard` — Today's behaviour. The in-process command-parser
93
+ * regex layer + WorkspaceGuard path-boundary checks
94
+ * are the only line of defence. Fast, no platform
95
+ * dependencies, no behaviour change.
96
+ * - `os-sandbox` — Opt-in. Wraps every shell command in an
97
+ * OS-enforced sandbox (`sandbox-exec` on macOS,
98
+ * `bwrap` on Linux). Blocks writes outside the
99
+ * workspace + tmpdir even when the regex guard is
100
+ * bypassed by a creative command. Requires the
101
+ * platform binary to be present; surfaces a
102
+ * structured error otherwise rather than silently
103
+ * downgrading to `guard`.
104
+ *
105
+ * Always combined with the regex/guard layer — defence in depth.
106
+ */
107
+ export type SandboxMode = 'guard' | 'os-sandbox';
76
108
  /** Safety preferences — Pillar 1, 2, 3 surface. Pillar 4 lives in the
77
109
  * credential vault module, not in the user-facing config. */
78
110
  export interface SafetyConfig {
@@ -100,6 +132,166 @@ export interface SafetyConfig {
100
132
  predictiveBudgetPct?: number;
101
133
  /** Tool-call budget — see {@link ToolCallBudgetPolicy}. */
102
134
  toolCalls: ToolCallBudgetPolicy;
135
+ /** OS-level sandbox for `run_command`. Defaults to `'guard'`. */
136
+ sandboxMode?: SandboxMode;
137
+ /**
138
+ * Phase 2 — automatic post-edit verification. When `true` (default)
139
+ * AND the run is in BUILD mode AND at least one file-mutating tool
140
+ * was called, the agent runs the project's detected test/typecheck
141
+ * command at the end of the tool loop and — if it fails — pushes a
142
+ * repair-request message back to the model up to
143
+ * {@link autoVerifyMaxRepairs} times before returning.
144
+ *
145
+ * Set to `false` to restore the pre-Phase-2 "trust the model"
146
+ * behaviour. Cheap-to-detect projects (no test/typecheck command in
147
+ * {@link import('./project-memory.js').detectProjectFacts}) silently
148
+ * skip the verifier — there's nothing to run.
149
+ */
150
+ autoVerify?: boolean;
151
+ /**
152
+ * Maximum number of automatic repair turns the verifier may use in
153
+ * one run. The default of 1 was chosen so a long-horizon task gets
154
+ * exactly one self-correction shot — enough to catch obvious type
155
+ * errors without spinning forever on hard failures.
156
+ */
157
+ autoVerifyMaxRepairs?: number;
158
+ }
159
+ /**
160
+ * Phase 5 — Agent Pool tuning surface.
161
+ *
162
+ * Controls the concurrency and per-subtask budget of the orchestrator's
163
+ * parallel worker pool. All defaults match the constants that were
164
+ * hardcoded in `agent-pool.ts` before this namespace existed, so adding
165
+ * the namespace alone is a zero-behavior-change refactor.
166
+ */
167
+ export interface AgentPoolConfig {
168
+ /** Maximum concurrent worker subtasks. Default 3. */
169
+ concurrencyLimit: number;
170
+ /** Tool-call budget per subtask. Default 12 (raised to 40 in Phase 4a). */
171
+ subtaskBudget: number;
172
+ /**
173
+ * When true, successful peer subtasks are committed even if siblings
174
+ * fail (Phase 2). Default false; flipped in Phase 7 after the regression
175
+ * harness validates the partial-commit path.
176
+ */
177
+ preservePartialOnFailure: boolean;
178
+ }
179
+ /**
180
+ * Phase 5 — loop-mitigation policy.
181
+ *
182
+ * The legacy `LoopMitigationTracker` (loop-mitigation.ts) blocks reads
183
+ * on a target permanently once the warn threshold trips. Phase 1b adds a
184
+ * sliding-window alternative; this config selects between them.
185
+ */
186
+ export interface AgentLoopGuardConfig {
187
+ /**
188
+ * When true, block accounting uses a sliding window of tool calls
189
+ * instead of session-lifetime lockout. Default false in phase 1b;
190
+ * flipped to true in Phase 7 after soak.
191
+ */
192
+ useSlidingWindow: boolean;
193
+ /** Sliding-window size in tool calls. Default 10. Ignored when sliding is off. */
194
+ blockWindowTurns: number;
195
+ /**
196
+ * When true, the loop-mitigation tracker is reset between orchestrator
197
+ * subtasks so one stuck subtask cannot poison the rest of the run.
198
+ * Default true.
199
+ */
200
+ blockResetOnSubtask: boolean;
201
+ }
202
+ /**
203
+ * Phase 5 — routing-honor policy.
204
+ *
205
+ * The router currently surfaces a "model unverified for autonomous DAG
206
+ * execution" warning but routes to the Orchestrator anyway. Phase 6
207
+ * makes the warning actionable.
208
+ */
209
+ export interface AgentRoutingConfig {
210
+ /**
211
+ * When true, Complex-classified tasks on models NOT in the
212
+ * verified-DAG list are routed to SingleAgent. Default false in
213
+ * Phase 0; flipped to true in Phase 6.
214
+ */
215
+ honorVerificationFlag: boolean;
216
+ /**
217
+ * Override that permits unverified-model DAG execution even when
218
+ * `honorVerificationFlag` is true. For power users who explicitly
219
+ * accept the risk. Default false.
220
+ */
221
+ allowUnverifiedDag: boolean;
222
+ }
223
+ /**
224
+ * Phase 5.3 — DAG-level conflict policy.
225
+ *
226
+ * The orchestrator currently parallelizes any subtasks that don't
227
+ * declare a dependency on each other. This causes write-conflicts
228
+ * when the LLM emits multiple subtasks targeting the same file (the
229
+ * "3 workers all writing style.css" race observed in the log).
230
+ *
231
+ * `serializeWriteConflicts`, when true, runs a post-pass on the
232
+ * generated DAG that injects dependency edges whenever two subtasks
233
+ * could write to overlapping files. Default true since the
234
+ * alternative is observed-broken; flag exists so users can opt out
235
+ * for benchmarks or future verified orchestrators.
236
+ *
237
+ * `serializeMissingFiles` extends the same policy to subtasks that
238
+ * declared no files at all (LLMs often omit). Conservative default
239
+ * trades parallelism for correctness — over-serialization is the
240
+ * worst case.
241
+ */
242
+ export interface AgentDagConfig {
243
+ serializeWriteConflicts: boolean;
244
+ serializeMissingFiles: boolean;
245
+ }
246
+ export interface AgentConfig {
247
+ pool: AgentPoolConfig;
248
+ loopGuard: AgentLoopGuardConfig;
249
+ routing: AgentRoutingConfig;
250
+ dag: AgentDagConfig;
251
+ }
252
+ /**
253
+ * Phase 3.3 — repo-map scan caps.
254
+ *
255
+ * Controls how aggressively `buildRepoMap` walks the workspace.
256
+ * Both fields are optional; defaults track the pre-Phase-3.3
257
+ * constants (depth 4, 200 files) so existing users see no
258
+ * behaviour change. Increase these on large repos where the
259
+ * default cap truncates important directories.
260
+ */
261
+ export interface RepoMapConfig {
262
+ /** Maximum recursion depth. Default 4. */
263
+ maxDepth?: number;
264
+ /** Maximum files per directory. Default 200. */
265
+ maxFiles?: number;
266
+ }
267
+ /**
268
+ * Phase 2.4 — local fast/heavy-tier model substitution.
269
+ *
270
+ * When a code path tags its request with `required_capabilities`,
271
+ * the client looks up the corresponding tier in this table and
272
+ * substitutes the locally-configured model BEFORE issuing the
273
+ * request. Works in both direct and proxy modes — direct sends the
274
+ * substituted model to the provider; proxy still sees the
275
+ * substitution as well as the legacy metadata headers.
276
+ *
277
+ * Per-tier semantics:
278
+ * - `fast` — used for planner classification, complexity
279
+ * routing, summary turns. Optimise for latency
280
+ * + cost; quality is less important.
281
+ * - `heavy` — used for the orchestrator's plan() and any
282
+ * call that asks for `'heavy'`. Optimise for
283
+ * quality.
284
+ * - `default` — fallback when a request asks for a capability
285
+ * the user hasn't configured; equivalent to
286
+ * not substituting at all.
287
+ *
288
+ * All three fields are optional. When a tier is unset, the
289
+ * client falls through to the model the caller passed.
290
+ */
291
+ export interface ModelRoutingConfig {
292
+ fast?: string;
293
+ default?: string;
294
+ heavy?: string;
103
295
  }
104
296
  /** Resilience preferences for the new withRetry + chatStreamWithResume paths. */
105
297
  export interface ResilienceConfig {
@@ -128,9 +320,33 @@ export interface ResilienceConfig {
128
320
  * Persisted at `~/.fixocli/config.json`.
129
321
  */
130
322
  export interface FreeLLMConfig {
323
+ /**
324
+ * Authentication mode. New installs default to `'direct'`. Existing
325
+ * configs that predate this field are inferred at load time:
326
+ * presence of `freellmapi_api_key` means `'proxy'`, absence means
327
+ * `'direct'`. Never undefined after {@link loadConfig} returns.
328
+ */
329
+ provider_mode: ProviderMode;
330
+ /**
331
+ * When `provider_mode === 'direct'`, identifies the provider the
332
+ * user selected at setup time and the default model to use for new
333
+ * sessions. The actual API key lives in the providers store
334
+ * (`~/.fixocli/providers.json`) and the in-memory credential vault,
335
+ * never here.
336
+ */
337
+ directProvider?: {
338
+ name: string;
339
+ defaultModel: string;
340
+ };
131
341
  freellmapi_api_key?: string;
132
342
  apiUrl?: string;
133
343
  defaultModel: string;
344
+ /** Persisted across launches so the next boot auto-reconnects. */
345
+ lastSession?: {
346
+ provider: string;
347
+ model: string;
348
+ updatedAt: string;
349
+ };
134
350
  preferences: {
135
351
  autoCommit: boolean;
136
352
  streaming: boolean;
@@ -165,6 +381,22 @@ export interface FreeLLMConfig {
165
381
  * is a programmatic-only surface and is not user-configurable.
166
382
  */
167
383
  safety: SafetyConfig;
384
+ /**
385
+ * Phase 2.4 — per-capability model substitution. Optional. See
386
+ * {@link ModelRoutingConfig}.
387
+ */
388
+ modelRouting?: ModelRoutingConfig;
389
+ /**
390
+ * Phase 3.3 — repo-map walk caps. Optional. See
391
+ * {@link RepoMapConfig}.
392
+ */
393
+ repoMap?: RepoMapConfig;
394
+ /**
395
+ * Phase 5 — Agent subsystem tunables (pool, loop guard, routing).
396
+ * Optional. Missing fields fall through to the defaults in
397
+ * {@link getDefaultConfig}. See {@link AgentConfig}.
398
+ */
399
+ agent?: AgentConfig;
168
400
  };
169
401
  _firstRunComplete: boolean;
170
402
  }
@@ -182,6 +414,16 @@ export declare function getDefaultConfig(): FreeLLMConfig;
182
414
  * instead — the caller can then decide whether to run the setup wizard.
183
415
  */
184
416
  export declare function loadConfig(): FreeLLMConfig;
417
+ /**
418
+ * Returns the resolved {@link AgentConfig} from the loaded config.
419
+ * Guaranteed non-null — falls back to defaults for old configs that
420
+ * predate this namespace.
421
+ */
422
+ export declare function getAgentConfig(config?: FreeLLMConfig): AgentConfig;
423
+ export declare function getAgentPoolConfig(config?: FreeLLMConfig): AgentPoolConfig;
424
+ export declare function getAgentLoopGuardConfig(config?: FreeLLMConfig): AgentLoopGuardConfig;
425
+ export declare function getAgentRoutingConfig(config?: FreeLLMConfig): AgentRoutingConfig;
426
+ export declare function getAgentDagConfig(config?: FreeLLMConfig): AgentDagConfig;
185
427
  /**
186
428
  * Persists the given config to `~/.fixocli/config.json`.
187
429
  * Creates the config directory if it doesn't already exist.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/config.js CHANGED
@@ -23,6 +23,7 @@ export function getHistoryPath() {
23
23
  /** Returns a complete default configuration object. */
24
24
  export function getDefaultConfig() {
25
25
  return {
26
+ provider_mode: 'direct',
26
27
  defaultModel: 'auto',
27
28
  preferences: {
28
29
  autoCommit: false,
@@ -65,6 +66,29 @@ export function getDefaultConfig() {
65
66
  autoExtend: true,
66
67
  investigationMultiplier: 3,
67
68
  },
69
+ sandboxMode: 'guard',
70
+ autoVerify: true,
71
+ autoVerifyMaxRepairs: 1,
72
+ },
73
+ agent: {
74
+ pool: {
75
+ concurrencyLimit: 3,
76
+ subtaskBudget: 12,
77
+ preservePartialOnFailure: true,
78
+ },
79
+ loopGuard: {
80
+ useSlidingWindow: true,
81
+ blockWindowTurns: 10,
82
+ blockResetOnSubtask: true,
83
+ },
84
+ routing: {
85
+ honorVerificationFlag: true,
86
+ allowUnverifiedDag: false,
87
+ },
88
+ dag: {
89
+ serializeWriteConflicts: true,
90
+ serializeMissingFiles: true,
91
+ },
68
92
  },
69
93
  },
70
94
  _firstRunComplete: false,
@@ -91,9 +115,20 @@ export function loadConfig() {
91
115
  const parsedSemanticLoopTrap = parsedSafety
92
116
  .semanticLoopTrap ?? {};
93
117
  const parsedToolCalls = parsedSafety.toolCalls ?? {};
118
+ const parsedAgent = parsedPreferences.agent ?? {};
119
+ const parsedAgentPool = parsedAgent.pool ?? {};
120
+ const parsedAgentLoopGuard = parsedAgent.loopGuard ?? {};
121
+ const parsedAgentRouting = parsedAgent.routing ?? {};
122
+ const parsedAgentDag = parsedAgent.dag ?? {};
123
+ // Back-compat: existing configs predating v1.1 don't have
124
+ // `provider_mode`. If they have a FreeLLMAPI key they were
125
+ // implicitly proxy users; otherwise they're either fresh or
126
+ // explicitly direct. Never silently flip an existing user.
127
+ const inferredMode = parsed.provider_mode ?? (parsed.freellmapi_api_key ? 'proxy' : 'direct');
94
128
  return {
95
129
  ...defaults,
96
130
  ...parsed,
131
+ provider_mode: inferredMode,
97
132
  preferences: {
98
133
  ...defaults.preferences,
99
134
  ...parsedPreferences,
@@ -117,6 +152,24 @@ export function loadConfig() {
117
152
  ...parsedToolCalls,
118
153
  },
119
154
  },
155
+ agent: {
156
+ pool: {
157
+ ...defaults.preferences.agent.pool,
158
+ ...parsedAgentPool,
159
+ },
160
+ loopGuard: {
161
+ ...defaults.preferences.agent.loopGuard,
162
+ ...parsedAgentLoopGuard,
163
+ },
164
+ routing: {
165
+ ...defaults.preferences.agent.routing,
166
+ ...parsedAgentRouting,
167
+ },
168
+ dag: {
169
+ ...defaults.preferences.agent.dag,
170
+ ...parsedAgentDag,
171
+ },
172
+ },
120
173
  },
121
174
  };
122
175
  }
@@ -125,6 +178,32 @@ export function loadConfig() {
125
178
  return getDefaultConfig();
126
179
  }
127
180
  }
181
+ // ---------------------------------------------------------------------------
182
+ // Agent subsystem helpers (Phase 5 — see AgentConfig)
183
+ // ---------------------------------------------------------------------------
184
+ /**
185
+ * Returns the resolved {@link AgentConfig} from the loaded config.
186
+ * Guaranteed non-null — falls back to defaults for old configs that
187
+ * predate this namespace.
188
+ */
189
+ export function getAgentConfig(config) {
190
+ const cfg = config ?? loadConfig();
191
+ if (cfg.preferences.agent)
192
+ return cfg.preferences.agent;
193
+ return getDefaultConfig().preferences.agent;
194
+ }
195
+ export function getAgentPoolConfig(config) {
196
+ return getAgentConfig(config).pool;
197
+ }
198
+ export function getAgentLoopGuardConfig(config) {
199
+ return getAgentConfig(config).loopGuard;
200
+ }
201
+ export function getAgentRoutingConfig(config) {
202
+ return getAgentConfig(config).routing;
203
+ }
204
+ export function getAgentDagConfig(config) {
205
+ return getAgentConfig(config).dag;
206
+ }
128
207
  /**
129
208
  * Persists the given config to `~/.fixocli/config.json`.
130
209
  * Creates the config directory if it doesn't already exist.
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -21,8 +21,39 @@ export declare class GitManager {
21
21
  undoLastCommit(): boolean;
22
22
  /** Get last N commit messages for display. */
23
23
  getRecentCommits(count?: number): string;
24
- /** Discard all uncommitted modifications and untracked files in the workspace. */
25
- discardUncommittedChanges(): void;
24
+ /**
25
+ * Discard the agent's edits to a specific set of files only.
26
+ *
27
+ * Background: an earlier version exposed a `discardUncommittedChanges()`
28
+ * method that ran `git checkout -- .` followed by `git clean -fd`,
29
+ * unconditionally wiping every uncommitted change in the workspace —
30
+ * including pre-existing user work the agent never touched. The
31
+ * orchestrator's failure-rollback path called it on any error, which
32
+ * meant a *read-only* task failing on a tool-call budget could
33
+ * destroy hours of unrelated in-progress work. That method has been
34
+ * removed. Callers must now name the files they want to roll back.
35
+ *
36
+ * For tracked files in `files`, the change is reverted to the
37
+ * `HEAD` revision. For untracked files in `files` (i.e. new files
38
+ * the agent created during the run), the file is unlinked. Files
39
+ * NOT in `files` are left completely alone — including any other
40
+ * uncommitted user work.
41
+ *
42
+ * Passing an empty list is a no-op.
43
+ *
44
+ * @param files Absolute or workspace-relative paths the run actually modified.
45
+ */
46
+ discardChangesIn(files: string[]): void;
47
+ /**
48
+ * Escape hatch — full workspace wipe (`git checkout -- .` + `git clean -fd`).
49
+ * Removed from any agent-driven path; intentionally kept here for
50
+ * the rare case where a user explicitly chooses to discard
51
+ * everything from a slash command. Callers must pass
52
+ * `{ iAmCertain: true }` to spell out the intent.
53
+ */
54
+ forceDiscardAllUncommittedChanges(opts: {
55
+ iAmCertain: true;
56
+ }): void;
26
57
  /**
27
58
  * Create a named workspace snapshot commit (works in non-auto-commit mode).
28
59
  * Stages all changes and commits with "fixo-snapshot: <label>" message.
@@ -1 +1 @@
1
- {"version":3,"file":"git-manager.d.ts","sourceRoot":"","sources":["../../src/git/git-manager.ts"],"names":[],"mappings":"AAsBA,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,KAAK,CAAiB;gBAElB,GAAG,EAAE,MAAM;IAKvB,iEAAiE;IACjE,SAAS,IAAI,OAAO;IAapB,mCAAmC;IACnC,gBAAgB,IAAI,MAAM;IAY1B,8CAA8C;IAC9C,UAAU,IAAI,OAAO;IAarB,qFAAqF;IACrF,aAAa,IAAI,MAAM,EAAE;IAuBzB,8CAA8C;IAC9C,OAAO,IAAI,MAAM;IA8CjB;;;OAGG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI;IAkEhE,yEAAyE;IACzE,cAAc,IAAI,OAAO;IAsCzB,8CAA8C;IAC9C,gBAAgB,CAAC,KAAK,SAAI,GAAG,MAAM;IAWnC,kFAAkF;IAClF,yBAAyB,IAAI,IAAI;IAWjC;;;;OAIG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAgC7C"}
1
+ {"version":3,"file":"git-manager.d.ts","sourceRoot":"","sources":["../../src/git/git-manager.ts"],"names":[],"mappings":"AAwBA,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,KAAK,CAAiB;gBAElB,GAAG,EAAE,MAAM;IAKvB,iEAAiE;IACjE,SAAS,IAAI,OAAO;IAapB,mCAAmC;IACnC,gBAAgB,IAAI,MAAM;IAY1B,8CAA8C;IAC9C,UAAU,IAAI,OAAO;IAarB,qFAAqF;IACrF,aAAa,IAAI,MAAM,EAAE;IA8BzB,8CAA8C;IAC9C,OAAO,IAAI,MAAM;IA8CjB;;;OAGG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI;IAkEhE,yEAAyE;IACzE,cAAc,IAAI,OAAO;IAsCzB,8CAA8C;IAC9C,gBAAgB,CAAC,KAAK,SAAI,GAAG,MAAM;IAWnC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAiDvC;;;;;;OAMG;IACH,iCAAiC,CAAC,IAAI,EAAE;QAAE,UAAU,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI;IAanE;;;;OAIG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAiC7C"}
@@ -3,6 +3,8 @@
3
3
  * All git operations are safely sandboxed to the workspace directory.
4
4
  */
5
5
  import { execFileSync } from 'child_process';
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
6
8
  import { WorkspaceGuard } from '../workspace-guard.js';
7
9
  import { C } from '../ui/colors.js';
8
10
  /* ──────────────────────── ANSI Colors ──────────────────────── */
@@ -69,21 +71,27 @@ export class GitManager {
69
71
  if (!this.isGitRepo())
70
72
  return [];
71
73
  try {
72
- const output = execFileSync('git', ['status', '--porcelain'], {
74
+ const output = execFileSync('git', ['status', '--porcelain', '-z'], {
73
75
  cwd: this.cwd,
74
76
  encoding: 'utf-8',
75
77
  stdio: ['pipe', 'pipe', 'pipe'],
76
78
  });
77
- return output.split('\n')
78
- .map(line => line.trim())
79
- .filter(line => line.length > 0)
80
- .map(line => {
81
- let p = line.slice(2).trim();
82
- if (p.startsWith('"') && p.endsWith('"')) {
83
- p = p.slice(1, -1).replace(/\\"/g, '"');
79
+ if (!output)
80
+ return [];
81
+ const files = [];
82
+ const parts = output.split('\0');
83
+ for (let i = 0; i < parts.length; i++) {
84
+ const part = parts[i];
85
+ if (!part)
86
+ continue;
87
+ const xy = part.slice(0, 2);
88
+ files.push(part.slice(3));
89
+ // If it's a rename (R) or copy (C), skip the old path that follows
90
+ if (xy[0] === 'R' || xy[0] === 'C') {
91
+ i++;
84
92
  }
85
- return p;
86
- });
93
+ }
94
+ return files;
87
95
  }
88
96
  catch {
89
97
  return [];
@@ -242,17 +250,104 @@ export class GitManager {
242
250
  return '(no commits)';
243
251
  }
244
252
  }
245
- /** Discard all uncommitted modifications and untracked files in the workspace. */
246
- discardUncommittedChanges() {
253
+ /**
254
+ * Discard the agent's edits to a specific set of files only.
255
+ *
256
+ * Background: an earlier version exposed a `discardUncommittedChanges()`
257
+ * method that ran `git checkout -- .` followed by `git clean -fd`,
258
+ * unconditionally wiping every uncommitted change in the workspace —
259
+ * including pre-existing user work the agent never touched. The
260
+ * orchestrator's failure-rollback path called it on any error, which
261
+ * meant a *read-only* task failing on a tool-call budget could
262
+ * destroy hours of unrelated in-progress work. That method has been
263
+ * removed. Callers must now name the files they want to roll back.
264
+ *
265
+ * For tracked files in `files`, the change is reverted to the
266
+ * `HEAD` revision. For untracked files in `files` (i.e. new files
267
+ * the agent created during the run), the file is unlinked. Files
268
+ * NOT in `files` are left completely alone — including any other
269
+ * uncommitted user work.
270
+ *
271
+ * Passing an empty list is a no-op.
272
+ *
273
+ * @param files Absolute or workspace-relative paths the run actually modified.
274
+ */
275
+ discardChangesIn(files) {
276
+ if (!this.isGitRepo())
277
+ return;
278
+ if (files.length === 0) {
279
+ console.log(`${colors.dim} ⏪ Rollback: nothing to discard (0 files reported).${colors.reset}`);
280
+ return;
281
+ }
282
+ const relativeFiles = files.map((f) => path.isAbsolute(f) ? path.relative(this.cwd, f) : f);
283
+ const tracked = [];
284
+ const untracked = [];
285
+ try {
286
+ for (const rel of relativeFiles) {
287
+ let status = '';
288
+ try {
289
+ status = execFileSync('git', ['status', '--porcelain', '-z', '--', rel], {
290
+ cwd: this.cwd,
291
+ encoding: 'utf-8',
292
+ stdio: ['pipe', 'pipe', 'pipe'],
293
+ });
294
+ }
295
+ catch {
296
+ // safe: file may have been deleted mid-run; treat as no-op
297
+ continue;
298
+ }
299
+ if (!status)
300
+ continue; // file is clean — nothing to roll back
301
+ if (status.startsWith('??'))
302
+ untracked.push(rel);
303
+ else
304
+ tracked.push(rel);
305
+ }
306
+ if (tracked.length > 0) {
307
+ execFileSync('git', ['checkout', 'HEAD', '--', ...tracked], {
308
+ cwd: this.cwd,
309
+ stdio: ['pipe', 'pipe', 'pipe'],
310
+ });
311
+ }
312
+ for (const rel of untracked) {
313
+ try {
314
+ fs.unlinkSync(path.join(this.cwd, rel));
315
+ }
316
+ catch { /* safe: best-effort */ }
317
+ }
318
+ const total = tracked.length + untracked.length;
319
+ if (total > 0) {
320
+ console.log(`${colors.green} ⏪ Rolled back ${tracked.length} modified + ${untracked.length} new file(s) the agent touched.${colors.reset}`);
321
+ }
322
+ else {
323
+ console.log(`${colors.dim} ⏪ Rollback: agent-touched files were already clean.${colors.reset}`);
324
+ }
325
+ }
326
+ catch (error) {
327
+ const msg = error instanceof Error ? error.message : String(error);
328
+ console.log(`${colors.yellow} ⚠ Failed to discard targeted changes: ${msg}${colors.reset}`);
329
+ }
330
+ }
331
+ /**
332
+ * Escape hatch — full workspace wipe (`git checkout -- .` + `git clean -fd`).
333
+ * Removed from any agent-driven path; intentionally kept here for
334
+ * the rare case where a user explicitly chooses to discard
335
+ * everything from a slash command. Callers must pass
336
+ * `{ iAmCertain: true }` to spell out the intent.
337
+ */
338
+ forceDiscardAllUncommittedChanges(opts) {
339
+ if (!opts.iAmCertain)
340
+ return;
247
341
  if (!this.isGitRepo())
248
342
  return;
249
343
  try {
250
344
  execFileSync('git', ['checkout', '--', '.'], { cwd: this.cwd, stdio: ['pipe', 'pipe', 'pipe'] });
251
345
  execFileSync('git', ['clean', '-fd'], { cwd: this.cwd, stdio: ['pipe', 'pipe', 'pipe'] });
252
- console.log(`${colors.green} ⏪ Discarded all uncommitted workspace changes due to execution failure.${colors.reset}`);
346
+ console.log(`${colors.green} ⏪ Discarded ALL uncommitted workspace changes (explicit user request).${colors.reset}`);
253
347
  }
254
348
  catch (error) {
255
- console.log(`${colors.yellow} ⚠ Failed to discard uncommitted changes: ${error.message || error}${colors.reset}`);
349
+ const msg = error instanceof Error ? error.message : String(error);
350
+ console.log(`${colors.yellow} ⚠ Failed to discard uncommitted changes: ${msg}${colors.reset}`);
256
351
  }
257
352
  }
258
353
  /**
@@ -285,7 +380,8 @@ export class GitManager {
285
380
  return hash;
286
381
  }
287
382
  catch (error) {
288
- console.log(`${colors.yellow} ⚠ Snapshot failed: ${(error.message || String(error)).slice(0, 80)}${colors.reset}`);
383
+ const msg = error instanceof Error ? error.message : String(error);
384
+ console.log(`${colors.yellow} ⚠ Snapshot failed: ${msg.slice(0, 80)}${colors.reset}`);
289
385
  return null;
290
386
  }
291
387
  }