howtofixcli 0.7.8 → 0.7.9

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 (152) hide show
  1. package/dist/chunk-27TRKD65.js +2 -0
  2. package/dist/chunk-3FYCFLNK.js +1 -0
  3. package/dist/chunk-56SEAGAQ.js +1 -0
  4. package/dist/chunk-63ZCQDXH.js +6 -0
  5. package/dist/chunk-6FUWMLWO.js +1 -0
  6. package/dist/chunk-7CHDNTH6.js +1 -0
  7. package/dist/chunk-ACOMNDUL.js +185 -0
  8. package/dist/chunk-AEVPET7X.js +2 -0
  9. package/dist/chunk-AGGIYXN7.js +2 -0
  10. package/dist/chunk-BHVBO4SC.js +1 -0
  11. package/dist/chunk-FPXVDP32.js +8 -0
  12. package/dist/chunk-GIUYIKH3.js +109 -0
  13. package/dist/chunk-GQCAJ56I.js +5 -0
  14. package/dist/chunk-GXB7RZHH.js +1 -0
  15. package/dist/chunk-IGEY3AWF.js +1 -0
  16. package/dist/chunk-ILDDDLRC.js +1 -0
  17. package/dist/chunk-JFYVRWJI.js +2 -0
  18. package/dist/chunk-MVLCGU3G.js +1 -0
  19. package/dist/chunk-N345KWWK.js +1 -0
  20. package/dist/chunk-NBQFPCRT.js +1 -0
  21. package/dist/chunk-OIPSLIZE.js +5 -0
  22. package/dist/chunk-ORJ2QZBG.js +3 -0
  23. package/dist/chunk-PCALBZOO.js +2 -0
  24. package/dist/chunk-PDNBGUYP.js +2 -0
  25. package/dist/chunk-S656RE4A.js +1 -0
  26. package/dist/chunk-TSEKPGK4.js +1 -0
  27. package/dist/chunk-U6CI6KXN.js +34 -0
  28. package/dist/chunk-UTYFLLSM.js +1 -0
  29. package/dist/chunk-V3R4FYTJ.js +1 -0
  30. package/dist/chunk-V656XVXV.js +8 -0
  31. package/dist/chunk-WKUJ7CFO.js +1 -0
  32. package/dist/chunk-WOT6VMZA.js +1 -0
  33. package/dist/chunk-WUPU6LTD.js +4 -0
  34. package/dist/chunk-WX3V5P7U.js +5 -0
  35. package/dist/chunk-ZKZ6WCI3.js +2 -0
  36. package/dist/main.js +94 -536
  37. package/package.json +15 -62
  38. package/dist/account-credential.js +0 -136
  39. package/dist/account-credential.test.js +0 -38
  40. package/dist/activity.js +0 -124
  41. package/dist/agent-defs.js +0 -237
  42. package/dist/agent-limiter.js +0 -68
  43. package/dist/agents.js +0 -554
  44. package/dist/anim.js +0 -361
  45. package/dist/args.js +0 -228
  46. package/dist/at-file.js +0 -28
  47. package/dist/brand-extension.js +0 -87
  48. package/dist/brand.js +0 -76
  49. package/dist/browser.js +0 -58
  50. package/dist/cache-report.js +0 -139
  51. package/dist/checkpoint.js +0 -437
  52. package/dist/claims.js +0 -167
  53. package/dist/cli-auth.js +0 -142
  54. package/dist/cli-checkin.js +0 -120
  55. package/dist/cli-credentials.js +0 -254
  56. package/dist/clipboard.js +0 -149
  57. package/dist/collapse.js +0 -129
  58. package/dist/commands.js +0 -301
  59. package/dist/compaction-guard.js +0 -81
  60. package/dist/context-extension.js +0 -17
  61. package/dist/dcp/commands.js +0 -172
  62. package/dist/dcp/compress-state.js +0 -139
  63. package/dist/dcp/compress.js +0 -329
  64. package/dist/dcp/dcp-extension.js +0 -288
  65. package/dist/dcp/dedup.js +0 -93
  66. package/dist/dcp/ids.js +0 -189
  67. package/dist/dcp/index.js +0 -25
  68. package/dist/dcp/prompts.js +0 -68
  69. package/dist/dcp/protected-content.js +0 -221
  70. package/dist/dcp/protected.js +0 -161
  71. package/dist/dcp/prune.js +0 -418
  72. package/dist/dcp/state.js +0 -176
  73. package/dist/device-id.js +0 -90
  74. package/dist/device-id.test.js +0 -23
  75. package/dist/errors.js +0 -63
  76. package/dist/extensions.js +0 -48
  77. package/dist/fatal.js +0 -35
  78. package/dist/feed.js +0 -498
  79. package/dist/fs-atomic.js +0 -54
  80. package/dist/gateway-errors.js +0 -90
  81. package/dist/git.js +0 -230
  82. package/dist/goal-extension.js +0 -88
  83. package/dist/goal.js +0 -222
  84. package/dist/hooks-extension.js +0 -176
  85. package/dist/hooks.js +0 -443
  86. package/dist/howtofix-account.js +0 -715
  87. package/dist/hud-line.js +0 -153
  88. package/dist/hwid.js +0 -130
  89. package/dist/interrupt.js +0 -60
  90. package/dist/json-events.js +0 -50
  91. package/dist/level-style.js +0 -112
  92. package/dist/loop-guard.js +0 -95
  93. package/dist/lsp-tools.js +0 -32
  94. package/dist/lsp.js +0 -347
  95. package/dist/mcp-config.js +0 -85
  96. package/dist/mcp-lifecycle.js +0 -147
  97. package/dist/model-catalog.js +0 -217
  98. package/dist/model-resolve.js +0 -65
  99. package/dist/notes.js +0 -78
  100. package/dist/oauth-login.js +0 -568
  101. package/dist/paths.js +0 -61
  102. package/dist/permissions.js +0 -298
  103. package/dist/plan-mode.js +0 -363
  104. package/dist/preset-command.js +0 -227
  105. package/dist/preset-extension.js +0 -35
  106. package/dist/preset-mcp.js +0 -292
  107. package/dist/presets.js +0 -727
  108. package/dist/prompt-files.js +0 -103
  109. package/dist/prompt-text.js +0 -41
  110. package/dist/proxy.js +0 -137
  111. package/dist/quality/ast.js +0 -196
  112. package/dist/quality/cognitive.js +0 -83
  113. package/dist/quality/cyclomatic.js +0 -30
  114. package/dist/quality/halstead.js +0 -83
  115. package/dist/quality/index.js +0 -18
  116. package/dist/quality/length.js +0 -3
  117. package/dist/quality/maintainability.js +0 -15
  118. package/dist/quality/nesting.js +0 -57
  119. package/dist/quality/report.js +0 -803
  120. package/dist/quality/smells.js +0 -67
  121. package/dist/quality-tool.js +0 -63
  122. package/dist/read-only-commands.js +0 -597
  123. package/dist/repo-map.js +0 -292
  124. package/dist/rtk.js +0 -193
  125. package/dist/sandbox.js +0 -105
  126. package/dist/schema.js +0 -214
  127. package/dist/session-lifecycle.js +0 -19
  128. package/dist/session-retention.js +0 -111
  129. package/dist/session.js +0 -446
  130. package/dist/sessions.js +0 -100
  131. package/dist/settings.js +0 -148
  132. package/dist/skills.js +0 -35
  133. package/dist/slop-tool.js +0 -96
  134. package/dist/spend-cap.js +0 -43
  135. package/dist/subagent.js +0 -171
  136. package/dist/tar.js +0 -146
  137. package/dist/theme.js +0 -79
  138. package/dist/thinking.js +0 -45
  139. package/dist/todo.js +0 -114
  140. package/dist/tool-loadout.js +0 -97
  141. package/dist/tool-render.js +0 -769
  142. package/dist/tools.js +0 -176
  143. package/dist/ui.js +0 -4757
  144. package/dist/update.js +0 -533
  145. package/dist/usage-segment.js +0 -69
  146. package/dist/web-tools.js +0 -46
  147. package/dist/web.js +0 -265
  148. package/dist/welcome.js +0 -179
  149. package/dist/workflow-engine.js +0 -246
  150. package/dist/workflow-progress.js +0 -446
  151. package/dist/workflow-view.js +0 -195
  152. package/dist/workflow.js +0 -349
@@ -1,221 +0,0 @@
1
- import { refIndicesOf } from "./ids.js";
2
- import { activeCompressedRanges, estimateSummaryTokens } from "./compress-state.js";
3
- import { HARD_EXCEPTION_TOOLS, isToolProtected } from "./protected.js";
4
- /**
5
- * The shared predicate, once: selection members in transcript order, minus
6
- * the ones an active block already covers, resolved to array positions.
7
- *
8
- * `exceptBlockId` is the block this append is FOR. At render time that block is
9
- * already active and covers exactly the window being appended, so leaving it in
10
- * the skip set makes every append a no-op — silently, with a stored summary that
11
- * looks correct and has lost the user's own words. The caller that renders a
12
- * block's summary passes its id; a caller doing anything else omits it.
13
- */
14
- function unprotectedPositions(selection, source, state, exceptBlockId) {
15
- // No ref state (a transcript that was never tagged): nothing resolves, so
16
- // every append is a no-op rather than an error — the compaction case.
17
- const posByRef = new Map();
18
- if (source.idState) {
19
- const refs = refIndicesOf(source.idState, source.messages);
20
- for (let position = 0; position < refs.length; position++) {
21
- const ref = refs[position];
22
- if (ref !== null)
23
- posByRef.set(ref, position);
24
- }
25
- }
26
- const covered = new Set();
27
- for (const range of activeCompressedRanges(state)) {
28
- if (exceptBlockId !== undefined && range.blockId === exceptBlockId)
29
- continue;
30
- for (const index of range.coveredIndices) {
31
- covered.add(index);
32
- }
33
- }
34
- const positions = [];
35
- if (source.idState) {
36
- for (const ref of selection.indices) {
37
- if (covered.has(ref))
38
- continue;
39
- const position = posByRef.get(ref);
40
- if (position === undefined)
41
- continue;
42
- positions.push(position);
43
- }
44
- }
45
- return positions;
46
- }
47
- /** Every non-empty text of a user message; the content may be a bare string. */
48
- function userTextParts(message) {
49
- if (typeof message.content === "string") {
50
- return message.content.trim() ? [message.content] : [];
51
- }
52
- const texts = [];
53
- for (const part of message.content) {
54
- if (part.type === "text" && part.text.trim()) {
55
- texts.push(part.text);
56
- }
57
- }
58
- return texts;
59
- }
60
- /**
61
- * Append the first non-empty text of every selected user message that is not
62
- * already covered by an active block. Byte-identical no-op when `enabled` is
63
- * false or nothing qualifies — a heading with no body would be worse than
64
- * nothing, it reads as a bug to the model.
65
- */
66
- export function appendProtectedUserMessages(summary, selection, source, state, enabled, forBlockId) {
67
- if (!enabled)
68
- return summary;
69
- const userTexts = [];
70
- for (const position of unprotectedPositions(selection, source, state, forBlockId)) {
71
- const message = source.messages[position];
72
- if (!message || message.role !== "user")
73
- continue;
74
- const first = userTextParts(message)[0];
75
- if (first !== undefined) {
76
- userTexts.push(first);
77
- }
78
- }
79
- if (userTexts.length === 0)
80
- return summary;
81
- const heading = "\n\nThe following user messages were sent in this conversation verbatim:";
82
- const body = userTexts.map((text) => `\n${text}`).join("");
83
- return summary + heading + body;
84
- }
85
- /**
86
- * Append every `<protect>...</protect>` capture from the selected user
87
- * messages that is not already covered by an active block. Same no-op rule
88
- * as the user-message path.
89
- */
90
- export function appendProtectedPromptInfo(summary, selection, source, state, enabled, forBlockId) {
91
- if (!enabled)
92
- return summary;
93
- const protectedTexts = [];
94
- for (const position of unprotectedPositions(selection, source, state, forBlockId)) {
95
- const message = source.messages[position];
96
- if (!message || message.role !== "user")
97
- continue;
98
- for (const text of userTextParts(message)) {
99
- protectedTexts.push(...extractProtectedPromptInfo(text));
100
- }
101
- }
102
- if (protectedTexts.length === 0)
103
- return summary;
104
- const heading = "\n\nThe following protected prompt information was included in this conversation verbatim:";
105
- const body = protectedTexts.map((text) => `\n${text}`).join("");
106
- return summary + heading + body;
107
- }
108
- /** Every `<protect>...</protect>` capture in `text`, trimmed, empties dropped. */
109
- export function extractProtectedPromptInfo(text) {
110
- const protectedTexts = [];
111
- const protectTagRegex = /<protect>([\s\S]*?)<\/protect>/gi;
112
- for (const match of text.matchAll(protectTagRegex)) {
113
- const captured = match[1]?.trim();
114
- if (captured) {
115
- protectedTexts.push(captured);
116
- }
117
- }
118
- return protectedTexts;
119
- }
120
- /**
121
- * Append the outputs of protected tools from the selection window. A tool is
122
- * protected when its name matches the hard exceptions, the configured list,
123
- * or a configured file pattern matches a path in its arguments.
124
- *
125
- * The window is also the pairing scope: an output whose call sits outside the
126
- * window has no arguments to inspect, so it falls back to name-based
127
- * protection (`isToolProtected` with an undefined input).
128
- */
129
- export function appendProtectedTools(summary, selection, source, state, protectedTools = [], protectedFilePatterns = [], forBlockId) {
130
- const argsByCallId = new Map();
131
- const outputs = [];
132
- for (const position of unprotectedPositions(selection, source, state, forBlockId)) {
133
- const message = source.messages[position];
134
- if (!message)
135
- continue;
136
- if (message.role === "assistant") {
137
- for (const part of message.content) {
138
- if (part.type === "toolCall") {
139
- argsByCallId.set(part.id, part.arguments);
140
- }
141
- }
142
- continue;
143
- }
144
- if (message.role === "toolResult") {
145
- // Error outputs are prune candidates, not keepsakes; the reference only
146
- // ever preserved completed output.
147
- if (message.isError)
148
- continue;
149
- const text = message.content
150
- .filter((part) => part.type === "text")
151
- .map((part) => part.text)
152
- .join("");
153
- if (text.trim()) {
154
- outputs.push({ toolCallId: message.toolCallId, toolName: message.toolName, text });
155
- }
156
- }
157
- }
158
- if (outputs.length === 0)
159
- return summary;
160
- const toolNames = [...new Set([...HARD_EXCEPTION_TOOLS, ...protectedTools])];
161
- const filePatterns = [...protectedFilePatterns];
162
- const blocks = [];
163
- for (const output of outputs) {
164
- const input = argsByCallId.get(output.toolCallId);
165
- if (!isToolProtected(output.toolName, input, toolNames, filePatterns))
166
- continue;
167
- blocks.push(`\n### Tool: ${output.toolName}\n${output.text}`);
168
- }
169
- if (blocks.length === 0)
170
- return summary;
171
- const heading = "\n\nThe following protected tools were used in this conversation as well:";
172
- return summary + heading + blocks.join("");
173
- }
174
- /**
175
- * Store-side enrichment: layer a block's window's protected content onto its
176
- * stored summary in one mutation.
177
- *
178
- * This is the only path that carries the text, and the handler calls it once
179
- * per active block on every request. It runs here rather than in the compress
180
- * tool because the tool's `messages()` is a ref snapshot, not the transcript —
181
- * the appends resolve refs to messages, so only a caller holding both can do
182
- * this at all.
183
- *
184
- * Contract rules, each observable in `check-dcp.mjs`:
185
- *
186
- * 1. The selection is the block's own coverage — min/max bound it, the
187
- * indices enumerate it.
188
- * 2. `forBlockId` is passed on every append: the block is active and covers
189
- * its window, so without the self-exclusion everything no-ops silently.
190
- * 3. The result is written back with `summaryTokens` recomputed through the
191
- * same estimator creation uses — stale tokens would lie about the savings.
192
- * 4. Idempotent via `protectedEnriched`: a re-run on a resumed session never
193
- * duplicates the user's words. The flag lives on the block, not in the
194
- * text, so a nested block whose body inherits an enriched summary still
195
- * enriches its own window.
196
- * 5. A transcript that no longer holds the covered refs simply resolves to
197
- * no messages: nothing is appended, nothing throws.
198
- *
199
- * `state` must carry the ref assignment (`DcpState.messageIds`); typed as an
200
- * intersection so this module does not depend on the store that depends on
201
- * `compress-state.ts`.
202
- */
203
- export function enrichBlockSummary(state, block, messages) {
204
- if (block.protectedEnriched)
205
- return;
206
- const covered = block.coveredIndices;
207
- if (covered.length > 0) {
208
- const selection = {
209
- startIdx: Math.min(...covered),
210
- endIdx: Math.max(...covered),
211
- indices: [...covered],
212
- requiredBlockIds: [],
213
- tokenByIndex: new Map(),
214
- };
215
- const source = { messages, idState: state.messageIds };
216
- const enriched = appendProtectedTools(appendProtectedPromptInfo(appendProtectedUserMessages(block.summary, selection, source, state, true, block.blockId), selection, source, state, true, block.blockId), selection, source, state, [], [], block.blockId);
217
- block.summary = enriched;
218
- block.summaryTokens = estimateSummaryTokens(enriched);
219
- }
220
- block.protectedEnriched = true;
221
- }
@@ -1,161 +0,0 @@
1
- /**
2
- * Static protection layer: which tools and which file paths are never pruned.
3
- *
4
- * Ported from Opencode-DCP `lib/protected-patterns.ts`. `normalizePath`,
5
- * `matchesGlob` (`*`, `?`, `**`), `getFilePathsFromParameters` (`path`,
6
- * `filePath`, `patchText`, `multiedit`), `isFilePathProtected`,
7
- * `isToolNameProtected`, and `isToolProtected` keep DCP's behaviour; the only
8
- * divergence is typed access — the port uses `unknown` narrowing instead of the
9
- * original's `any`.
10
- *
11
- * The keep-set (goal/plan/notes aware) is the other, dynamic protection layer
12
- * and lives in `prune.ts`; this module is pure pattern matching.
13
- */
14
- /** Collapse Windows separators so paths compare across platforms. */
15
- export function normalizePath(input) {
16
- // A single backslash. In source, "\\" is the one-character string; the
17
- // previous "\\\\" was a *two*-character string, so it only ever matched a
18
- // doubled separator -- which a real Windows path does not contain. The
19
- // normalisation was therefore a no-op on the only platform that needs it.
20
- return input.replaceAll("\\", "/");
21
- }
22
- function escapeRegExpChar(ch) {
23
- return /[\\.^$+{}()|\[\]]/.test(ch) ? `\\${ch}` : ch;
24
- }
25
- /**
26
- * Glob match supporting `*` (no `/`), `?` (one non-`/`), and `**`
27
- * (`**` before a slash = zero or more directories, bare `**` = anything).
28
- */
29
- export function matchesGlob(inputPath, pattern) {
30
- if (!pattern)
31
- return false;
32
- const input = normalizePath(inputPath);
33
- const pat = normalizePath(pattern);
34
- let regex = "^";
35
- for (let i = 0; i < pat.length; i++) {
36
- const ch = pat[i];
37
- if (ch === "*") {
38
- const next = pat[i + 1];
39
- if (next === "*") {
40
- const after = pat[i + 2];
41
- if (after === "/") {
42
- // A doubled star before a slash: zero or more directories
43
- regex += "(?:.*/)?";
44
- i += 2;
45
- continue;
46
- }
47
- // **
48
- regex += ".*";
49
- i++;
50
- continue;
51
- }
52
- // *
53
- regex += "[^/]*";
54
- continue;
55
- }
56
- if (ch === "?") {
57
- regex += "[^/]";
58
- continue;
59
- }
60
- if (ch === "/") {
61
- regex += "/";
62
- continue;
63
- }
64
- regex += escapeRegExpChar(ch);
65
- }
66
- regex += "$";
67
- return new RegExp(regex).test(input);
68
- }
69
- /**
70
- * Extract file paths from a tool call's parameters:
71
- * - `apply_patch`/`patch` → paths embedded in `patchText`
72
- * - `multiedit` → top-level `filePath` plus each edit's `filePath`
73
- * - any tool → a string `filePath`
74
- * - `read`/`write`/`edit` → their V2 `path` parameter
75
- * Returns unique non-empty paths.
76
- */
77
- export function getFilePathsFromParameters(tool, parameters) {
78
- if (typeof parameters !== "object" || parameters === null) {
79
- return [];
80
- }
81
- const paths = [];
82
- const params = parameters;
83
- // 1. apply_patch uses patchText with embedded paths
84
- if ((tool === "apply_patch" || tool === "patch") && typeof params.patchText === "string") {
85
- const pathRegex = /\*\*\* (?:Add|Delete|Update) File: ([^\n\r]+)/g;
86
- let match;
87
- while ((match = pathRegex.exec(params.patchText)) !== null) {
88
- paths.push(match[1].trim());
89
- }
90
- }
91
- // 2. multiedit uses top-level filePath and nested edits array
92
- if (tool === "multiedit") {
93
- if (typeof params.filePath === "string") {
94
- paths.push(params.filePath);
95
- }
96
- if (Array.isArray(params.edits)) {
97
- for (const edit of params.edits) {
98
- if (edit && typeof edit === "object" && typeof edit.filePath === "string") {
99
- paths.push(edit.filePath);
100
- }
101
- }
102
- }
103
- }
104
- // 3. Default check for common filePath parameter (read, write, edit, etc)
105
- if (typeof params.filePath === "string") {
106
- paths.push(params.filePath);
107
- }
108
- // V2 file tools use path rather than filePath.
109
- if (["read", "write", "edit"].includes(tool) && typeof params.path === "string") {
110
- paths.push(params.path);
111
- }
112
- // Unique, non-empty
113
- return [...new Set(paths)].filter((p) => p.length > 0);
114
- }
115
- export function isFilePathProtected(filePaths, patterns) {
116
- if (filePaths.length === 0)
117
- return false;
118
- if (patterns.length === 0)
119
- return false;
120
- return filePaths.some((path) => patterns.some((pattern) => matchesGlob(path, pattern)));
121
- }
122
- const GLOB_CHARS = /[*?]/;
123
- /**
124
- * Tools that are never pruned, deduped, or compressed — their results carry
125
- * state the session replays from (todo/plan), or steer the run (goal/context/task).
126
- * Spec §3.4 hard exceptions; the default protection list for dedup and prune.
127
- */
128
- export const HARD_EXCEPTION_TOOLS = ["todo", "goal", "context", "task"];
129
- export function isToolNameProtected(toolName, patterns) {
130
- if (!toolName || patterns.length === 0)
131
- return false;
132
- const exactPatterns = new Set();
133
- const globPatterns = [];
134
- for (const pattern of patterns) {
135
- if (GLOB_CHARS.test(pattern)) {
136
- globPatterns.push(pattern);
137
- }
138
- else {
139
- exactPatterns.add(pattern);
140
- }
141
- }
142
- if (exactPatterns.has(toolName))
143
- return true;
144
- return globPatterns.some((pattern) => matchesGlob(toolName, pattern));
145
- }
146
- /**
147
- * True when the tool name matches `tools` or any of its file paths match
148
- * `files`. `metadata.toolCalls` (V2 code-mode nested calls) is checked too:
149
- * one combined output is protected when any nested call matches.
150
- */
151
- export function isToolProtected(tool, input, tools, files, metadata) {
152
- const calls = [{ tool, input }];
153
- if (tool === "execute" && Array.isArray(metadata?.toolCalls)) {
154
- for (const call of metadata.toolCalls) {
155
- if (call && typeof call === "object" && typeof call.tool === "string") {
156
- calls.push({ tool: call.tool, input: call.input });
157
- }
158
- }
159
- }
160
- return calls.some((call) => isToolNameProtected(call.tool, tools) || isFilePathProtected(getFilePathsFromParameters(call.tool, call.input), files));
161
- }