@agentclientprotocol/claude-agent-acp 0.81.2 → 0.81.3-preview.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/dist/acp-agent.d.ts +32 -40
- package/dist/acp-agent.d.ts.map +1 -1
- package/dist/acp-agent.js +557 -577
- package/dist/acp-subagents.d.ts +6 -0
- package/dist/acp-subagents.d.ts.map +1 -1
- package/dist/air-extension.d.ts +31 -1
- package/dist/air-extension.d.ts.map +1 -1
- package/dist/air-extension.js +35 -1
- package/dist/async-tasks.d.ts +39 -2
- package/dist/async-tasks.d.ts.map +1 -1
- package/dist/async-tasks.js +147 -44
- package/dist/context-compaction-meta.d.ts +6 -5
- package/dist/context-compaction-meta.d.ts.map +1 -1
- package/dist/context-compaction-meta.js +10 -10
- package/dist/context-compaction.d.ts +3 -0
- package/dist/context-compaction.d.ts.map +1 -1
- package/dist/context-compaction.js +23 -57
- package/dist/diff.d.ts +73 -5
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +435 -64
- package/dist/elicitation.d.ts +1 -1
- package/dist/elicitation.d.ts.map +1 -1
- package/dist/elicitation.js +12 -14
- package/dist/hide-claude-auth.d.ts +2 -6
- package/dist/hide-claude-auth.d.ts.map +1 -1
- package/dist/hide-claude-auth.js +3 -21
- package/dist/native-subagents.d.ts +58 -0
- package/dist/native-subagents.d.ts.map +1 -1
- package/dist/native-subagents.js +186 -34
- package/dist/paths.d.ts +3 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +6 -0
- package/dist/permissions/presentation.d.ts +13 -2
- package/dist/permissions/presentation.d.ts.map +1 -1
- package/dist/permissions/presentation.js +49 -44
- package/dist/resumed-session.d.ts +11 -0
- package/dist/resumed-session.d.ts.map +1 -1
- package/dist/resumed-session.js +106 -4
- package/dist/session-failure-extension.js +1 -1
- package/dist/session-mode.d.ts +2 -0
- package/dist/session-mode.d.ts.map +1 -1
- package/dist/session-mode.js +12 -5
- package/dist/settings.js +2 -2
- package/dist/subagent-history.d.ts +20 -0
- package/dist/subagent-history.d.ts.map +1 -0
- package/dist/subagent-history.js +46 -0
- package/dist/tool-calls/background.d.ts +20 -0
- package/dist/tool-calls/background.d.ts.map +1 -0
- package/dist/tool-calls/background.js +41 -0
- package/dist/tool-calls/changed-meta-filter.d.ts +27 -0
- package/dist/tool-calls/changed-meta-filter.d.ts.map +1 -0
- package/dist/tool-calls/changed-meta-filter.js +102 -0
- package/dist/tool-calls/client-capabilities.d.ts +51 -0
- package/dist/tool-calls/client-capabilities.d.ts.map +1 -0
- package/dist/tool-calls/client-capabilities.js +43 -0
- package/dist/tool-calls/content.d.ts +59 -0
- package/dist/tool-calls/content.d.ts.map +1 -0
- package/dist/tool-calls/content.js +194 -0
- package/dist/tool-calls/facts.d.ts +116 -0
- package/dist/tool-calls/facts.d.ts.map +1 -0
- package/dist/tool-calls/facts.js +1 -0
- package/dist/tool-calls/field-tracker.d.ts +58 -0
- package/dist/tool-calls/field-tracker.d.ts.map +1 -0
- package/dist/tool-calls/field-tracker.js +167 -0
- package/dist/tool-calls/renderer.d.ts +216 -0
- package/dist/tool-calls/renderer.d.ts.map +1 -0
- package/dist/tool-calls/renderer.js +487 -0
- package/dist/tool-calls/reporters/agent.d.ts +7 -0
- package/dist/tool-calls/reporters/agent.d.ts.map +1 -0
- package/dist/tool-calls/reporters/agent.js +190 -0
- package/dist/tool-calls/reporters/bash.d.ts +9 -0
- package/dist/tool-calls/reporters/bash.d.ts.map +1 -0
- package/dist/tool-calls/reporters/bash.js +83 -0
- package/dist/tool-calls/reporters/compaction.d.ts +24 -0
- package/dist/tool-calls/reporters/compaction.d.ts.map +1 -0
- package/dist/tool-calls/reporters/compaction.js +66 -0
- package/dist/tool-calls/reporters/file-edit.d.ts +46 -0
- package/dist/tool-calls/reporters/file-edit.d.ts.map +1 -0
- package/dist/tool-calls/reporters/file-edit.js +180 -0
- package/dist/tool-calls/reporters/index.d.ts +4 -0
- package/dist/tool-calls/reporters/index.d.ts.map +1 -0
- package/dist/tool-calls/reporters/index.js +40 -0
- package/dist/tool-calls/reporters/interaction.d.ts +71 -0
- package/dist/tool-calls/reporters/interaction.d.ts.map +1 -0
- package/dist/tool-calls/reporters/interaction.js +222 -0
- package/dist/tool-calls/reporters/read.d.ts +7 -0
- package/dist/tool-calls/reporters/read.d.ts.map +1 -0
- package/dist/tool-calls/reporters/read.js +64 -0
- package/dist/tool-calls/reporters/search.d.ts +10 -0
- package/dist/tool-calls/reporters/search.d.ts.map +1 -0
- package/dist/tool-calls/reporters/search.js +50 -0
- package/dist/tool-calls/reporters/web.d.ts +11 -0
- package/dist/tool-calls/reporters/web.d.ts.map +1 -0
- package/dist/tool-calls/reporters/web.js +42 -0
- package/dist/tools.d.ts +32 -37
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +48 -970
- package/package.json +4 -1
package/dist/diff.js
CHANGED
|
@@ -1,10 +1,207 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { structuredPatch } from "diff";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { open } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { AIR_DIFF_PATCH_CAPABILITY, withAirMeta } from "./air-extension.js";
|
|
6
|
+
import { normalizeWriteInput } from "./tool-calls/reporters/file-edit.js";
|
|
2
7
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
+
* The largest file, in bytes, that the adapter turns into a git patch.
|
|
9
|
+
*
|
|
10
|
+
* A larger file, a larger new text, or an Edit whose result can be larger
|
|
11
|
+
* gets no patch. The tool call then keeps its standard ACP content. The limit
|
|
12
|
+
* bounds the file read, the replacement, and the line diff that run while
|
|
13
|
+
* Claude waits for an approval.
|
|
14
|
+
*/
|
|
15
|
+
export const MAX_PATCH_FILE_BYTES = 1024 * 1024;
|
|
16
|
+
/**
|
|
17
|
+
* The wall-clock budget, in milliseconds, of one line diff for a patch.
|
|
18
|
+
*
|
|
19
|
+
* The diff runs synchronously, so the budget is also the longest block of the
|
|
20
|
+
* event loop.
|
|
21
|
+
*/
|
|
22
|
+
const PATCH_DIFF_TIMEOUT_MS = 100;
|
|
23
|
+
/** The number of context lines around a change in a hunk. */
|
|
24
|
+
const PATCH_CONTEXT_LINES = 3;
|
|
25
|
+
/** Git reads this many leading bytes to decide that a file is binary. */
|
|
26
|
+
const BINARY_SNIFF_BYTES = 8000;
|
|
27
|
+
const NO_NEWLINE_MARKER = "\";
|
|
28
|
+
/**
|
|
29
|
+
* Builds the exact patch shown before Claude runs an Edit or Write tool.
|
|
30
|
+
*
|
|
31
|
+
* Returns undefined when the adapter cannot predict the file change exactly.
|
|
32
|
+
* The caller then keeps the standard tool-call content. The adapter declines
|
|
33
|
+
* a file that is missing for an Edit, too large, binary, or that has CR line
|
|
34
|
+
* endings. Claude converts the line endings of an edited file, so an in-memory
|
|
35
|
+
* replacement would not match the bytes that Claude writes. It also declines
|
|
36
|
+
* an `old_string` that does not match exactly once, because Claude then
|
|
37
|
+
* normalizes quotes or fails.
|
|
38
|
+
*
|
|
39
|
+
* A Write always gets content that shows the change: the patch, the standard
|
|
40
|
+
* diff of a text that cannot have an exact patch, or a notice that the Write
|
|
41
|
+
* overwrites a file that the adapter cannot show.
|
|
42
|
+
*
|
|
43
|
+
* The preview uses the tool input as it is. Claude can still remove the
|
|
44
|
+
* trailing whitespace of a line before it writes. The PostToolUse hook then
|
|
45
|
+
* sends the patch of the written file.
|
|
46
|
+
*/
|
|
47
|
+
export async function previewPatchContent(toolName, input, cwd) {
|
|
48
|
+
if (toolName === "Edit") {
|
|
49
|
+
const edit = input;
|
|
50
|
+
if (typeof edit.file_path !== "string" ||
|
|
51
|
+
typeof edit.old_string !== "string" ||
|
|
52
|
+
typeof edit.new_string !== "string") {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const oldString = edit.old_string;
|
|
56
|
+
const filePath = resolveToolPath(edit.file_path, cwd);
|
|
57
|
+
const oldText = await readPatchSource(filePath);
|
|
58
|
+
if (oldText === undefined)
|
|
59
|
+
return undefined;
|
|
60
|
+
const newString = edit.new_string;
|
|
61
|
+
if (oldString === newString || !isPatchableText(newString))
|
|
62
|
+
return undefined;
|
|
63
|
+
if (oldString.length === 0) {
|
|
64
|
+
// An empty old_string creates the file, or fills an existing file that
|
|
65
|
+
// holds only whitespace. `trim` also removes a byte order mark, whose
|
|
66
|
+
// handling the adapter does not predict, so such a file is declined.
|
|
67
|
+
if (oldText !== null && (oldText.trim() !== "" || oldText.includes("\uFEFF"))) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
return optionalContent(filePatch(filePath, oldText, newString)?.content);
|
|
71
|
+
}
|
|
72
|
+
if (oldText === null)
|
|
73
|
+
return undefined;
|
|
74
|
+
const occurrences = oldText.split(oldString).length - 1;
|
|
75
|
+
if (occurrences === 0 || (edit.replace_all !== true && occurrences !== 1))
|
|
76
|
+
return undefined;
|
|
77
|
+
if (replacedTextBytesBound(oldText, oldString, newString, occurrences) > MAX_PATCH_FILE_BYTES) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
const newText = replacedText(oldText, oldString, newString, edit.replace_all === true);
|
|
81
|
+
return optionalContent(filePatch(filePath, oldText, newText)?.content);
|
|
82
|
+
}
|
|
83
|
+
if (toolName === "Write") {
|
|
84
|
+
const write = normalizeWriteInput(input);
|
|
85
|
+
if (typeof write?.file_path !== "string" || typeof write.content !== "string") {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
// The Write tool call shows no diff, so the approval is the only place that
|
|
89
|
+
// shows what the Write changes.
|
|
90
|
+
const content = write.content;
|
|
91
|
+
const filePath = resolveToolPath(write.file_path, cwd);
|
|
92
|
+
const oldText = await readPatchSource(filePath);
|
|
93
|
+
if (oldText === undefined) {
|
|
94
|
+
return [
|
|
95
|
+
{
|
|
96
|
+
type: "content",
|
|
97
|
+
content: {
|
|
98
|
+
type: "text",
|
|
99
|
+
text: `Overwrites the existing file \`${write.file_path}\`. The adapter cannot show its current content.`,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
if (oldText === content)
|
|
105
|
+
return undefined;
|
|
106
|
+
const standard = [
|
|
107
|
+
{ type: "diff", path: write.file_path, oldText, newText: content },
|
|
108
|
+
];
|
|
109
|
+
if (!isPatchableText(content))
|
|
110
|
+
return standard;
|
|
111
|
+
// A dense change can exceed the diff budget. The approval then shows the standard diff.
|
|
112
|
+
return optionalContent(filePatch(filePath, oldText, content)?.content) ?? standard;
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* An upper bound of the UTF-8 size, in bytes, of {@link replacedText}.
|
|
118
|
+
*
|
|
119
|
+
* The caller checks the bound before it builds the text. A `replace_all` of
|
|
120
|
+
* many short matches with a long `newString` can otherwise build a text of
|
|
121
|
+
* gigabytes before the timed line diff starts.
|
|
122
|
+
*/
|
|
123
|
+
function replacedTextBytesBound(fileText, oldString, newString, occurrences) {
|
|
124
|
+
const growth = Buffer.byteLength(newString, "utf8") - Buffer.byteLength(oldString, "utf8");
|
|
125
|
+
return Buffer.byteLength(fileText, "utf8") + occurrences * Math.max(0, growth);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The file text after Claude replaces `oldString` with `newString`.
|
|
129
|
+
*
|
|
130
|
+
* An empty `newString` deletes a line: when `oldString` does not end with a
|
|
131
|
+
* line break and the file holds `oldString` and a line break, Claude also
|
|
132
|
+
* removes that line break. With `replaceAll`, it then replaces only the
|
|
133
|
+
* occurrences that a line break follows.
|
|
134
|
+
*/
|
|
135
|
+
function replacedText(fileText, oldString, newString, replaceAll) {
|
|
136
|
+
const target = newString === "" && !oldString.endsWith("\n") && fileText.includes(`${oldString}\n`)
|
|
137
|
+
? `${oldString}\n`
|
|
138
|
+
: oldString;
|
|
139
|
+
return replaceAll
|
|
140
|
+
? fileText.split(target).join(newString)
|
|
141
|
+
: fileText.replace(target, () => newString);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Builds the git patch for a finished Edit or Write from the file on disk.
|
|
145
|
+
*
|
|
146
|
+
* The Claude SDK `structuredPatch` is display data: Claude converts leading
|
|
147
|
+
* tabs to spaces and CRLF line endings to LF before it computes the hunks. A
|
|
148
|
+
* patch built from those hunks does not match the file. This function diffs
|
|
149
|
+
* `originalFile` against the written file instead. It returns undefined when
|
|
150
|
+
* it cannot build an exact patch, and the caller then sends the standard diff.
|
|
151
|
+
* A written file that contains a CR or a byte order mark is declined, because
|
|
152
|
+
* Claude removed those bytes from `originalFile`.
|
|
153
|
+
*/
|
|
154
|
+
export async function patchUpdateFromDiffToolResponse(toolResponse) {
|
|
155
|
+
if (!toolResponse || typeof toolResponse !== "object")
|
|
156
|
+
return undefined;
|
|
157
|
+
const response = toolResponse;
|
|
158
|
+
if (typeof response.filePath !== "string")
|
|
159
|
+
return undefined;
|
|
160
|
+
// An Edit with an empty old_string reports "" as the original of a created
|
|
161
|
+
// file and of an existing empty file. The response does not tell the two
|
|
162
|
+
// apart, so the caller keeps the standard diff.
|
|
163
|
+
if (response.type === undefined && response.oldString === "" && response.originalFile === "") {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
// A Write whose content is the previous text changed nothing. The file on
|
|
167
|
+
// disk can hold a later change, and that change is not the change of this Write.
|
|
168
|
+
if (response.type === "update" &&
|
|
169
|
+
typeof response.content === "string" &&
|
|
170
|
+
response.originalFile === response.content) {
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
const oldText = response.type === "create"
|
|
174
|
+
? null
|
|
175
|
+
: typeof response.originalFile === "string"
|
|
176
|
+
? response.originalFile
|
|
177
|
+
: undefined;
|
|
178
|
+
if (oldText === undefined)
|
|
179
|
+
return undefined;
|
|
180
|
+
// The same size limit as the new side: a larger text gets the standard diff.
|
|
181
|
+
if (oldText !== null && Buffer.byteLength(oldText, "utf8") > MAX_PATCH_FILE_BYTES)
|
|
182
|
+
return undefined;
|
|
183
|
+
const newText = await readPatchSource(response.filePath);
|
|
184
|
+
if (typeof newText !== "string" || newText.startsWith("\uFEFF"))
|
|
185
|
+
return undefined;
|
|
186
|
+
if (response.type === "create" && newText !== response.content)
|
|
187
|
+
return undefined;
|
|
188
|
+
const patch = filePatch(response.filePath, oldText, newText);
|
|
189
|
+
if (!patch)
|
|
190
|
+
return undefined;
|
|
191
|
+
return {
|
|
192
|
+
content: [patch.content],
|
|
193
|
+
// A created file keeps the location of its Write tool call.
|
|
194
|
+
locations: oldText === null
|
|
195
|
+
? [{ path: response.filePath }]
|
|
196
|
+
: patch.hunks.map(({ newStart }) => ({ path: response.filePath, line: newStart })),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Builds standard ACP diff content from the structured toolResponse provided
|
|
201
|
+
* by the PostToolUse hook for diff-producing tools (Edit, Write). Unlike
|
|
202
|
+
* parsing the plain unified diff string, this uses the pre-parsed
|
|
203
|
+
* structuredPatch which supports multiple replacement sites (replaceAll) and
|
|
204
|
+
* always includes context lines for better readability.
|
|
8
205
|
*/
|
|
9
206
|
export function toolUpdateFromDiffToolResponse(toolResponse) {
|
|
10
207
|
if (!toolResponse || typeof toolResponse !== "object")
|
|
@@ -14,67 +211,20 @@ export function toolUpdateFromDiffToolResponse(toolResponse) {
|
|
|
14
211
|
return {};
|
|
15
212
|
const content = [];
|
|
16
213
|
const locations = [];
|
|
17
|
-
|
|
18
|
-
let previousNewEnd = 0;
|
|
19
|
-
let accumulatedDelta = 0;
|
|
20
|
-
let coordinatesRemainConsistent = true;
|
|
21
|
-
for (const { lines, oldStart, newStart, oldLines, newLines } of response.structuredPatch) {
|
|
214
|
+
for (const { lines, newStart } of response.structuredPatch) {
|
|
22
215
|
const oldText = [];
|
|
23
216
|
const newText = [];
|
|
24
|
-
|
|
25
|
-
let removed = 0;
|
|
26
|
-
let validPrefixes = true;
|
|
27
|
-
let validEofMarkers = true;
|
|
28
|
-
const oldPosition = oldStart + (oldLines === 0 ? 1 : 0);
|
|
29
|
-
const newPosition = newStart + (newLines === 0 ? 1 : 0);
|
|
30
|
-
const oldEnd = oldPosition + oldLines;
|
|
31
|
-
const newEnd = newPosition + newLines;
|
|
32
|
-
const nextDelta = accumulatedDelta + newLines - oldLines;
|
|
33
|
-
const validCoordinates = coordinatesRemainConsistent &&
|
|
34
|
-
Number.isSafeInteger(oldStart) &&
|
|
35
|
-
Number.isSafeInteger(newStart) &&
|
|
36
|
-
Number.isSafeInteger(oldLines) &&
|
|
37
|
-
Number.isSafeInteger(newLines) &&
|
|
38
|
-
oldStart >= (oldLines === 0 ? 0 : 1) &&
|
|
39
|
-
newStart >= (newLines === 0 ? 0 : 1) &&
|
|
40
|
-
oldLines >= 0 &&
|
|
41
|
-
newLines >= 0 &&
|
|
42
|
-
Number.isSafeInteger(oldPosition) &&
|
|
43
|
-
Number.isSafeInteger(newPosition) &&
|
|
44
|
-
Number.isSafeInteger(oldEnd) &&
|
|
45
|
-
Number.isSafeInteger(newEnd) &&
|
|
46
|
-
Number.isSafeInteger(nextDelta) &&
|
|
47
|
-
oldPosition >= previousOldEnd &&
|
|
48
|
-
newPosition >= previousNewEnd &&
|
|
49
|
-
newPosition - oldPosition === accumulatedDelta;
|
|
50
|
-
coordinatesRemainConsistent = validCoordinates;
|
|
51
|
-
if (validCoordinates) {
|
|
52
|
-
previousOldEnd = oldEnd;
|
|
53
|
-
previousNewEnd = newEnd;
|
|
54
|
-
accumulatedDelta = nextDelta;
|
|
55
|
-
}
|
|
56
|
-
for (const [index, line] of lines.entries()) {
|
|
217
|
+
for (const line of lines) {
|
|
57
218
|
if (line.startsWith("-")) {
|
|
58
219
|
oldText.push(line.slice(1));
|
|
59
|
-
removed++;
|
|
60
220
|
}
|
|
61
221
|
else if (line.startsWith("+")) {
|
|
62
222
|
newText.push(line.slice(1));
|
|
63
|
-
added++;
|
|
64
223
|
}
|
|
65
|
-
else if (line ===
|
|
66
|
-
const previousLine = lines[index - 1];
|
|
67
|
-
if (typeof previousLine !== "string" ||
|
|
68
|
-
(!previousLine.startsWith("-") &&
|
|
69
|
-
!previousLine.startsWith("+") &&
|
|
70
|
-
!previousLine.startsWith(" "))) {
|
|
71
|
-
validEofMarkers = false;
|
|
72
|
-
}
|
|
224
|
+
else if (line === NO_NEWLINE_MARKER) {
|
|
73
225
|
continue;
|
|
74
226
|
}
|
|
75
227
|
else {
|
|
76
|
-
if (!line.startsWith(" "))
|
|
77
|
-
validPrefixes = false;
|
|
78
228
|
oldText.push(line.slice(1));
|
|
79
229
|
newText.push(line.slice(1));
|
|
80
230
|
}
|
|
@@ -86,13 +236,6 @@ export function toolUpdateFromDiffToolResponse(toolResponse) {
|
|
|
86
236
|
path: response.filePath,
|
|
87
237
|
oldText: oldText.join("\n") || null,
|
|
88
238
|
newText: newText.join("\n"),
|
|
89
|
-
...(validCoordinates &&
|
|
90
|
-
validPrefixes &&
|
|
91
|
-
validEofMarkers &&
|
|
92
|
-
oldText.length === oldLines &&
|
|
93
|
-
newText.length === newLines
|
|
94
|
-
? { _meta: withAirMeta(undefined, AIR_DIFF_STATS_KEY, { version: 1, added, removed }) }
|
|
95
|
-
: {}),
|
|
96
239
|
});
|
|
97
240
|
}
|
|
98
241
|
}
|
|
@@ -104,7 +247,9 @@ export function toolUpdateFromDiffToolResponse(toolResponse) {
|
|
|
104
247
|
// of a large existing file would render as creating it. Emit a truthful
|
|
105
248
|
// replacement instead. Gated on `type` so Edit (whose output carries no
|
|
106
249
|
// `type` and whose optimistic old/new diff is already truthful) keeps the
|
|
107
|
-
// empty-return behavior.
|
|
250
|
+
// empty-return behavior. A `create` needs nothing here: the
|
|
251
|
+
// tool_use-time diff shows the created file, and a client with diffPatch
|
|
252
|
+
// gets it from the Write reporter.
|
|
108
253
|
if (content.length === 0 && response.type === "update" && typeof response.content === "string") {
|
|
109
254
|
locations.push({ path: response.filePath });
|
|
110
255
|
content.push(typeof response.originalFile === "string"
|
|
@@ -129,3 +274,229 @@ export function toolUpdateFromDiffToolResponse(toolResponse) {
|
|
|
129
274
|
result.locations = locations;
|
|
130
275
|
return result;
|
|
131
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* The text of one git patch for `filePath`.
|
|
279
|
+
*
|
|
280
|
+
* The headers follow `git diff`: the path loses its leading slash, gets the
|
|
281
|
+
* `a/` and `b/` prefixes, and is quoted when git would quote it. A created
|
|
282
|
+
* file gets its mode line and a `/dev/null` side.
|
|
283
|
+
*/
|
|
284
|
+
export function gitPatchText(filePath, change, hunks) {
|
|
285
|
+
return [
|
|
286
|
+
...gitPatchHeader(filePath, change),
|
|
287
|
+
...hunks.flatMap((hunk) => [hunkHeader(hunk), ...hunk.lines]),
|
|
288
|
+
"",
|
|
289
|
+
].join("\n");
|
|
290
|
+
}
|
|
291
|
+
function gitPatchHeader(filePath, change) {
|
|
292
|
+
// git drops one leading slash of an absolute path; a Windows path gets
|
|
293
|
+
// forward slashes so the header names the same file on every platform.
|
|
294
|
+
const name = filePath.replaceAll("\\", "/").replace(/^\/+/u, "");
|
|
295
|
+
const oldName = quoteGitPath("a/", name);
|
|
296
|
+
const newName = quoteGitPath("b/", name);
|
|
297
|
+
// git ends a ---/+++ name that contains a space with a tab, for GNU patch.
|
|
298
|
+
const tab = name.includes(" ") ? "\t" : "";
|
|
299
|
+
return [
|
|
300
|
+
`diff --git ${oldName} ${newName}`,
|
|
301
|
+
...(change === "create" ? ["new file mode 100644"] : []),
|
|
302
|
+
`--- ${change === "create" ? "/dev/null" : `${oldName}${tab}`}`,
|
|
303
|
+
`+++ ${newName}${tab}`,
|
|
304
|
+
];
|
|
305
|
+
}
|
|
306
|
+
const GIT_PATH_ESCAPES = {
|
|
307
|
+
0x07: "a",
|
|
308
|
+
0x08: "b",
|
|
309
|
+
0x09: "t",
|
|
310
|
+
0x0a: "n",
|
|
311
|
+
0x0b: "v",
|
|
312
|
+
0x0c: "f",
|
|
313
|
+
0x0d: "r",
|
|
314
|
+
0x22: '"',
|
|
315
|
+
0x5c: "\\",
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* Quotes `prefix + name` like git with the default `core.quotePath`.
|
|
319
|
+
*
|
|
320
|
+
* A double quote, a backslash, a control byte, or a non-ASCII byte makes git
|
|
321
|
+
* put the whole name in double quotes. git then writes a C escape or a
|
|
322
|
+
* three-digit octal escape for each such UTF-8 byte.
|
|
323
|
+
*/
|
|
324
|
+
function quoteGitPath(prefix, name) {
|
|
325
|
+
const full = `${prefix}${name}`;
|
|
326
|
+
let quoted = "";
|
|
327
|
+
let needsQuotes = false;
|
|
328
|
+
for (const byte of Buffer.from(full, "utf8")) {
|
|
329
|
+
const escape = GIT_PATH_ESCAPES[byte];
|
|
330
|
+
if (escape !== undefined) {
|
|
331
|
+
quoted += `\\${escape}`;
|
|
332
|
+
needsQuotes = true;
|
|
333
|
+
}
|
|
334
|
+
else if (byte < 0x20 || byte >= 0x7f) {
|
|
335
|
+
quoted += `\\${byte.toString(8).padStart(3, "0")}`;
|
|
336
|
+
needsQuotes = true;
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
quoted += String.fromCharCode(byte);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return needsQuotes ? `"${quoted}"` : full;
|
|
343
|
+
}
|
|
344
|
+
function hunkHeader({ oldStart, oldLines, newStart, newLines }) {
|
|
345
|
+
return `@@ -${hunkRange(oldStart, oldLines)} +${hunkRange(newStart, newLines)} @@`;
|
|
346
|
+
}
|
|
347
|
+
/** A git hunk range. A side with zero lines names the line before the change. */
|
|
348
|
+
function hunkRange(start, count) {
|
|
349
|
+
if (count === 0)
|
|
350
|
+
return `${Math.max(0, start - 1)},0`;
|
|
351
|
+
return count === 1 ? String(start) : `${start},${count}`;
|
|
352
|
+
}
|
|
353
|
+
/** The hunk that adds every line of `text` to an empty file. */
|
|
354
|
+
function wholeFileHunk(text) {
|
|
355
|
+
if (text.length === 0)
|
|
356
|
+
return undefined;
|
|
357
|
+
const terminated = text.endsWith("\n");
|
|
358
|
+
const lines = (terminated ? text.slice(0, -1) : text).split("\n");
|
|
359
|
+
return {
|
|
360
|
+
oldStart: 1,
|
|
361
|
+
oldLines: 0,
|
|
362
|
+
newStart: 1,
|
|
363
|
+
newLines: lines.length,
|
|
364
|
+
lines: [...lines.map((line) => `+${line}`), ...(terminated ? [] : [NO_NEWLINE_MARKER])],
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* The line-diff hunks between two texts. Returns undefined when the diff runs
|
|
369
|
+
* out of its time budget.
|
|
370
|
+
*/
|
|
371
|
+
function diffHunks(oldText, newText) {
|
|
372
|
+
if (oldText === null) {
|
|
373
|
+
const hunk = wholeFileHunk(newText);
|
|
374
|
+
return hunk ? [hunk] : [];
|
|
375
|
+
}
|
|
376
|
+
const oldLines = textLines(oldText);
|
|
377
|
+
const newLines = textLines(newText);
|
|
378
|
+
// The diff gets only the changed middle and its context lines. An edit
|
|
379
|
+
// usually changes a small part of a large file.
|
|
380
|
+
const common = Math.min(oldLines.length, newLines.length);
|
|
381
|
+
let prefix = 0;
|
|
382
|
+
while (prefix < common && oldLines[prefix] === newLines[prefix])
|
|
383
|
+
prefix++;
|
|
384
|
+
let suffix = 0;
|
|
385
|
+
while (suffix < common - prefix &&
|
|
386
|
+
oldLines[oldLines.length - 1 - suffix] === newLines[newLines.length - 1 - suffix]) {
|
|
387
|
+
suffix++;
|
|
388
|
+
}
|
|
389
|
+
const skipped = Math.max(0, prefix - PATCH_CONTEXT_LINES);
|
|
390
|
+
const skippedEnd = Math.max(0, suffix - PATCH_CONTEXT_LINES);
|
|
391
|
+
const patch = structuredPatch("", "", oldLines.slice(skipped, oldLines.length - skippedEnd).join(""), newLines.slice(skipped, newLines.length - skippedEnd).join(""), "", "", { context: PATCH_CONTEXT_LINES, timeout: PATCH_DIFF_TIMEOUT_MS });
|
|
392
|
+
return patch?.hunks.map((hunk) => ({
|
|
393
|
+
...hunk,
|
|
394
|
+
oldStart: hunk.oldStart + skipped,
|
|
395
|
+
newStart: hunk.newStart + skipped,
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
398
|
+
/** The lines of a text, each with its line break. The last line can have none. */
|
|
399
|
+
function textLines(text) {
|
|
400
|
+
return text.match(/[^\n]*\n|[^\n]+$/g) ?? [];
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* The git patch of a file change and its hunks. Returns undefined when
|
|
404
|
+
* nothing changed or the diff runs out of its time budget.
|
|
405
|
+
*/
|
|
406
|
+
function filePatch(filePath, oldText, newText) {
|
|
407
|
+
const hunks = diffHunks(oldText, newText);
|
|
408
|
+
if (!hunks || hunks.length === 0)
|
|
409
|
+
return undefined;
|
|
410
|
+
const change = oldText === null ? "create" : "update";
|
|
411
|
+
return { content: patchContent(filePath, gitPatchText(filePath, change, hunks)), hunks };
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Reads a file as patch input.
|
|
415
|
+
*
|
|
416
|
+
* Returns null when the file does not exist. Returns undefined when the file
|
|
417
|
+
* cannot be read, is not a regular file, is larger than
|
|
418
|
+
* {@link MAX_PATCH_FILE_BYTES}, is binary, is not valid UTF-8, or contains a
|
|
419
|
+
* CR.
|
|
420
|
+
*/
|
|
421
|
+
async function readPatchSource(filePath) {
|
|
422
|
+
let handle;
|
|
423
|
+
try {
|
|
424
|
+
// O_NONBLOCK keeps the open of a FIFO from waiting for a writer. It does not change a regular file.
|
|
425
|
+
handle = await open(filePath, constants.O_RDONLY | constants.O_NONBLOCK);
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
return isMissingFileError(error) ? null : undefined;
|
|
429
|
+
}
|
|
430
|
+
try {
|
|
431
|
+
// The checks and the read use one open file, so a swap of the path between them has no effect.
|
|
432
|
+
const stats = await handle.stat();
|
|
433
|
+
if (!stats.isFile() || stats.size > MAX_PATCH_FILE_BYTES)
|
|
434
|
+
return undefined;
|
|
435
|
+
// One byte more than the checked size shows a file that grew after the check.
|
|
436
|
+
const buffer = Buffer.alloc(stats.size + 1);
|
|
437
|
+
let length = 0;
|
|
438
|
+
while (length < buffer.length) {
|
|
439
|
+
const { bytesRead } = await handle.read(buffer, length, buffer.length - length, length);
|
|
440
|
+
if (bytesRead === 0)
|
|
441
|
+
break;
|
|
442
|
+
length += bytesRead;
|
|
443
|
+
}
|
|
444
|
+
if (length > stats.size)
|
|
445
|
+
return undefined;
|
|
446
|
+
const text = decodeFileText(buffer.subarray(0, length));
|
|
447
|
+
return text?.includes("\r") ? undefined : text;
|
|
448
|
+
}
|
|
449
|
+
catch {
|
|
450
|
+
return undefined;
|
|
451
|
+
}
|
|
452
|
+
finally {
|
|
453
|
+
await handle.close();
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/** The text of a file of at most {@link MAX_PATCH_FILE_BYTES} that is not binary and is valid UTF-8. */
|
|
457
|
+
function decodeFileText(bytes) {
|
|
458
|
+
if (bytes.length > MAX_PATCH_FILE_BYTES)
|
|
459
|
+
return undefined;
|
|
460
|
+
if (bytes.subarray(0, BINARY_SNIFF_BYTES).includes(0))
|
|
461
|
+
return undefined;
|
|
462
|
+
try {
|
|
463
|
+
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
464
|
+
}
|
|
465
|
+
catch {
|
|
466
|
+
return undefined;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
/** Whether a tool input text can be the new side of an exact patch. */
|
|
470
|
+
function isPatchableText(text) {
|
|
471
|
+
return (Buffer.byteLength(text, "utf8") <= MAX_PATCH_FILE_BYTES &&
|
|
472
|
+
!text.includes("\0") &&
|
|
473
|
+
!text.includes("\r"));
|
|
474
|
+
}
|
|
475
|
+
function optionalContent(content) {
|
|
476
|
+
return content ? [content] : undefined;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* A diff block in the AIR patch form.
|
|
480
|
+
*
|
|
481
|
+
* `oldText: null` and `newText: ""` only satisfy the ACP schema. The adapter
|
|
482
|
+
* sends this form only to a client that advertised `diffPatch`.
|
|
483
|
+
*/
|
|
484
|
+
function patchContent(filePath, text) {
|
|
485
|
+
return {
|
|
486
|
+
type: "diff",
|
|
487
|
+
path: filePath,
|
|
488
|
+
oldText: null,
|
|
489
|
+
newText: "",
|
|
490
|
+
_meta: withAirMeta(undefined, AIR_DIFF_PATCH_CAPABILITY, {
|
|
491
|
+
version: 1,
|
|
492
|
+
format: "git_patch",
|
|
493
|
+
text,
|
|
494
|
+
}),
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function resolveToolPath(filePath, cwd) {
|
|
498
|
+
return path.isAbsolute(filePath) ? filePath : path.resolve(cwd ?? process.cwd(), filePath);
|
|
499
|
+
}
|
|
500
|
+
function isMissingFileError(error) {
|
|
501
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
502
|
+
}
|
package/dist/elicitation.d.ts
CHANGED
|
@@ -63,7 +63,7 @@ export declare function extractAskUserQuestions(input: Record<string, unknown>):
|
|
|
63
63
|
* marked required, so the user can also just skip — matching the built-in tool,
|
|
64
64
|
* which always offers Skip + a free-text box.
|
|
65
65
|
*/
|
|
66
|
-
export declare function askUserQuestionsToCreateRequest(questions: AskUserQuestion[], sessionId: string, toolCallId: string | undefined): CreateElicitationRequest;
|
|
66
|
+
export declare function askUserQuestionsToCreateRequest(questions: AskUserQuestion[], sessionId: string, toolCallId: string | undefined, airClient?: boolean): CreateElicitationRequest;
|
|
67
67
|
/** Outcome of an AskUserQuestion elicitation, decoupled from any transport. */
|
|
68
68
|
export type AskUserQuestionOutcome = {
|
|
69
69
|
action: "answered";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../src/elicitation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EACV,wBAAwB,EAKzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,6CAA6C,CAAC;
|
|
1
|
+
{"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../src/elicitation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EACV,wBAAwB,EAKzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,6CAA6C,CAAC;AAGrD;;;;;;;;;;;;;GAaG;AAEH,yDAAyD;AACzD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,GAChB,wBAAwB,GAAG,IAAI,CAyBjC;AAgBD;;;GAGG;AACH,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,yBAAyB,GAClC,iBAAiB,CAUnB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,GAAG,IAAI,CAUhG;AAwBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,eAAe,EAAE,EAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,SAAS,UAAQ,GAChB,wBAAwB,CAiE1B;AAED,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAChC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAevF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,yBAAyB,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,SAAS,EAAE,eAAe,EAAE,GAC3B,sBAAsB,CAgExB;AAgBD;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,4BAA4B,CAAC;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,qBAAqB,GAAG,IAAI,CAW9B;AAYD;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,qBAAqB,EAC7B,SAAS,EAAE,MAAM,GAChB,wBAAwB,CA+B1B;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,yBAAyB,GAAG,MAAM,CAG7F"}
|
package/dist/elicitation.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { CreateElicitationResponse } from "@agentclientprotocol/sdk";
|
|
3
|
+
import { AIR_CUSTOM_ANSWER_KEY, withAirMeta } from "./air-extension.js";
|
|
3
4
|
/**
|
|
4
5
|
* Convert an MCP elicitation request (from the SDK's `onElicitation` callback)
|
|
5
6
|
* into an ACP `CreateElicitationRequest`. Returns `null` when the request can't
|
|
@@ -89,13 +90,6 @@ function questionCustomFieldKey(index) {
|
|
|
89
90
|
* extensions (`_claude/...`).
|
|
90
91
|
*/
|
|
91
92
|
const OPTION_META_KEY = "_claude/askUserQuestionOption";
|
|
92
|
-
/**
|
|
93
|
-
* Shared `_meta` key for marking a per-question free-text field as the custom
|
|
94
|
-
* answer companion for a select question. This intentionally has no
|
|
95
|
-
* agent-specific namespace so ACP clients can recognize the same marker across
|
|
96
|
-
* Codex, Claude, and other AskUserQuestion bridges.
|
|
97
|
-
*/
|
|
98
|
-
const CUSTOM_ANSWER_META_KEY = "_askUserQuestionCustomAnswer";
|
|
99
93
|
/**
|
|
100
94
|
* Render the AskUserQuestion tool's questions as an ACP form elicitation.
|
|
101
95
|
*
|
|
@@ -114,7 +108,7 @@ const CUSTOM_ANSWER_META_KEY = "_askUserQuestionCustomAnswer";
|
|
|
114
108
|
* marked required, so the user can also just skip — matching the built-in tool,
|
|
115
109
|
* which always offers Skip + a free-text box.
|
|
116
110
|
*/
|
|
117
|
-
export function askUserQuestionsToCreateRequest(questions, sessionId, toolCallId) {
|
|
111
|
+
export function askUserQuestionsToCreateRequest(questions, sessionId, toolCallId, airClient = false) {
|
|
118
112
|
const single = questions.length === 1;
|
|
119
113
|
const properties = {};
|
|
120
114
|
questions.forEach((question, index) => {
|
|
@@ -148,12 +142,16 @@ export function askUserQuestionsToCreateRequest(questions, sessionId, toolCallId
|
|
|
148
142
|
description: question.multiSelect
|
|
149
143
|
? "Type your own answer to add to your selection above (optional)."
|
|
150
144
|
: "Type your own answer, or add a note to the option you chose above (optional).",
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
145
|
+
// Marks the field as the custom answer companion of a select question,
|
|
146
|
+
// under `_meta.jetbrains.air.customAnswer`. Only AIR gets the marker.
|
|
147
|
+
...(airClient
|
|
148
|
+
? {
|
|
149
|
+
_meta: withAirMeta(undefined, AIR_CUSTOM_ANSWER_KEY, {
|
|
150
|
+
questionId: questionFieldKey(index),
|
|
151
|
+
isCustomAnswer: true,
|
|
152
|
+
}),
|
|
153
|
+
}
|
|
154
|
+
: {}),
|
|
157
155
|
};
|
|
158
156
|
});
|
|
159
157
|
const requestedSchema = {
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
*/
|
|
33
33
|
import { RequestError } from "@agentclientprotocol/sdk";
|
|
34
34
|
import type { AccountInfo, Query } from "@anthropic-ai/claude-agent-sdk";
|
|
35
|
-
import type { SessionFailureController } from "./session-failure-extension.js";
|
|
36
35
|
export declare function shouldHideClaudeAuth(): boolean;
|
|
37
36
|
/**
|
|
38
37
|
* `data.reason` carried by the `authRequired` JSON-RPC error when the flag
|
|
@@ -84,7 +83,7 @@ export declare function claudeSubscriptionNotSupportedError(): RequestError;
|
|
|
84
83
|
export declare function claudeLoginRequiredError(): RequestError;
|
|
85
84
|
/**
|
|
86
85
|
* The state the guard keeps for one session. It lives on the session so that a
|
|
87
|
-
* concurrent pair of turns shares one account read
|
|
86
|
+
* concurrent pair of turns shares one account read, and so
|
|
88
87
|
* that each degraded-guard warning is logged once.
|
|
89
88
|
*/
|
|
90
89
|
export type ClaudeSubscriptionGuardState = {
|
|
@@ -112,8 +111,6 @@ type GuardOptions = {
|
|
|
112
111
|
sessionId: string;
|
|
113
112
|
query: Pick<Query, "accountInfo">;
|
|
114
113
|
guardState: ClaudeSubscriptionGuardState;
|
|
115
|
-
/** Built lazily: most turns pass and never need a controller. */
|
|
116
|
-
sessionFailures: () => SessionFailureController;
|
|
117
114
|
logger: GuardLogger;
|
|
118
115
|
/** Display hook: called with the account the guard just read, before the
|
|
119
116
|
* guard decides on it. It exists so a refused turn still reports which
|
|
@@ -140,8 +137,7 @@ type GuardOptions = {
|
|
|
140
137
|
* mid-session. The refusal mirrors the signed-out path exactly (see
|
|
141
138
|
* `failActiveWithSessionFailure` for `auth_required` in `acp-agent.ts`): every
|
|
142
139
|
* client gets the `authRequired` JSON-RPC rejection that starts its own auth
|
|
143
|
-
* flow
|
|
144
|
-
* failure whose `login` action stays the way back in.
|
|
140
|
+
* flow. The guard sends no separate access message.
|
|
145
141
|
*
|
|
146
142
|
* Fails open when no account can be read at all: session creation already
|
|
147
143
|
* refused every account without a usable credential, and an unavailable probe
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hide-claude-auth.d.ts","sourceRoot":"","sources":["../src/hide-claude-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"hide-claude-auth.d.ts","sourceRoot":"","sources":["../src/hide-claude-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAEzE,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED;;;;;;GAMG;AACH,eAAO,MAAM,wCAAwC,sCAAsC,CAAC;AAC5F,MAAM,MAAM,kBAAkB,GAAG,OAAO,wCAAwC,CAAC;AAEjF,eAAO,MAAM,yCAAyC,qEACc,CAAC;AAErE;;qEAEqE;AACrE,eAAO,MAAM,6BAA6B,0EAC+B,CAAC;AAmB1E;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAWjF;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAWxF;AAED,wBAAgB,mCAAmC,IAAI,YAAY,CAKlE;AAED;oEACoE;AACpE,wBAAgB,wBAAwB,IAAI,YAAY,CAEvD;AAED;;;;GAIG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,6DAA6D;IAC7D,UAAU,CAAC,EAAE,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;IAC/C,8EAA8E;IAC9E,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACpC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACrC,CAAC;AAMF;;;;GAIG;AACH,wBAAgB,mCAAmC,CAAC,OAAO,EAAE;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,4BAA4B,CAAC;IACzC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,IAAI,CAWP;AAED,KAAK,YAAY,GAAG;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IAClC,UAAU,EAAE,4BAA4B,CAAC;IACzC,MAAM,EAAE,WAAW,CAAC;IACpB;;;;+BAI2B;IAC3B,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CAC5C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,4BAA4B,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAavF"}
|