@quantiya/codevibe-antigravity-plugin 2.0.102 → 2.0.103
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/dist/agy-hook.js +56 -18
- package/dist/server.js +150 -19
- package/package.json +1 -1
package/dist/agy-hook.js
CHANGED
|
@@ -100,8 +100,32 @@ function decodeBoolean(val) {
|
|
|
100
100
|
if (typeof val === "number") return val !== 0;
|
|
101
101
|
return false;
|
|
102
102
|
}
|
|
103
|
+
function sliceToSerializedBudget(rawText, buildCandidate, maxChars) {
|
|
104
|
+
if (maxChars <= 0) return null;
|
|
105
|
+
const emptyCandidate = buildCandidate("");
|
|
106
|
+
if (emptyCandidate.length > maxChars) {
|
|
107
|
+
return "[]".length <= maxChars ? "[]" : null;
|
|
108
|
+
}
|
|
109
|
+
const fullCandidate = buildCandidate(rawText);
|
|
110
|
+
if (fullCandidate.length <= maxChars) return fullCandidate;
|
|
111
|
+
let low = 0;
|
|
112
|
+
let high = rawText.length;
|
|
113
|
+
let best = emptyCandidate;
|
|
114
|
+
while (low <= high) {
|
|
115
|
+
const mid = low + high >>> 1;
|
|
116
|
+
const candidate = buildCandidate(rawText.slice(0, mid));
|
|
117
|
+
if (candidate.length <= maxChars) {
|
|
118
|
+
best = candidate;
|
|
119
|
+
low = mid + 1;
|
|
120
|
+
} else {
|
|
121
|
+
high = mid - 1;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return best;
|
|
125
|
+
}
|
|
103
126
|
function serializeStructuredArg(value, maxChars = MAX_STRUCTURED_ARG_CHARS, keyHint) {
|
|
104
127
|
try {
|
|
128
|
+
if (maxChars <= 0) return null;
|
|
105
129
|
let parsed = value;
|
|
106
130
|
if (typeof value === "string") {
|
|
107
131
|
const trimmed = value.trim();
|
|
@@ -121,15 +145,15 @@ function serializeStructuredArg(value, maxChars = MAX_STRUCTURED_ARG_CHARS, keyH
|
|
|
121
145
|
);
|
|
122
146
|
if (isOptionArray) {
|
|
123
147
|
const boundedOptions = parsed.slice(0, 30).map((opt, idx) => {
|
|
124
|
-
if (typeof opt === "string") return { number: String(idx + 1), text: opt
|
|
148
|
+
if (typeof opt === "string") return { number: String(idx + 1), text: opt };
|
|
125
149
|
if (typeof opt === "number") return { number: String(idx + 1), text: String(opt) };
|
|
126
150
|
if (opt && typeof opt === "object") {
|
|
127
151
|
const optObj = opt;
|
|
128
152
|
const num = typeof optObj.number !== "undefined" ? String(optObj.number).slice(0, 16) : String(idx + 1);
|
|
129
|
-
const txt = typeof optObj.text === "string" ? optObj.text
|
|
153
|
+
const txt = typeof optObj.text === "string" ? optObj.text : String(optObj.text ?? optObj.label ?? optObj.value ?? "");
|
|
130
154
|
return { number: num, text: txt };
|
|
131
155
|
}
|
|
132
|
-
return { number: String(idx + 1), text: String(opt ?? "")
|
|
156
|
+
return { number: String(idx + 1), text: String(opt ?? "") };
|
|
133
157
|
});
|
|
134
158
|
const str2 = JSON.stringify(boundedOptions);
|
|
135
159
|
if (str2.length <= maxChars) return str2;
|
|
@@ -139,38 +163,41 @@ function serializeStructuredArg(value, maxChars = MAX_STRUCTURED_ARG_CHARS, keyH
|
|
|
139
163
|
}
|
|
140
164
|
const firstOpt = boundedOptions[0];
|
|
141
165
|
if (firstOpt) {
|
|
142
|
-
|
|
143
|
-
|
|
166
|
+
return sliceToSerializedBudget(
|
|
167
|
+
firstOpt.text,
|
|
168
|
+
(safeText) => JSON.stringify([{ number: firstOpt.number, text: safeText }]),
|
|
169
|
+
maxChars
|
|
170
|
+
);
|
|
144
171
|
}
|
|
145
|
-
return
|
|
172
|
+
return "[]".length <= maxChars ? "[]" : null;
|
|
146
173
|
}
|
|
147
174
|
const bounded = parsed.slice(0, 20).map((item) => {
|
|
148
|
-
if (typeof item === "string") return { question: item
|
|
175
|
+
if (typeof item === "string") return { question: item, options: [] };
|
|
149
176
|
if (item && typeof item === "object") {
|
|
150
177
|
const res = {};
|
|
151
178
|
const obj = item;
|
|
152
|
-
if (typeof obj.question === "string") res.question = obj.question
|
|
179
|
+
if (typeof obj.question === "string") res.question = obj.question;
|
|
153
180
|
if (typeof obj.is_multi_select !== "undefined") res.is_multi_select = decodeBoolean(obj.is_multi_select);
|
|
154
181
|
if (typeof obj.isMultiSelect !== "undefined") res.isMultiSelect = decodeBoolean(obj.isMultiSelect);
|
|
155
182
|
if (Array.isArray(obj.options)) {
|
|
156
|
-
res.options = obj.options.slice(0, 25).map((opt
|
|
157
|
-
if (typeof opt === "string") return opt
|
|
183
|
+
res.options = obj.options.slice(0, 25).map((opt) => {
|
|
184
|
+
if (typeof opt === "string") return opt;
|
|
158
185
|
if (typeof opt === "number") return String(opt);
|
|
159
186
|
if (opt && typeof opt === "object") {
|
|
160
187
|
const optObj = opt;
|
|
161
188
|
return {
|
|
162
189
|
...typeof optObj.number !== "undefined" ? { number: String(optObj.number).slice(0, 16) } : {},
|
|
163
|
-
text: typeof optObj.text === "string" ? optObj.text
|
|
190
|
+
text: typeof optObj.text === "string" ? optObj.text : String(optObj.text ?? optObj.label ?? optObj.value ?? "")
|
|
164
191
|
};
|
|
165
192
|
}
|
|
166
|
-
return String(opt ?? "")
|
|
193
|
+
return String(opt ?? "");
|
|
167
194
|
});
|
|
168
195
|
}
|
|
169
196
|
return res;
|
|
170
197
|
}
|
|
171
|
-
return { question: String(item)
|
|
198
|
+
return { question: String(item), options: [] };
|
|
172
199
|
});
|
|
173
|
-
|
|
200
|
+
const str = JSON.stringify(bounded);
|
|
174
201
|
if (str.length <= maxChars) return str;
|
|
175
202
|
for (let i = bounded.length - 1; i >= 1; i--) {
|
|
176
203
|
const sub = JSON.stringify(bounded.slice(0, i));
|
|
@@ -178,11 +205,20 @@ function serializeStructuredArg(value, maxChars = MAX_STRUCTURED_ARG_CHARS, keyH
|
|
|
178
205
|
}
|
|
179
206
|
const firstQ = bounded[0];
|
|
180
207
|
if (firstQ && typeof firstQ === "object") {
|
|
181
|
-
const
|
|
182
|
-
const
|
|
183
|
-
|
|
208
|
+
const qObj = firstQ;
|
|
209
|
+
const qText = typeof qObj.question === "string" ? qObj.question : "";
|
|
210
|
+
const opts = Array.isArray(qObj.options) ? qObj.options : [];
|
|
211
|
+
for (let k = opts.length - 1; k >= 1; k--) {
|
|
212
|
+
const subQ = JSON.stringify([{ ...qObj, options: opts.slice(0, k) }]);
|
|
213
|
+
if (subQ.length <= maxChars) return subQ;
|
|
214
|
+
}
|
|
215
|
+
return sliceToSerializedBudget(
|
|
216
|
+
qText,
|
|
217
|
+
(safeQText) => JSON.stringify([{ question: safeQText, options: [] }]),
|
|
218
|
+
maxChars
|
|
219
|
+
);
|
|
184
220
|
}
|
|
185
|
-
return
|
|
221
|
+
return "[]".length <= maxChars ? "[]" : null;
|
|
186
222
|
}
|
|
187
223
|
if (parsed && typeof parsed === "object") {
|
|
188
224
|
const raw = JSON.stringify(parsed);
|
|
@@ -216,6 +252,8 @@ function buildBody(raw) {
|
|
|
216
252
|
if (key === "questions" || key === "options") {
|
|
217
253
|
const serialized = serializeStructuredArg(value, MAX_STRUCTURED_ARG_CHARS, key);
|
|
218
254
|
if (serialized !== null) kept[key] = serialized;
|
|
255
|
+
} else if (key === "question" || key === "prompt") {
|
|
256
|
+
kept[key] = value.slice(0, MAX_STRUCTURED_ARG_CHARS);
|
|
219
257
|
} else {
|
|
220
258
|
kept[key] = value.slice(0, MAX_TOOL_ARG_CHARS);
|
|
221
259
|
}
|
package/dist/server.js
CHANGED
|
@@ -3556,8 +3556,9 @@ function looksLikePromptSnapshot(snapshot) {
|
|
|
3556
3556
|
const allLines = stripped.trimEnd().split("\n");
|
|
3557
3557
|
const fenceMask = computeFenceMask(allLines);
|
|
3558
3558
|
const windowStart = Math.max(0, allLines.length - 30);
|
|
3559
|
+
const questionWindowStart = Math.max(0, allLines.length - 80);
|
|
3559
3560
|
let headerIdx = -1;
|
|
3560
|
-
for (let i = allLines.length - 1; i >=
|
|
3561
|
+
for (let i = allLines.length - 1; i >= questionWindowStart; i--) {
|
|
3561
3562
|
if (!fenceMask[i] && isQuestionHeaderLine(allLines[i])) {
|
|
3562
3563
|
headerIdx = i;
|
|
3563
3564
|
break;
|
|
@@ -3565,9 +3566,16 @@ function looksLikePromptSnapshot(snapshot) {
|
|
|
3565
3566
|
}
|
|
3566
3567
|
if (headerIdx < 0) return false;
|
|
3567
3568
|
const headerLine = allLines[headerIdx].trim();
|
|
3569
|
+
const isTallHeader = headerIdx < windowStart;
|
|
3568
3570
|
const optionIndices = [];
|
|
3569
3571
|
for (let i = headerIdx + 1; i < allLines.length; i++) {
|
|
3570
|
-
if (
|
|
3572
|
+
if (fenceMask[i]) continue;
|
|
3573
|
+
const trimmed = allLines[i].trim();
|
|
3574
|
+
if (!trimmed) continue;
|
|
3575
|
+
if ((isTallHeader || optionIndices.length > 0) && isResumedTurnSignal(trimmed) || isComposerBoxAt(allLines, i) || /^\s*(?:[❯>]\s*)?\?\s+for\s+(?:shortcuts|help|commands|options|keybindings|menu)\b/i.test(trimmed)) {
|
|
3576
|
+
return false;
|
|
3577
|
+
}
|
|
3578
|
+
if (/^(?:[>\s❯]{0,4})[1-9][.)]\s+\S/.test(allLines[i])) {
|
|
3571
3579
|
optionIndices.push(i);
|
|
3572
3580
|
}
|
|
3573
3581
|
}
|
|
@@ -3591,7 +3599,7 @@ function looksLikePromptSnapshot(snapshot) {
|
|
|
3591
3599
|
}
|
|
3592
3600
|
}
|
|
3593
3601
|
}
|
|
3594
|
-
if (!hasQuestionFooter) return false;
|
|
3602
|
+
if (!hasQuestionFooter || footerIdx < windowStart) return false;
|
|
3595
3603
|
if (hasTrailingAgyComposer(allLines, footerIdx, fenceMask)) {
|
|
3596
3604
|
return false;
|
|
3597
3605
|
}
|
|
@@ -4310,6 +4318,38 @@ function detectActivePromptKind(snapshot) {
|
|
|
4310
4318
|
}
|
|
4311
4319
|
if (lastApprovalLineIdx >= 0 && lastQuestionLineIdx >= 0 && lastFileAccessLineIdx >= 0 && lastSystemErrorLineIdx >= 0) break;
|
|
4312
4320
|
}
|
|
4321
|
+
if (lastQuestionLineIdx < 0 && lastApprovalLineIdx < 0 && lastFileAccessLineIdx < 0) {
|
|
4322
|
+
const tallQuestionStart = Math.max(0, lines.length - 80);
|
|
4323
|
+
for (let i = windowStart - 1; i >= tallQuestionStart; i--) {
|
|
4324
|
+
if (lineInFence[i]) continue;
|
|
4325
|
+
if (isQuestionHeaderLine(lines[i])) {
|
|
4326
|
+
let optCount = 0;
|
|
4327
|
+
let footerInBottomWindow = false;
|
|
4328
|
+
let footerIdx = i;
|
|
4329
|
+
let interrupted = false;
|
|
4330
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
4331
|
+
if (lineInFence[j]) continue;
|
|
4332
|
+
const trimmed = lines[j].trim();
|
|
4333
|
+
if (!trimmed) continue;
|
|
4334
|
+
if (approvalRe.test(trimmed) || fileEditQuestionRe.test(trimmed) || fileAccessRe.test(trimmed) || fileAccessQuestionRe.test(trimmed) || /Do you want to proceed\?/i.test(trimmed) || isResumedTurnSignal(trimmed) || isComposerBoxAt(lines, j) || /^\s*(?:[❯>]\s*)?\?\s+for\s+(?:shortcuts|help|commands|options|keybindings|menu)\b/i.test(trimmed)) {
|
|
4335
|
+
interrupted = true;
|
|
4336
|
+
break;
|
|
4337
|
+
}
|
|
4338
|
+
if (/^(?:[>\s❯]{0,4})[1-9][.)]\s+\S/.test(lines[j])) {
|
|
4339
|
+
optCount += 1;
|
|
4340
|
+
} else if (isQuestionFooterLine(trimmed) && j >= windowStart) {
|
|
4341
|
+
footerInBottomWindow = true;
|
|
4342
|
+
footerIdx = j;
|
|
4343
|
+
break;
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4346
|
+
if (!interrupted && optCount >= 2 && footerInBottomWindow && !hasTrailingAgyComposer(lines, footerIdx, lineInFence)) {
|
|
4347
|
+
lastQuestionLineIdx = i;
|
|
4348
|
+
}
|
|
4349
|
+
break;
|
|
4350
|
+
}
|
|
4351
|
+
}
|
|
4352
|
+
}
|
|
4313
4353
|
if (lastApprovalLineIdx < 0 && lastQuestionLineIdx < 0) {
|
|
4314
4354
|
for (let i = lines.length - 1; i >= windowStart; i--) {
|
|
4315
4355
|
if (/Do you want to proceed\?/i.test(lines[i])) {
|
|
@@ -4335,7 +4375,7 @@ function detectActivePromptKind(snapshot) {
|
|
|
4335
4375
|
for (let j = lastSystemErrorLineIdx + 1; j < lines.length; j++) {
|
|
4336
4376
|
if (!lineInFence[j]) {
|
|
4337
4377
|
const trimmed = lines[j].trim();
|
|
4338
|
-
if (hasQuestionOptions && isResumedTurnSignal(trimmed)) {
|
|
4378
|
+
if ((hasQuestionOptions || lastQuestionLineIdx < windowStart) && isResumedTurnSignal(trimmed)) {
|
|
4339
4379
|
break;
|
|
4340
4380
|
}
|
|
4341
4381
|
if (/^[>\s❯]*[1-9][.)]\s+\S/.test(trimmed)) {
|
|
@@ -4389,7 +4429,7 @@ function detectActivePromptKind(snapshot) {
|
|
|
4389
4429
|
if (isAgyStatusFooterLine(trimmed) || /^\s*(?:[❯>]\s*)?\?\s+for\s+(?:shortcuts|help)\b/i.test(trimmed) || isComposerBoxAt(lines, j)) {
|
|
4390
4430
|
break;
|
|
4391
4431
|
}
|
|
4392
|
-
if (hasFoundOptions && isResumedTurnSignal(trimmed)) {
|
|
4432
|
+
if ((hasFoundOptions || lastQuestionLineIdx < windowStart) && isResumedTurnSignal(trimmed)) {
|
|
4393
4433
|
break;
|
|
4394
4434
|
}
|
|
4395
4435
|
if (/^[>\s❯]*[1-9][.)]\s+\S/.test(trimmed)) {
|
|
@@ -4882,7 +4922,8 @@ function buildApprovalSemanticKey(candidate) {
|
|
|
4882
4922
|
body: isDiffBody ? rawBody.trim() : normalize(rawBody),
|
|
4883
4923
|
options: (candidate.options ?? []).map((option) => ({
|
|
4884
4924
|
number: option.number,
|
|
4885
|
-
text: normalize(option.text)
|
|
4925
|
+
text: normalize(option.text),
|
|
4926
|
+
...option.rawLines && option.rawLines.length > 1 ? { rawLines: option.rawLines.map((line) => normalize(line)) } : {}
|
|
4886
4927
|
})),
|
|
4887
4928
|
submitMap: Object.fromEntries(
|
|
4888
4929
|
Object.entries(candidate.submitMap ?? {}).sort(([left], [right]) => Number(left) - Number(right)).map(([number, keys]) => [number, [...keys]])
|
|
@@ -5003,7 +5044,7 @@ function parseQuestionSnapshot(stripped, originalSnapshot, header) {
|
|
|
5003
5044
|
}
|
|
5004
5045
|
}
|
|
5005
5046
|
const belowHeader = headerIdx >= 0 ? lines.slice(headerIdx + 1).join("\n") : stripped;
|
|
5006
|
-
const options = parseOptions(belowHeader);
|
|
5047
|
+
const options = parseOptions(belowHeader, 80);
|
|
5007
5048
|
if (options.length < 2) return null;
|
|
5008
5049
|
const normalizedHeader = header.fullLine.replace(/^[❯>\s*•-]+\s*/, "").trim();
|
|
5009
5050
|
const isMultiSelect = /\bselect\s+(?:all|multiple)\b/i.test(normalizedHeader) || /\bselect\s+(?:all|multiple)\b/i.test(belowHeader) || /(?:<space>|\bspace)\s+(?:to\s+)?(?:select|toggle)\b/i.test(belowHeader) || /\bctrl\+a\s+select\s+all\b/i.test(belowHeader);
|
|
@@ -5024,7 +5065,7 @@ function parseQuestionSnapshot(stripped, originalSnapshot, header) {
|
|
|
5024
5065
|
}
|
|
5025
5066
|
function extractBodyBetweenHeaderAndFirstOption(belowHeader) {
|
|
5026
5067
|
const lines = belowHeader.split("\n");
|
|
5027
|
-
const optionRegex = /^[>\s❯]
|
|
5068
|
+
const optionRegex = /^(?:[>\s❯]{0,4})([1-9])[.)]\s+(.+?)\s*$/;
|
|
5028
5069
|
const lineInFence = computeFenceMask(lines);
|
|
5029
5070
|
let firstOptionIdx = -1;
|
|
5030
5071
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -5037,7 +5078,34 @@ function extractBodyBetweenHeaderAndFirstOption(belowHeader) {
|
|
|
5037
5078
|
if (firstOptionIdx <= 0) return "";
|
|
5038
5079
|
return lines.slice(0, firstOptionIdx).join("\n").trim();
|
|
5039
5080
|
}
|
|
5040
|
-
function
|
|
5081
|
+
function isOptionContinuationBoundary(trimmed, rawLine, nextTrimmedLine) {
|
|
5082
|
+
if (!trimmed) return true;
|
|
5083
|
+
if (/^[•‣◦▪▫]\s/.test(trimmed)) return true;
|
|
5084
|
+
if (/^\s{2,4}[-*]\s/.test(rawLine)) return true;
|
|
5085
|
+
if (isQuestionFooterLine(trimmed)) return true;
|
|
5086
|
+
if (isQuestionHeaderLine(trimmed)) return true;
|
|
5087
|
+
if (isResumedTurnSignal(trimmed)) return true;
|
|
5088
|
+
if (/^[─━═-]{4,}$/.test(trimmed)) return true;
|
|
5089
|
+
if (/^\s*esc to cancel\b/i.test(trimmed)) return true;
|
|
5090
|
+
if (/^(?:↑\/↓|↑|↓|\^|v)\s*(?:\/|\s+)?Navigate\b/i.test(trimmed)) return true;
|
|
5091
|
+
if (/^ctrl\+[a-z0-9]+\s+[a-zA-Z]+$/i.test(trimmed)) return true;
|
|
5092
|
+
if (/^\(?use\s+(?:arrow|\S+)\s+keys[^)]*\)?$/i.test(trimmed)) return true;
|
|
5093
|
+
if (!/^ {5,}/.test(rawLine) && /^Your answer:/i.test(trimmed) && (/^Your answer:\s*$/i.test(trimmed) || Boolean(
|
|
5094
|
+
nextTrimmedLine && (isQuestionFooterLine(nextTrimmedLine) || /^\(?Enter to submit(?:\s*,\s*esc to cancel)?\)?\s*$/i.test(nextTrimmedLine) || /^\s*esc to cancel\b/i.test(nextTrimmedLine))
|
|
5095
|
+
))) {
|
|
5096
|
+
return true;
|
|
5097
|
+
}
|
|
5098
|
+
if (!/^ {5,}/.test(rawLine) && /^\(?Enter to submit(?:\s*,\s*esc to cancel)?\)?\s*$/i.test(trimmed)) {
|
|
5099
|
+
return true;
|
|
5100
|
+
}
|
|
5101
|
+
if (/^\s*(?:[❯>]\s*)?\?\s+for\s+(?:shortcuts|help|commands|options|keybindings|menu)\b/i.test(trimmed)) return true;
|
|
5102
|
+
if (/Requesting permission for:/i.test(trimmed)) return true;
|
|
5103
|
+
if (/Do you want to proceed\?/i.test(trimmed)) return true;
|
|
5104
|
+
if (/^\s*Allow access to this file\?\s*$/i.test(trimmed)) return true;
|
|
5105
|
+
if (/^\s*(?:Accept this file edit\?|Allow creation of this file\?)\s*$/i.test(trimmed)) return true;
|
|
5106
|
+
return false;
|
|
5107
|
+
}
|
|
5108
|
+
function parseOptions(snapshot, maxRecentLines = 30) {
|
|
5041
5109
|
const lines = snapshot.split("\n");
|
|
5042
5110
|
const lineInFence = computeFenceMask(lines);
|
|
5043
5111
|
const filteredLines = [];
|
|
@@ -5049,16 +5117,72 @@ function parseOptions(snapshot) {
|
|
|
5049
5117
|
while (filteredLines.length > 0 && filteredLines[filteredLines.length - 1].trim() === "") {
|
|
5050
5118
|
filteredLines.pop();
|
|
5051
5119
|
}
|
|
5052
|
-
const recent = filteredLines.slice(-30);
|
|
5053
|
-
const optionRegex = /^[>\s❯]
|
|
5120
|
+
const recent = filteredLines.slice(-Math.max(30, maxRecentLines));
|
|
5121
|
+
const optionRegex = /^(?:[>\s❯]{0,4})([1-9])[.)]\s+(.+?)\s*$/;
|
|
5054
5122
|
const found = /* @__PURE__ */ new Map();
|
|
5055
|
-
|
|
5123
|
+
let currentOptionNum = null;
|
|
5124
|
+
let currentOptionTextCol = 5;
|
|
5125
|
+
let prevOptionRawLen = 0;
|
|
5126
|
+
for (let idx = 0; idx < recent.length; idx++) {
|
|
5127
|
+
const line = recent[idx];
|
|
5056
5128
|
const m = line.match(optionRegex);
|
|
5057
|
-
if (
|
|
5058
|
-
|
|
5059
|
-
|
|
5129
|
+
if (m) {
|
|
5130
|
+
const num = m[1];
|
|
5131
|
+
const text = m[2].trim();
|
|
5132
|
+
const prefixMatch = line.match(/^(?:[>\s❯]{0,4})[1-9][.)]\s+/);
|
|
5133
|
+
currentOptionTextCol = prefixMatch ? prefixMatch[0].length : 5;
|
|
5134
|
+
prevOptionRawLen = line.trimEnd().length;
|
|
5135
|
+
found.set(num, {
|
|
5136
|
+
text,
|
|
5137
|
+
rawLines: [text],
|
|
5138
|
+
rawLineLengths: [prevOptionRawLen]
|
|
5139
|
+
});
|
|
5140
|
+
currentOptionNum = /^\s*write-?in(?:\s*(?:\.{3}|…))?\s*$/i.test(text) ? null : num;
|
|
5141
|
+
continue;
|
|
5142
|
+
}
|
|
5143
|
+
const trimmed = line.trim();
|
|
5144
|
+
if (currentOptionNum !== null) {
|
|
5145
|
+
let nextTrimmedLine;
|
|
5146
|
+
for (let k = idx + 1; k < recent.length; k++) {
|
|
5147
|
+
const nt = recent[k].trim();
|
|
5148
|
+
if (nt) {
|
|
5149
|
+
nextTrimmedLine = nt;
|
|
5150
|
+
break;
|
|
5151
|
+
}
|
|
5152
|
+
}
|
|
5153
|
+
const leadingSpaces = (line.match(/^\s*/)?.[0] ?? "").length;
|
|
5154
|
+
const isIndentedContinuation = leadingSpaces >= Math.max(4, currentOptionTextCol);
|
|
5155
|
+
const isColumnZeroWrapContinuation = leadingSpaces === 0;
|
|
5156
|
+
if (isOptionContinuationBoundary(trimmed, line, nextTrimmedLine) || !isIndentedContinuation && !isColumnZeroWrapContinuation) {
|
|
5157
|
+
currentOptionNum = null;
|
|
5158
|
+
} else {
|
|
5159
|
+
const entry = found.get(currentOptionNum);
|
|
5160
|
+
if (entry) {
|
|
5161
|
+
const existing = entry.text;
|
|
5162
|
+
entry.text = existing ? `${existing} ${trimmed}` : trimmed;
|
|
5163
|
+
entry.rawLines.push(trimmed);
|
|
5164
|
+
prevOptionRawLen = line.trimEnd().length;
|
|
5165
|
+
entry.rawLineLengths.push(prevOptionRawLen);
|
|
5166
|
+
}
|
|
5167
|
+
}
|
|
5168
|
+
}
|
|
5060
5169
|
}
|
|
5061
|
-
return Array.from(found.entries()).sort(([a], [b]) => Number(a) - Number(b)).map(([number,
|
|
5170
|
+
return Array.from(found.entries()).sort(([a], [b]) => Number(a) - Number(b)).map(([number, entry]) => {
|
|
5171
|
+
const opt = { number, text: entry.text };
|
|
5172
|
+
if (entry.rawLines.length > 1) {
|
|
5173
|
+
Object.defineProperty(opt, "rawLines", {
|
|
5174
|
+
value: entry.rawLines,
|
|
5175
|
+
enumerable: false,
|
|
5176
|
+
configurable: true
|
|
5177
|
+
});
|
|
5178
|
+
Object.defineProperty(opt, "rawLineLengths", {
|
|
5179
|
+
value: entry.rawLineLengths,
|
|
5180
|
+
enumerable: false,
|
|
5181
|
+
configurable: true
|
|
5182
|
+
});
|
|
5183
|
+
}
|
|
5184
|
+
return opt;
|
|
5185
|
+
});
|
|
5062
5186
|
}
|
|
5063
5187
|
function buildApprovalSubmitMap(options) {
|
|
5064
5188
|
const map = {};
|
|
@@ -5079,10 +5203,11 @@ function isWriteInInputActive(paneText, expectedHeader, expectedStep, expectedBo
|
|
|
5079
5203
|
if (detectActivePromptKind(paneText) !== "question") return false;
|
|
5080
5204
|
const stripped = stripAnsiAndExpandRep(paneText);
|
|
5081
5205
|
const lines = stripped.trimEnd().split("\n");
|
|
5082
|
-
const
|
|
5206
|
+
const fenceMask = computeFenceMask(lines);
|
|
5207
|
+
const windowStart = Math.max(0, lines.length - 80);
|
|
5083
5208
|
let headerIdx = -1;
|
|
5084
5209
|
for (let i = lines.length - 1; i >= windowStart; i--) {
|
|
5085
|
-
if (isQuestionHeaderLine(lines[i])) {
|
|
5210
|
+
if (!fenceMask[i] && isQuestionHeaderLine(lines[i])) {
|
|
5086
5211
|
headerIdx = i;
|
|
5087
5212
|
break;
|
|
5088
5213
|
}
|
|
@@ -5987,10 +6112,13 @@ var ApprovalDetector = class extends import_events3.EventEmitter {
|
|
|
5987
6112
|
this.emit("prompt-upgraded", existing);
|
|
5988
6113
|
return existing;
|
|
5989
6114
|
}
|
|
6115
|
+
const hasPriorPaneObservation = Boolean(existing.paneSemanticKey);
|
|
5990
6116
|
const areControlsMutated = (existingOpts, candidateOpts) => {
|
|
5991
6117
|
if (!existingOpts || !candidateOpts) return false;
|
|
5992
6118
|
if (existingOpts.length !== candidateOpts.length) return true;
|
|
5993
|
-
return !existingOpts.every(
|
|
6119
|
+
return !existingOpts.every(
|
|
6120
|
+
(o, idx) => o.number === candidateOpts[idx].number && (o.text || "").trim() === (candidateOpts[idx].text || "").trim() && (!hasPriorPaneObservation || JSON.stringify(o.rawLines ?? []) === JSON.stringify(candidateOpts[idx].rawLines ?? []))
|
|
6121
|
+
);
|
|
5994
6122
|
};
|
|
5995
6123
|
const isControlDelta = Boolean(
|
|
5996
6124
|
existing.paneOptions && existing.paneOptions.length > 0 && candidate.options && candidate.options.length > 0 && areControlsMutated(existing.paneOptions, candidate.options)
|
|
@@ -6006,6 +6134,9 @@ var ApprovalDetector = class extends import_events3.EventEmitter {
|
|
|
6006
6134
|
} else {
|
|
6007
6135
|
if (!existing.paneSemanticKey) {
|
|
6008
6136
|
existing.paneSemanticKey = candidateSemanticKey;
|
|
6137
|
+
if (candidate.options && candidate.options.length > 0) {
|
|
6138
|
+
existing.paneOptions = candidate.options;
|
|
6139
|
+
}
|
|
6009
6140
|
}
|
|
6010
6141
|
if (stepLineMatch) {
|
|
6011
6142
|
existing.matchedPaneHeader = stepLineMatch.stitchedHeaderText;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quantiya/codevibe-antigravity-plugin",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.103",
|
|
4
4
|
"description": "Control Antigravity CLI from your iPhone and Android — real-time sync, approve file edits, send prompts by voice. Part of CodeVibe.",
|
|
5
5
|
"main": "dist/server.js",
|
|
6
6
|
"codevibe": {
|