howtofixcli 0.7.24 → 0.7.26

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 (167) hide show
  1. package/dist/account-credential.js +136 -0
  2. package/dist/acp.js +234 -0
  3. package/dist/activity.js +124 -0
  4. package/dist/agent-defs.js +237 -0
  5. package/dist/agent-limiter.js +68 -0
  6. package/dist/agents.js +554 -0
  7. package/dist/anim.js +361 -0
  8. package/dist/args.js +250 -0
  9. package/dist/at-file.js +28 -0
  10. package/dist/brand-extension.js +87 -0
  11. package/dist/brand.js +76 -0
  12. package/dist/browser.js +58 -0
  13. package/dist/cache-report.js +139 -0
  14. package/dist/checkpoint.js +437 -0
  15. package/dist/claims.js +167 -0
  16. package/dist/cli-auth.js +142 -0
  17. package/dist/cli-checkin.js +121 -0
  18. package/dist/cli-credentials.js +254 -0
  19. package/dist/clipboard.js +149 -0
  20. package/dist/collapse.js +129 -0
  21. package/dist/commands.js +381 -0
  22. package/dist/compaction-guard.js +81 -0
  23. package/dist/connect-prompt.js +22 -0
  24. package/dist/context-extension.js +17 -0
  25. package/dist/dcp/commands.js +172 -0
  26. package/dist/dcp/compress-state.js +139 -0
  27. package/dist/dcp/compress.js +329 -0
  28. package/dist/dcp/dcp-extension.js +295 -0
  29. package/dist/dcp/dedup.js +93 -0
  30. package/dist/dcp/ids.js +189 -0
  31. package/dist/dcp/index.js +25 -0
  32. package/dist/dcp/middle-prune.js +76 -0
  33. package/dist/dcp/prompts.js +68 -0
  34. package/dist/dcp/protected-content.js +221 -0
  35. package/dist/dcp/protected.js +161 -0
  36. package/dist/dcp/prune.js +418 -0
  37. package/dist/dcp/state.js +176 -0
  38. package/dist/errors.js +63 -0
  39. package/dist/extensions.js +48 -0
  40. package/dist/fatal.js +35 -0
  41. package/dist/feed.js +498 -0
  42. package/dist/fs-atomic.js +54 -0
  43. package/dist/gateway-errors.js +107 -0
  44. package/dist/git.js +230 -0
  45. package/dist/goal-extension.js +88 -0
  46. package/dist/goal.js +222 -0
  47. package/dist/hooks-extension.js +176 -0
  48. package/dist/hooks.js +443 -0
  49. package/dist/howtofix-account.js +834 -0
  50. package/dist/hud-line.js +158 -0
  51. package/dist/hwid.js +130 -0
  52. package/dist/interrupt.js +60 -0
  53. package/dist/json-events.js +50 -0
  54. package/dist/level-style.js +112 -0
  55. package/dist/loop-guard.js +95 -0
  56. package/dist/lsp-tools.js +32 -0
  57. package/dist/lsp.js +429 -0
  58. package/dist/main.js +573 -98
  59. package/dist/mcp-config.js +85 -0
  60. package/dist/mcp-lifecycle.js +147 -0
  61. package/dist/model-catalog.js +217 -0
  62. package/dist/model-facts.js +35 -0
  63. package/dist/model-resolve.js +65 -0
  64. package/dist/notes.js +78 -0
  65. package/dist/oauth-login.js +568 -0
  66. package/dist/paths.js +61 -0
  67. package/dist/permissions.js +298 -0
  68. package/dist/plan-mode.js +363 -0
  69. package/dist/preset-command.js +227 -0
  70. package/dist/preset-extension.js +35 -0
  71. package/dist/preset-mcp.js +292 -0
  72. package/dist/presets/mcp/rea/preset.json +28 -0
  73. package/dist/presets/mcp/rea/prompt.md +5 -0
  74. package/dist/presets/mcp/rea/skills/mcp-rea/SKILL.md +6 -0
  75. package/dist/presets/mcp/remotion/preset.json +27 -0
  76. package/dist/presets/mcp/remotion/prompt.md +7 -0
  77. package/dist/presets/mcp/remotion/skills/mcp-remotion/SKILL.md +6 -0
  78. package/dist/presets.js +727 -0
  79. package/dist/prompt-files.js +103 -0
  80. package/dist/prompt-text.js +41 -0
  81. package/dist/proxy.js +137 -0
  82. package/dist/quality/ast.js +196 -0
  83. package/dist/quality/cognitive.js +83 -0
  84. package/dist/quality/cyclomatic.js +30 -0
  85. package/dist/quality/halstead.js +83 -0
  86. package/dist/quality/index.js +18 -0
  87. package/dist/quality/length.js +3 -0
  88. package/dist/quality/maintainability.js +15 -0
  89. package/dist/quality/nesting.js +57 -0
  90. package/dist/quality/report.js +803 -0
  91. package/dist/quality/smells.js +67 -0
  92. package/dist/quality-tool.js +63 -0
  93. package/dist/read-only-commands.js +597 -0
  94. package/dist/repo-map.js +292 -0
  95. package/dist/roblox-connect.js +125 -0
  96. package/dist/rpc.js +91 -0
  97. package/dist/rtk.js +193 -0
  98. package/dist/sandbox.js +105 -0
  99. package/dist/schema.js +214 -0
  100. package/dist/serve.js +50 -0
  101. package/dist/session-lifecycle.js +19 -0
  102. package/dist/session-retention.js +111 -0
  103. package/dist/session.js +460 -0
  104. package/dist/sessions.js +100 -0
  105. package/dist/settings.js +148 -0
  106. package/dist/skills.js +35 -0
  107. package/dist/slop-tool.js +96 -0
  108. package/dist/spend-cap.js +43 -0
  109. package/dist/subagent.js +171 -0
  110. package/dist/tar.js +146 -0
  111. package/dist/theme.js +79 -0
  112. package/dist/thinking.js +45 -0
  113. package/dist/todo.js +114 -0
  114. package/dist/tool-loadout.js +102 -0
  115. package/dist/tool-render.js +769 -0
  116. package/dist/tools.js +176 -0
  117. package/dist/ui.js +4931 -0
  118. package/dist/update.js +551 -0
  119. package/dist/usage-segment.js +74 -0
  120. package/dist/web-tools.js +46 -0
  121. package/dist/web.js +265 -0
  122. package/dist/welcome.js +179 -0
  123. package/dist/workflow-engine.js +246 -0
  124. package/dist/workflow-progress.js +446 -0
  125. package/dist/workflow-view.js +195 -0
  126. package/dist/workflow.js +349 -0
  127. package/package.json +62 -15
  128. package/dist/chunk-27TRKD65.js +0 -2
  129. package/dist/chunk-3FYCFLNK.js +0 -1
  130. package/dist/chunk-3LZR7OEU.js +0 -1
  131. package/dist/chunk-56SEAGAQ.js +0 -1
  132. package/dist/chunk-5AWTL34S.js +0 -1
  133. package/dist/chunk-75P2SCOT.js +0 -1
  134. package/dist/chunk-7CHDNTH6.js +0 -1
  135. package/dist/chunk-7PHRNXLN.js +0 -34
  136. package/dist/chunk-AGGIYXN7.js +0 -2
  137. package/dist/chunk-AUDMRGWF.js +0 -189
  138. package/dist/chunk-C5E3SFOQ.js +0 -2
  139. package/dist/chunk-CMTKCUL5.js +0 -1
  140. package/dist/chunk-DAPXGSGD.js +0 -12
  141. package/dist/chunk-DOD7MUGX.js +0 -1
  142. package/dist/chunk-FPXVDP32.js +0 -8
  143. package/dist/chunk-GXB7RZHH.js +0 -1
  144. package/dist/chunk-I7KVLBMF.js +0 -2
  145. package/dist/chunk-ILDDDLRC.js +0 -1
  146. package/dist/chunk-JFYVRWJI.js +0 -2
  147. package/dist/chunk-LAHVHRCS.js +0 -2
  148. package/dist/chunk-LSJC73DG.js +0 -1
  149. package/dist/chunk-MNDKS6UH.js +0 -6
  150. package/dist/chunk-N345KWWK.js +0 -1
  151. package/dist/chunk-N3J2J7EQ.js +0 -5
  152. package/dist/chunk-ONZLNFQ2.js +0 -3
  153. package/dist/chunk-ORJ2QZBG.js +0 -3
  154. package/dist/chunk-PCALBZOO.js +0 -2
  155. package/dist/chunk-QPHSHL7H.js +0 -2
  156. package/dist/chunk-TKROS3BE.js +0 -5
  157. package/dist/chunk-TSEKPGK4.js +0 -1
  158. package/dist/chunk-UP7ENLEL.js +0 -117
  159. package/dist/chunk-UTYFLLSM.js +0 -1
  160. package/dist/chunk-V3R4FYTJ.js +0 -1
  161. package/dist/chunk-V656XVXV.js +0 -8
  162. package/dist/chunk-WKUJ7CFO.js +0 -1
  163. package/dist/chunk-WOT6VMZA.js +0 -1
  164. package/dist/chunk-WUPU6LTD.js +0 -4
  165. package/dist/chunk-WX3V5P7U.js +0 -5
  166. package/dist/chunk-XW6LMQGX.js +0 -1
  167. package/dist/chunk-YW7NORH3.js +0 -2
@@ -0,0 +1,246 @@
1
+ import { acquireAgentSlot } from "./agent-limiter.js";
2
+ export const LIFETIME_CAP = 1000;
3
+ export const FANOUT_CAP = 4096;
4
+ /** How often a paused run re-checks for resume. */
5
+ export const PAUSE_POLL_MS = 100;
6
+ /** Ceiling on a pause, so a forgotten pause cannot hang the run forever. */
7
+ export const PAUSE_MAX_MS = 5 * 60 * 1000;
8
+ /**
9
+ * Hold until the run is resumed, or give up after {@link PAUSE_MAX_MS}.
10
+ *
11
+ * Resolves `true` to continue and `false` when the wait ran out — the caller
12
+ * then resolves that one call as `null`, which is the engine's normal way of
13
+ * saying "this agent produced nothing". A pause is therefore visible in the
14
+ * results instead of silently vanishing.
15
+ */
16
+ export async function waitForResume(options, pollMs = PAUSE_POLL_MS, maxMs = PAUSE_MAX_MS) {
17
+ const deadline = Date.now() + maxMs;
18
+ while (options.isPaused?.()) {
19
+ if (options.signal?.aborted)
20
+ return false;
21
+ if (Date.now() >= deadline)
22
+ return false;
23
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
24
+ }
25
+ return true;
26
+ }
27
+ /** Thrown for the three conditions that must not be swallowed by a script. */
28
+ export class WorkflowError extends Error {
29
+ constructor(message) {
30
+ super(message);
31
+ this.name = "WorkflowError";
32
+ }
33
+ }
34
+ /** A FIFO semaphore, so `parallel()` fans out up to `limit` and queues the rest. */
35
+ function createSemaphore(limit) {
36
+ let active = 0;
37
+ const waiting = [];
38
+ return async function acquire() {
39
+ if (active >= limit)
40
+ await new Promise((resolve) => waiting.push(resolve));
41
+ active++;
42
+ let released = false;
43
+ return () => {
44
+ if (released)
45
+ return;
46
+ released = true;
47
+ active--;
48
+ waiting.shift()?.();
49
+ };
50
+ };
51
+ }
52
+ /**
53
+ * Build the bindings for one run.
54
+ *
55
+ * Every agent call goes through {@link createBindings}'s `runAgent`, which owns
56
+ * the counters, the semaphore and the budget check — so no binding can bypass
57
+ * the caps.
58
+ */
59
+ export function createBindings(options) {
60
+ const lifetimeCap = options.lifetimeCap ?? LIFETIME_CAP;
61
+ const fanoutCap = options.fanoutCap ?? FANOUT_CAP;
62
+ // The width is the shared limiter's, so a `task` call running at the same time
63
+ // is counted against the same budget. `concurrency` remains for a script that
64
+ // wants fewer in flight than the machine allows.
65
+ const local = options.concurrency ? createSemaphore(options.concurrency) : null;
66
+ const acquire = async () => {
67
+ const releaseShared = await acquireAgentSlot();
68
+ if (!local)
69
+ return releaseShared;
70
+ const releaseLocal = await local();
71
+ return () => {
72
+ releaseLocal();
73
+ releaseShared();
74
+ };
75
+ };
76
+ let calls = 0;
77
+ let spent = 0;
78
+ let currentPhase = "";
79
+ const emit = (event) => options.onEvent?.(event);
80
+ // Live snapshots, keyed by call so a repair turn updates the same entry rather
81
+ // than adding a second one for what the user sees as one agent.
82
+ const snapshots = new Map();
83
+ const publish = () => options.onProgress?.([...snapshots.values()]);
84
+ const runAgent = async (prompt, opts) => {
85
+ const spec = opts ?? {};
86
+ const label = typeof spec.label === "string" ? spec.label : `agent-${calls + 1}`;
87
+ const phase = typeof spec.phase === "string" ? spec.phase : currentPhase;
88
+ const agentType = typeof spec.agentType === "string" ? spec.agentType : "task";
89
+ const effort = typeof spec.effort === "string" ? spec.effort : undefined;
90
+ const model = typeof spec.model === "string" ? spec.model : undefined;
91
+ const isolation = typeof spec.isolation === "string" ? spec.isolation : undefined;
92
+ const schema = spec.schema;
93
+ // Budget and lifetime are checked before dispatch and throw, unlike an agent
94
+ // failure. This is the one difference a script is required to handle.
95
+ if (options.budgetTotal != null && spent >= options.budgetTotal) {
96
+ throw new WorkflowError(`budget exhausted: spent ${spent} of ${options.budgetTotal} output tokens`);
97
+ }
98
+ if (calls >= lifetimeCap) {
99
+ throw new WorkflowError(`lifetime cap reached: ${lifetimeCap} agent calls in one run`);
100
+ }
101
+ calls++;
102
+ const callIndex = calls;
103
+ // A pause holds the queue, it does not discard it: every call still runs,
104
+ // just later. The wait is bounded so a forgotten pause cannot hang a run.
105
+ if (options.isPaused?.()) {
106
+ const release = await waitForResume(options, PAUSE_POLL_MS, PAUSE_MAX_MS);
107
+ if (!release)
108
+ return null;
109
+ }
110
+ const release = await acquire();
111
+ try {
112
+ if (options.signal?.aborted)
113
+ return null;
114
+ emit({ kind: "agent_start", label, phase, ordinal: calls });
115
+ snapshots.set(callIndex, {
116
+ label,
117
+ phase,
118
+ agentType,
119
+ status: "running",
120
+ outputTokens: 0,
121
+ ...(model ? { model } : {}),
122
+ startedAt: Date.now(),
123
+ });
124
+ publish();
125
+ const settle = (status, outcome, detail) => {
126
+ const entry = snapshots.get(callIndex);
127
+ if (entry) {
128
+ entry.status = status;
129
+ entry.outputTokens = outcome.outputTokens;
130
+ entry.endedAt = Date.now();
131
+ if (outcome.toolCalls !== undefined)
132
+ entry.toolCalls = outcome.toolCalls;
133
+ if (outcome.model !== undefined)
134
+ entry.model = outcome.model;
135
+ if (detail)
136
+ entry.detail = detail;
137
+ }
138
+ emit({ kind: "agent_end", label, ok: status === "ok", outputTokens: outcome.outputTokens });
139
+ publish();
140
+ };
141
+ // A schema call gets one repair turn: the model is shown the validation
142
+ // errors and asked again. Exhausting the retries resolves null, per spec.
143
+ const attempts = schema === undefined ? 1 : 2;
144
+ for (let attempt = 0; attempt < attempts; attempt++) {
145
+ const ask = attempt === 0 ? String(prompt) : undefined;
146
+ const outcome = await invokeSafely(ask ?? buildRepairPrompt(String(prompt), lastRejection), { label, phase, agentType, effort, model, isolation });
147
+ if (outcome === null) {
148
+ settle("failed", { text: "", outputTokens: 0 });
149
+ return null;
150
+ }
151
+ spent += outcome.outputTokens;
152
+ if (schema === undefined) {
153
+ settle("ok", outcome, firstLine(outcome.text));
154
+ return outcome.text;
155
+ }
156
+ const parsed = extractJsonLoose(outcome.text);
157
+ const issues = parsed === undefined ? [{ path: "", message: "reply was not JSON" }] : validateSchema(parsed, schema);
158
+ if (issues.length === 0) {
159
+ settle("ok", outcome, firstLine(outcome.text));
160
+ return parsed;
161
+ }
162
+ lastRejection = formatIssues(issues);
163
+ if (attempt === attempts - 1) {
164
+ settle("failed", outcome, `schema: ${firstLine(lastRejection)}`);
165
+ return null;
166
+ }
167
+ }
168
+ return null;
169
+ }
170
+ finally {
171
+ release();
172
+ }
173
+ };
174
+ let lastRejection = "";
175
+ const invokeSafely = async (prompt, spec) => {
176
+ try {
177
+ return await options.invoke({ prompt, ...spec });
178
+ }
179
+ catch {
180
+ // Engine-internal failures degrade to null, never a throw.
181
+ return null;
182
+ }
183
+ };
184
+ const parallel = async (thunks) => {
185
+ if (thunks.length > fanoutCap) {
186
+ throw new WorkflowError(`fan-out cap exceeded: ${thunks.length} items (max ${fanoutCap})`);
187
+ }
188
+ const results = await Promise.all(thunks.map(async (thunk) => {
189
+ try {
190
+ return await thunk();
191
+ }
192
+ catch {
193
+ return null;
194
+ }
195
+ }));
196
+ return results;
197
+ };
198
+ const pipeline = async (items, ...stages) => {
199
+ if (items.length > fanoutCap) {
200
+ throw new WorkflowError(`fan-out cap exceeded: ${items.length} items (max ${fanoutCap})`);
201
+ }
202
+ const results = await Promise.all(items.map(async (item, index) => {
203
+ let prev = item;
204
+ for (const stage of stages) {
205
+ try {
206
+ prev = await stage(prev, item, index);
207
+ }
208
+ catch {
209
+ return null; // only a throw drops the item
210
+ }
211
+ }
212
+ return prev;
213
+ }));
214
+ return results;
215
+ };
216
+ return {
217
+ agent: (prompt, opts) => runAgent(prompt, opts),
218
+ parallel,
219
+ pipeline,
220
+ phase: (title) => {
221
+ currentPhase = String(title);
222
+ emit({ kind: "phase", title: currentPhase });
223
+ },
224
+ log: (message) => emit({ kind: "log", message: String(message) }),
225
+ args: options.args,
226
+ budget: {
227
+ total: options.budgetTotal ?? null,
228
+ spent: () => spent,
229
+ remaining: () => (options.budgetTotal == null ? Infinity : Math.max(0, options.budgetTotal - spent)),
230
+ },
231
+ };
232
+ }
233
+ /** Told to the model when its reply did not validate. */
234
+ function buildRepairPrompt(original, rejection) {
235
+ return `${original}\n\nYour previous reply did not satisfy the required schema:\n${rejection}\n\nReply with ONLY a corrected JSON value.`;
236
+ }
237
+ /** The first non-empty line, clipped — the one-line detail for a progress row. */
238
+ function firstLine(text, max = 80) {
239
+ const line = text
240
+ .split("\n")
241
+ .map((entry) => entry.trim())
242
+ .find((entry) => entry.length > 0) ?? "";
243
+ return line.length > max ? `${line.slice(0, max)}…` : line;
244
+ }
245
+ /** Late-bound to keep `validateSchema`/`extractJson` out of the engine's import cycle. */
246
+ import { extractJson as extractJsonLoose, formatIssues, validateSchema } from "./schema.js";