@anypal/plugin-git 0.0.0-stage → 0.1.1

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/index.cjs ADDED
@@ -0,0 +1,3233 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key2 of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key2) && key2 !== except)
15
+ __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var stdin_exports = {};
29
+ __export(stdin_exports, {
30
+ activate: () => activate2,
31
+ deactivate: () => deactivate
32
+ });
33
+ module.exports = __toCommonJS(stdin_exports);
34
+ var import_node_async_hooks = require("node:async_hooks");
35
+ var local = __toESM(require("node:fs/promises"));
36
+ var import_node_path = __toESM(require("node:path"));
37
+ var import_node_async_hooks2 = require("node:async_hooks");
38
+ var import_diff = require("diff");
39
+ var import_node_path2 = __toESM(require("node:path"));
40
+ var import_node_crypto = require("node:crypto");
41
+ var import_promises = require("node:fs/promises");
42
+ var import_diff2 = require("diff");
43
+ var __create2 = Object.create;
44
+ var __defProp2 = Object.defineProperty;
45
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
46
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
47
+ var __getProtoOf2 = Object.getPrototypeOf;
48
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
49
+ var __commonJS = (cb, mod) => function __require() {
50
+ return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
51
+ };
52
+ var __export2 = (target, all) => {
53
+ for (var name in all)
54
+ __defProp2(target, name, { get: all[name], enumerable: true });
55
+ };
56
+ var __copyProps2 = (to, from, except, desc) => {
57
+ if (from && typeof from === "object" || typeof from === "function") {
58
+ for (let key2 of __getOwnPropNames2(from))
59
+ if (!__hasOwnProp2.call(to, key2) && key2 !== except)
60
+ __defProp2(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc2(from, key2)) || desc.enumerable });
61
+ }
62
+ return to;
63
+ };
64
+ var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps2(
65
+ // If the importer is in node compatibility mode or this is not an ESM
66
+ // file that has been converted to a CommonJS file using a Babel-
67
+ // compatible transform (i.e. "__esModule" has not been set), then set
68
+ // "default" to the CommonJS "module.exports" for node compatibility.
69
+ isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
70
+ mod
71
+ ));
72
+ var require_ipaddr = __commonJS({
73
+ "../../node_modules/ipaddr.js/lib/ipaddr.js"(exports, module2) {
74
+ (function(root) {
75
+ "use strict";
76
+ const ipv4Part = "(0?\\d+|0x[a-f0-9]+)";
77
+ const ipv4Regexes = {
78
+ fourOctet: new RegExp(`^${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}$`, "i"),
79
+ threeOctet: new RegExp(`^${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}$`, "i"),
80
+ twoOctet: new RegExp(`^${ipv4Part}\\.${ipv4Part}$`, "i"),
81
+ longValue: new RegExp(`^${ipv4Part}$`, "i")
82
+ };
83
+ const octalRegex = new RegExp(`^0[0-7]+$`, "i");
84
+ const hexRegex = new RegExp(`^0x[a-f0-9]+$`, "i");
85
+ const zoneIndex = "%[0-9a-z]{1,}";
86
+ const ipv6Part = "(?:[0-9a-f]+::?)+";
87
+ const ipv6Regexes = {
88
+ zoneIndex: new RegExp(zoneIndex, "i"),
89
+ "native": new RegExp(`^(::)?(${ipv6Part})?([0-9a-f]+)?(::)?(${zoneIndex})?$`, "i"),
90
+ deprecatedTransitional: new RegExp(`^(?:::)(${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}(${zoneIndex})?)$`, "i"),
91
+ transitional: new RegExp(`^((?:${ipv6Part})|(?:::)(?:${ipv6Part})?)${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}\\.${ipv4Part}(${zoneIndex})?$`, "i")
92
+ };
93
+ function expandIPv6(string, parts) {
94
+ if (string.indexOf("::") !== string.lastIndexOf("::")) {
95
+ return null;
96
+ }
97
+ let colonCount = 0;
98
+ let lastColon = -1;
99
+ let zoneId = (string.match(ipv6Regexes.zoneIndex) || [])[0];
100
+ let replacement, replacementCount;
101
+ if (zoneId) {
102
+ zoneId = zoneId.substring(1);
103
+ string = string.replace(/%.+$/, "");
104
+ }
105
+ while ((lastColon = string.indexOf(":", lastColon + 1)) >= 0) {
106
+ colonCount++;
107
+ }
108
+ if (string.substr(0, 2) === "::") {
109
+ colonCount--;
110
+ }
111
+ if (string.substr(-2, 2) === "::") {
112
+ colonCount--;
113
+ }
114
+ if (colonCount > parts) {
115
+ return null;
116
+ }
117
+ replacementCount = parts - colonCount;
118
+ replacement = ":";
119
+ while (replacementCount--) {
120
+ replacement += "0:";
121
+ }
122
+ string = string.replace("::", replacement);
123
+ if (string[0] === ":") {
124
+ string = string.slice(1);
125
+ }
126
+ if (string[string.length - 1] === ":") {
127
+ string = string.slice(0, -1);
128
+ }
129
+ parts = (function() {
130
+ const ref = string.split(":");
131
+ const results = [];
132
+ for (let i = 0; i < ref.length; i++) {
133
+ results.push(parseInt(ref[i], 16));
134
+ }
135
+ return results;
136
+ })();
137
+ return {
138
+ parts,
139
+ zoneId
140
+ };
141
+ }
142
+ function matchCIDR(first, second, partSize, cidrBits) {
143
+ if (first.length !== second.length) {
144
+ throw new Error("ipaddr: cannot match CIDR for objects with different lengths");
145
+ }
146
+ let part = 0;
147
+ let shift;
148
+ while (cidrBits > 0) {
149
+ shift = partSize - cidrBits;
150
+ if (shift < 0) {
151
+ shift = 0;
152
+ }
153
+ if (first[part] >> shift !== second[part] >> shift) {
154
+ return false;
155
+ }
156
+ cidrBits -= partSize;
157
+ part += 1;
158
+ }
159
+ return true;
160
+ }
161
+ function parseIntAuto(string) {
162
+ if (hexRegex.test(string)) {
163
+ return parseInt(string, 16);
164
+ }
165
+ if (string[0] === "0" && !isNaN(parseInt(string[1], 10))) {
166
+ if (octalRegex.test(string)) {
167
+ return parseInt(string, 8);
168
+ }
169
+ throw new Error(`ipaddr: cannot parse ${string} as octal`);
170
+ }
171
+ return parseInt(string, 10);
172
+ }
173
+ function padPart(part, length) {
174
+ while (part.length < length) {
175
+ part = `0${part}`;
176
+ }
177
+ return part;
178
+ }
179
+ const ipaddr2 = {};
180
+ ipaddr2.IPv4 = (function() {
181
+ function IPv4(octets) {
182
+ if (octets.length !== 4) {
183
+ throw new Error("ipaddr: ipv4 octet count should be 4");
184
+ }
185
+ let i, octet;
186
+ for (i = 0; i < octets.length; i++) {
187
+ octet = octets[i];
188
+ if (!(0 <= octet && octet <= 255)) {
189
+ throw new Error("ipaddr: ipv4 octet should fit in 8 bits");
190
+ }
191
+ }
192
+ this.octets = octets;
193
+ }
194
+ IPv4.prototype.SpecialRanges = {
195
+ unspecified: [[new IPv4([0, 0, 0, 0]), 8]],
196
+ broadcast: [[new IPv4([255, 255, 255, 255]), 32]],
197
+ // RFC3171
198
+ multicast: [[new IPv4([224, 0, 0, 0]), 4]],
199
+ // RFC3927
200
+ linkLocal: [[new IPv4([169, 254, 0, 0]), 16]],
201
+ // RFC5735
202
+ loopback: [[new IPv4([127, 0, 0, 0]), 8]],
203
+ // RFC6598
204
+ carrierGradeNat: [[new IPv4([100, 64, 0, 0]), 10]],
205
+ // RFC1918
206
+ "private": [
207
+ [new IPv4([10, 0, 0, 0]), 8],
208
+ [new IPv4([172, 16, 0, 0]), 12],
209
+ [new IPv4([192, 168, 0, 0]), 16]
210
+ ],
211
+ // Reserved and testing-only ranges; RFCs 5735, 5737, 2544, 1700
212
+ reserved: [
213
+ [new IPv4([192, 0, 0, 0]), 24],
214
+ [new IPv4([192, 0, 2, 0]), 24],
215
+ [new IPv4([192, 88, 99, 0]), 24],
216
+ [new IPv4([198, 18, 0, 0]), 15],
217
+ [new IPv4([198, 51, 100, 0]), 24],
218
+ [new IPv4([203, 0, 113, 0]), 24],
219
+ [new IPv4([240, 0, 0, 0]), 4]
220
+ ],
221
+ // RFC7534, RFC7535
222
+ as112: [
223
+ [new IPv4([192, 175, 48, 0]), 24],
224
+ [new IPv4([192, 31, 196, 0]), 24]
225
+ ],
226
+ // RFC7450
227
+ amt: [
228
+ [new IPv4([192, 52, 193, 0]), 24]
229
+ ]
230
+ };
231
+ IPv4.prototype.kind = function() {
232
+ return "ipv4";
233
+ };
234
+ IPv4.prototype.match = function(other, cidrRange) {
235
+ let ref;
236
+ if (cidrRange === void 0) {
237
+ ref = other;
238
+ other = ref[0];
239
+ cidrRange = ref[1];
240
+ }
241
+ if (other.kind() !== "ipv4") {
242
+ throw new Error("ipaddr: cannot match ipv4 address with non-ipv4 one");
243
+ }
244
+ return matchCIDR(this.octets, other.octets, 8, cidrRange);
245
+ };
246
+ IPv4.prototype.prefixLengthFromSubnetMask = function() {
247
+ let cidr = 0;
248
+ let stop = false;
249
+ const zerotable = {
250
+ 0: 8,
251
+ 128: 7,
252
+ 192: 6,
253
+ 224: 5,
254
+ 240: 4,
255
+ 248: 3,
256
+ 252: 2,
257
+ 254: 1,
258
+ 255: 0
259
+ };
260
+ let i, octet, zeros;
261
+ for (i = 3; i >= 0; i -= 1) {
262
+ octet = this.octets[i];
263
+ if (octet in zerotable) {
264
+ zeros = zerotable[octet];
265
+ if (stop && zeros !== 0) {
266
+ return null;
267
+ }
268
+ if (zeros !== 8) {
269
+ stop = true;
270
+ }
271
+ cidr += zeros;
272
+ } else {
273
+ return null;
274
+ }
275
+ }
276
+ return 32 - cidr;
277
+ };
278
+ IPv4.prototype.range = function() {
279
+ return ipaddr2.subnetMatch(this, this.SpecialRanges);
280
+ };
281
+ IPv4.prototype.toByteArray = function() {
282
+ return this.octets.slice(0);
283
+ };
284
+ IPv4.prototype.toIPv4MappedAddress = function() {
285
+ return ipaddr2.IPv6.parse(`::ffff:${this.toString()}`);
286
+ };
287
+ IPv4.prototype.toNormalizedString = function() {
288
+ return this.toString();
289
+ };
290
+ IPv4.prototype.toString = function() {
291
+ return this.octets.join(".");
292
+ };
293
+ return IPv4;
294
+ })();
295
+ ipaddr2.IPv4.broadcastAddressFromCIDR = function(string) {
296
+ try {
297
+ const cidr = this.parseCIDR(string);
298
+ const ipInterfaceOctets = cidr[0].toByteArray();
299
+ const subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray();
300
+ const octets = [];
301
+ let i = 0;
302
+ while (i < 4) {
303
+ octets.push(parseInt(ipInterfaceOctets[i], 10) | parseInt(subnetMaskOctets[i], 10) ^ 255);
304
+ i++;
305
+ }
306
+ return new this(octets);
307
+ } catch (e) {
308
+ throw new Error("ipaddr: the address does not have IPv4 CIDR format");
309
+ }
310
+ };
311
+ ipaddr2.IPv4.isIPv4 = function(string) {
312
+ return this.parser(string) !== null;
313
+ };
314
+ ipaddr2.IPv4.isValid = function(string) {
315
+ try {
316
+ new this(this.parser(string));
317
+ return true;
318
+ } catch (e) {
319
+ return false;
320
+ }
321
+ };
322
+ ipaddr2.IPv4.isValidCIDR = function(string) {
323
+ try {
324
+ this.parseCIDR(string);
325
+ return true;
326
+ } catch (e) {
327
+ return false;
328
+ }
329
+ };
330
+ ipaddr2.IPv4.isValidFourPartDecimal = function(string) {
331
+ if (ipaddr2.IPv4.isValid(string) && string.match(/^(0|[1-9]\d*)(\.(0|[1-9]\d*)){3}$/)) {
332
+ return true;
333
+ } else {
334
+ return false;
335
+ }
336
+ };
337
+ ipaddr2.IPv4.networkAddressFromCIDR = function(string) {
338
+ let cidr, i, ipInterfaceOctets, octets, subnetMaskOctets;
339
+ try {
340
+ cidr = this.parseCIDR(string);
341
+ ipInterfaceOctets = cidr[0].toByteArray();
342
+ subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray();
343
+ octets = [];
344
+ i = 0;
345
+ while (i < 4) {
346
+ octets.push(parseInt(ipInterfaceOctets[i], 10) & parseInt(subnetMaskOctets[i], 10));
347
+ i++;
348
+ }
349
+ return new this(octets);
350
+ } catch (e) {
351
+ throw new Error("ipaddr: the address does not have IPv4 CIDR format");
352
+ }
353
+ };
354
+ ipaddr2.IPv4.parse = function(string) {
355
+ const parts = this.parser(string);
356
+ if (parts === null) {
357
+ throw new Error("ipaddr: string is not formatted like an IPv4 Address");
358
+ }
359
+ return new this(parts);
360
+ };
361
+ ipaddr2.IPv4.parseCIDR = function(string) {
362
+ let match;
363
+ if (match = string.match(/^(.+)\/(\d+)$/)) {
364
+ const maskLength = parseInt(match[2]);
365
+ if (maskLength >= 0 && maskLength <= 32) {
366
+ const parsed = [this.parse(match[1]), maskLength];
367
+ Object.defineProperty(parsed, "toString", {
368
+ value: function() {
369
+ return this.join("/");
370
+ }
371
+ });
372
+ return parsed;
373
+ }
374
+ }
375
+ throw new Error("ipaddr: string is not formatted like an IPv4 CIDR range");
376
+ };
377
+ ipaddr2.IPv4.parser = function(string) {
378
+ let match, part, value;
379
+ if (match = string.match(ipv4Regexes.fourOctet)) {
380
+ return (function() {
381
+ const ref = match.slice(1, 6);
382
+ const results = [];
383
+ for (let i = 0; i < ref.length; i++) {
384
+ part = ref[i];
385
+ results.push(parseIntAuto(part));
386
+ }
387
+ return results;
388
+ })();
389
+ } else if (match = string.match(ipv4Regexes.longValue)) {
390
+ value = parseIntAuto(match[1]);
391
+ if (value > 4294967295 || value < 0) {
392
+ throw new Error("ipaddr: address outside defined range");
393
+ }
394
+ return (function() {
395
+ const results = [];
396
+ let shift;
397
+ for (shift = 0; shift <= 24; shift += 8) {
398
+ results.push(value >> shift & 255);
399
+ }
400
+ return results;
401
+ })().reverse();
402
+ } else if (match = string.match(ipv4Regexes.twoOctet)) {
403
+ return (function() {
404
+ const ref = match.slice(1, 4);
405
+ const results = [];
406
+ value = parseIntAuto(ref[1]);
407
+ if (value > 16777215 || value < 0) {
408
+ throw new Error("ipaddr: address outside defined range");
409
+ }
410
+ results.push(parseIntAuto(ref[0]));
411
+ results.push(value >> 16 & 255);
412
+ results.push(value >> 8 & 255);
413
+ results.push(value & 255);
414
+ return results;
415
+ })();
416
+ } else if (match = string.match(ipv4Regexes.threeOctet)) {
417
+ return (function() {
418
+ const ref = match.slice(1, 5);
419
+ const results = [];
420
+ value = parseIntAuto(ref[2]);
421
+ if (value > 65535 || value < 0) {
422
+ throw new Error("ipaddr: address outside defined range");
423
+ }
424
+ results.push(parseIntAuto(ref[0]));
425
+ results.push(parseIntAuto(ref[1]));
426
+ results.push(value >> 8 & 255);
427
+ results.push(value & 255);
428
+ return results;
429
+ })();
430
+ } else {
431
+ return null;
432
+ }
433
+ };
434
+ ipaddr2.IPv4.subnetMaskFromPrefixLength = function(prefix) {
435
+ prefix = parseInt(prefix);
436
+ if (prefix < 0 || prefix > 32) {
437
+ throw new Error("ipaddr: invalid IPv4 prefix length");
438
+ }
439
+ const octets = [0, 0, 0, 0];
440
+ let j = 0;
441
+ const filledOctetCount = Math.floor(prefix / 8);
442
+ while (j < filledOctetCount) {
443
+ octets[j] = 255;
444
+ j++;
445
+ }
446
+ if (filledOctetCount < 4) {
447
+ octets[filledOctetCount] = Math.pow(2, prefix % 8) - 1 << 8 - prefix % 8;
448
+ }
449
+ return new this(octets);
450
+ };
451
+ ipaddr2.IPv6 = (function() {
452
+ function IPv6(parts, zoneId) {
453
+ let i, part;
454
+ if (parts.length === 16) {
455
+ this.parts = [];
456
+ for (i = 0; i <= 14; i += 2) {
457
+ this.parts.push(parts[i] << 8 | parts[i + 1]);
458
+ }
459
+ } else if (parts.length === 8) {
460
+ this.parts = parts;
461
+ } else {
462
+ throw new Error("ipaddr: ipv6 part count should be 8 or 16");
463
+ }
464
+ for (i = 0; i < this.parts.length; i++) {
465
+ part = this.parts[i];
466
+ if (!(0 <= part && part <= 65535)) {
467
+ throw new Error("ipaddr: ipv6 part should fit in 16 bits");
468
+ }
469
+ }
470
+ if (zoneId) {
471
+ this.zoneId = zoneId;
472
+ }
473
+ }
474
+ IPv6.prototype.SpecialRanges = {
475
+ // RFC4291, here and after
476
+ unspecified: [new IPv6([0, 0, 0, 0, 0, 0, 0, 0]), 128],
477
+ linkLocal: [new IPv6([65152, 0, 0, 0, 0, 0, 0, 0]), 10],
478
+ multicast: [new IPv6([65280, 0, 0, 0, 0, 0, 0, 0]), 8],
479
+ loopback: [new IPv6([0, 0, 0, 0, 0, 0, 0, 1]), 128],
480
+ uniqueLocal: [new IPv6([64512, 0, 0, 0, 0, 0, 0, 0]), 7],
481
+ ipv4Mapped: [new IPv6([0, 0, 0, 0, 0, 65535, 0, 0]), 96],
482
+ // RFC6666
483
+ discard: [new IPv6([256, 0, 0, 0, 0, 0, 0, 0]), 64],
484
+ // RFC6145
485
+ rfc6145: [new IPv6([0, 0, 0, 0, 65535, 0, 0, 0]), 96],
486
+ // RFC6052
487
+ rfc6052: [new IPv6([100, 65435, 0, 0, 0, 0, 0, 0]), 96],
488
+ // RFC3056
489
+ "6to4": [new IPv6([8194, 0, 0, 0, 0, 0, 0, 0]), 16],
490
+ // RFC6052, RFC6146
491
+ teredo: [new IPv6([8193, 0, 0, 0, 0, 0, 0, 0]), 32],
492
+ // RFC5180
493
+ benchmarking: [new IPv6([8193, 2, 0, 0, 0, 0, 0, 0]), 48],
494
+ // RFC7450
495
+ amt: [new IPv6([8193, 3, 0, 0, 0, 0, 0, 0]), 32],
496
+ as112v6: [
497
+ [new IPv6([8193, 4, 274, 0, 0, 0, 0, 0]), 48],
498
+ [new IPv6([9760, 79, 32768, 0, 0, 0, 0, 0]), 48]
499
+ ],
500
+ deprecated: [new IPv6([8193, 16, 0, 0, 0, 0, 0, 0]), 28],
501
+ orchid2: [new IPv6([8193, 32, 0, 0, 0, 0, 0, 0]), 28],
502
+ droneRemoteIdProtocolEntityTags: [new IPv6([8193, 48, 0, 0, 0, 0, 0, 0]), 28],
503
+ reserved: [
504
+ // RFC3849
505
+ [new IPv6([8193, 0, 0, 0, 0, 0, 0, 0]), 23],
506
+ // RFC2928
507
+ [new IPv6([8193, 3512, 0, 0, 0, 0, 0, 0]), 32]
508
+ ]
509
+ };
510
+ IPv6.prototype.isIPv4MappedAddress = function() {
511
+ return this.range() === "ipv4Mapped";
512
+ };
513
+ IPv6.prototype.kind = function() {
514
+ return "ipv6";
515
+ };
516
+ IPv6.prototype.match = function(other, cidrRange) {
517
+ let ref;
518
+ if (cidrRange === void 0) {
519
+ ref = other;
520
+ other = ref[0];
521
+ cidrRange = ref[1];
522
+ }
523
+ if (other.kind() !== "ipv6") {
524
+ throw new Error("ipaddr: cannot match ipv6 address with non-ipv6 one");
525
+ }
526
+ return matchCIDR(this.parts, other.parts, 16, cidrRange);
527
+ };
528
+ IPv6.prototype.prefixLengthFromSubnetMask = function() {
529
+ let cidr = 0;
530
+ let stop = false;
531
+ const zerotable = {
532
+ 0: 16,
533
+ 32768: 15,
534
+ 49152: 14,
535
+ 57344: 13,
536
+ 61440: 12,
537
+ 63488: 11,
538
+ 64512: 10,
539
+ 65024: 9,
540
+ 65280: 8,
541
+ 65408: 7,
542
+ 65472: 6,
543
+ 65504: 5,
544
+ 65520: 4,
545
+ 65528: 3,
546
+ 65532: 2,
547
+ 65534: 1,
548
+ 65535: 0
549
+ };
550
+ let part, zeros;
551
+ for (let i = 7; i >= 0; i -= 1) {
552
+ part = this.parts[i];
553
+ if (part in zerotable) {
554
+ zeros = zerotable[part];
555
+ if (stop && zeros !== 0) {
556
+ return null;
557
+ }
558
+ if (zeros !== 16) {
559
+ stop = true;
560
+ }
561
+ cidr += zeros;
562
+ } else {
563
+ return null;
564
+ }
565
+ }
566
+ return 128 - cidr;
567
+ };
568
+ IPv6.prototype.range = function() {
569
+ return ipaddr2.subnetMatch(this, this.SpecialRanges);
570
+ };
571
+ IPv6.prototype.toByteArray = function() {
572
+ let part;
573
+ const bytes = [];
574
+ const ref = this.parts;
575
+ for (let i = 0; i < ref.length; i++) {
576
+ part = ref[i];
577
+ bytes.push(part >> 8);
578
+ bytes.push(part & 255);
579
+ }
580
+ return bytes;
581
+ };
582
+ IPv6.prototype.toFixedLengthString = function() {
583
+ const addr = (function() {
584
+ const results = [];
585
+ for (let i = 0; i < this.parts.length; i++) {
586
+ results.push(padPart(this.parts[i].toString(16), 4));
587
+ }
588
+ return results;
589
+ }).call(this).join(":");
590
+ let suffix = "";
591
+ if (this.zoneId) {
592
+ suffix = `%${this.zoneId}`;
593
+ }
594
+ return addr + suffix;
595
+ };
596
+ IPv6.prototype.toIPv4Address = function() {
597
+ if (!this.isIPv4MappedAddress()) {
598
+ throw new Error("ipaddr: trying to convert a generic ipv6 address to ipv4");
599
+ }
600
+ const ref = this.parts.slice(-2);
601
+ const high = ref[0];
602
+ const low = ref[1];
603
+ return new ipaddr2.IPv4([high >> 8, high & 255, low >> 8, low & 255]);
604
+ };
605
+ IPv6.prototype.toNormalizedString = function() {
606
+ const addr = (function() {
607
+ const results = [];
608
+ for (let i = 0; i < this.parts.length; i++) {
609
+ results.push(this.parts[i].toString(16));
610
+ }
611
+ return results;
612
+ }).call(this).join(":");
613
+ let suffix = "";
614
+ if (this.zoneId) {
615
+ suffix = `%${this.zoneId}`;
616
+ }
617
+ return addr + suffix;
618
+ };
619
+ IPv6.prototype.toRFC5952String = function() {
620
+ const regex = /((^|:)(0(:|$)){2,})/g;
621
+ const string = this.toNormalizedString();
622
+ let bestMatchIndex = 0;
623
+ let bestMatchLength = -1;
624
+ let match;
625
+ while (match = regex.exec(string)) {
626
+ if (match[0].length > bestMatchLength) {
627
+ bestMatchIndex = match.index;
628
+ bestMatchLength = match[0].length;
629
+ }
630
+ }
631
+ if (bestMatchLength < 0) {
632
+ return string;
633
+ }
634
+ return `${string.substring(0, bestMatchIndex)}::${string.substring(bestMatchIndex + bestMatchLength)}`;
635
+ };
636
+ IPv6.prototype.toString = function() {
637
+ return this.toRFC5952String();
638
+ };
639
+ return IPv6;
640
+ })();
641
+ ipaddr2.IPv6.broadcastAddressFromCIDR = function(string) {
642
+ try {
643
+ const cidr = this.parseCIDR(string);
644
+ const ipInterfaceOctets = cidr[0].toByteArray();
645
+ const subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray();
646
+ const octets = [];
647
+ let i = 0;
648
+ while (i < 16) {
649
+ octets.push(parseInt(ipInterfaceOctets[i], 10) | parseInt(subnetMaskOctets[i], 10) ^ 255);
650
+ i++;
651
+ }
652
+ return new this(octets);
653
+ } catch (e) {
654
+ throw new Error(`ipaddr: the address does not have IPv6 CIDR format (${e})`);
655
+ }
656
+ };
657
+ ipaddr2.IPv6.isIPv6 = function(string) {
658
+ return this.parser(string) !== null;
659
+ };
660
+ ipaddr2.IPv6.isValid = function(string) {
661
+ if (typeof string === "string" && string.indexOf(":") === -1) {
662
+ return false;
663
+ }
664
+ try {
665
+ const addr = this.parser(string);
666
+ new this(addr.parts, addr.zoneId);
667
+ return true;
668
+ } catch (e) {
669
+ return false;
670
+ }
671
+ };
672
+ ipaddr2.IPv6.isValidCIDR = function(string) {
673
+ if (typeof string === "string" && string.indexOf(":") === -1) {
674
+ return false;
675
+ }
676
+ try {
677
+ this.parseCIDR(string);
678
+ return true;
679
+ } catch (e) {
680
+ return false;
681
+ }
682
+ };
683
+ ipaddr2.IPv6.networkAddressFromCIDR = function(string) {
684
+ let cidr, i, ipInterfaceOctets, octets, subnetMaskOctets;
685
+ try {
686
+ cidr = this.parseCIDR(string);
687
+ ipInterfaceOctets = cidr[0].toByteArray();
688
+ subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray();
689
+ octets = [];
690
+ i = 0;
691
+ while (i < 16) {
692
+ octets.push(parseInt(ipInterfaceOctets[i], 10) & parseInt(subnetMaskOctets[i], 10));
693
+ i++;
694
+ }
695
+ return new this(octets);
696
+ } catch (e) {
697
+ throw new Error(`ipaddr: the address does not have IPv6 CIDR format (${e})`);
698
+ }
699
+ };
700
+ ipaddr2.IPv6.parse = function(string) {
701
+ const addr = this.parser(string);
702
+ if (addr.parts === null) {
703
+ throw new Error("ipaddr: string is not formatted like an IPv6 Address");
704
+ }
705
+ return new this(addr.parts, addr.zoneId);
706
+ };
707
+ ipaddr2.IPv6.parseCIDR = function(string) {
708
+ let maskLength, match, parsed;
709
+ if (match = string.match(/^(.+)\/(\d+)$/)) {
710
+ maskLength = parseInt(match[2]);
711
+ if (maskLength >= 0 && maskLength <= 128) {
712
+ parsed = [this.parse(match[1]), maskLength];
713
+ Object.defineProperty(parsed, "toString", {
714
+ value: function() {
715
+ return this.join("/");
716
+ }
717
+ });
718
+ return parsed;
719
+ }
720
+ }
721
+ throw new Error("ipaddr: string is not formatted like an IPv6 CIDR range");
722
+ };
723
+ ipaddr2.IPv6.parser = function(string) {
724
+ let addr, i, match, octet, octets, zoneId;
725
+ if (match = string.match(ipv6Regexes.deprecatedTransitional)) {
726
+ return this.parser(`::ffff:${match[1]}`);
727
+ }
728
+ if (ipv6Regexes.native.test(string)) {
729
+ return expandIPv6(string, 8);
730
+ }
731
+ if (match = string.match(ipv6Regexes.transitional)) {
732
+ zoneId = match[6] || "";
733
+ addr = match[1];
734
+ if (!match[1].endsWith("::")) {
735
+ addr = addr.slice(0, -1);
736
+ }
737
+ addr = expandIPv6(addr + zoneId, 6);
738
+ if (addr.parts) {
739
+ octets = [
740
+ parseInt(match[2]),
741
+ parseInt(match[3]),
742
+ parseInt(match[4]),
743
+ parseInt(match[5])
744
+ ];
745
+ for (i = 0; i < octets.length; i++) {
746
+ octet = octets[i];
747
+ if (!(0 <= octet && octet <= 255)) {
748
+ return null;
749
+ }
750
+ }
751
+ addr.parts.push(octets[0] << 8 | octets[1]);
752
+ addr.parts.push(octets[2] << 8 | octets[3]);
753
+ return {
754
+ parts: addr.parts,
755
+ zoneId: addr.zoneId
756
+ };
757
+ }
758
+ }
759
+ return null;
760
+ };
761
+ ipaddr2.IPv6.subnetMaskFromPrefixLength = function(prefix) {
762
+ prefix = parseInt(prefix);
763
+ if (prefix < 0 || prefix > 128) {
764
+ throw new Error("ipaddr: invalid IPv6 prefix length");
765
+ }
766
+ const octets = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
767
+ let j = 0;
768
+ const filledOctetCount = Math.floor(prefix / 8);
769
+ while (j < filledOctetCount) {
770
+ octets[j] = 255;
771
+ j++;
772
+ }
773
+ if (filledOctetCount < 16) {
774
+ octets[filledOctetCount] = Math.pow(2, prefix % 8) - 1 << 8 - prefix % 8;
775
+ }
776
+ return new this(octets);
777
+ };
778
+ ipaddr2.fromByteArray = function(bytes) {
779
+ const length = bytes.length;
780
+ if (length === 4) {
781
+ return new ipaddr2.IPv4(bytes);
782
+ } else if (length === 16) {
783
+ return new ipaddr2.IPv6(bytes);
784
+ } else {
785
+ throw new Error("ipaddr: the binary input is neither an IPv6 nor IPv4 address");
786
+ }
787
+ };
788
+ ipaddr2.isValid = function(string) {
789
+ return ipaddr2.IPv6.isValid(string) || ipaddr2.IPv4.isValid(string);
790
+ };
791
+ ipaddr2.isValidCIDR = function(string) {
792
+ return ipaddr2.IPv6.isValidCIDR(string) || ipaddr2.IPv4.isValidCIDR(string);
793
+ };
794
+ ipaddr2.parse = function(string) {
795
+ if (ipaddr2.IPv6.isValid(string)) {
796
+ return ipaddr2.IPv6.parse(string);
797
+ } else if (ipaddr2.IPv4.isValid(string)) {
798
+ return ipaddr2.IPv4.parse(string);
799
+ } else {
800
+ throw new Error("ipaddr: the address has neither IPv6 nor IPv4 format");
801
+ }
802
+ };
803
+ ipaddr2.parseCIDR = function(string) {
804
+ try {
805
+ return ipaddr2.IPv6.parseCIDR(string);
806
+ } catch (e) {
807
+ try {
808
+ return ipaddr2.IPv4.parseCIDR(string);
809
+ } catch (e2) {
810
+ throw new Error("ipaddr: the address has neither IPv6 nor IPv4 CIDR format");
811
+ }
812
+ }
813
+ };
814
+ ipaddr2.process = function(string) {
815
+ const addr = this.parse(string);
816
+ if (addr.kind() === "ipv6" && addr.isIPv4MappedAddress()) {
817
+ return addr.toIPv4Address();
818
+ } else {
819
+ return addr;
820
+ }
821
+ };
822
+ ipaddr2.subnetMatch = function(address, rangeList, defaultName) {
823
+ let i, rangeName, rangeSubnets, subnet;
824
+ if (defaultName === void 0 || defaultName === null) {
825
+ defaultName = "unicast";
826
+ }
827
+ for (rangeName in rangeList) {
828
+ if (Object.prototype.hasOwnProperty.call(rangeList, rangeName)) {
829
+ rangeSubnets = rangeList[rangeName];
830
+ if (rangeSubnets[0] && !(rangeSubnets[0] instanceof Array)) {
831
+ rangeSubnets = [rangeSubnets];
832
+ }
833
+ for (i = 0; i < rangeSubnets.length; i++) {
834
+ subnet = rangeSubnets[i];
835
+ if (address.kind() === subnet[0].kind() && address.match.apply(address, subnet)) {
836
+ return rangeName;
837
+ }
838
+ }
839
+ }
840
+ }
841
+ return defaultName;
842
+ };
843
+ if (typeof module2 !== "undefined" && module2.exports) {
844
+ module2.exports = ipaddr2;
845
+ } else {
846
+ root.ipaddr = ipaddr2;
847
+ }
848
+ })(exports);
849
+ }
850
+ });
851
+ var src_exports = {};
852
+ __export2(src_exports, {
853
+ activate: () => activate
854
+ });
855
+ var operations = [
856
+ "toast.show",
857
+ "message.show",
858
+ "message.update",
859
+ "interaction.close",
860
+ "interaction.list",
861
+ "interaction.respond",
862
+ "interaction.action",
863
+ "dialog.alert",
864
+ "dialog.confirm",
865
+ "dialog.prompt",
866
+ "picker.directory",
867
+ "picker.files",
868
+ "tasks.submit",
869
+ "tasks.list",
870
+ "tasks.snapshot",
871
+ "tasks.cancel",
872
+ "tasks.result",
873
+ "notification.publish",
874
+ "notification.update"
875
+ ];
876
+ function publicCommandId(operation) {
877
+ if (!operations.includes(operation))
878
+ throw new Error("Unknown public command operation");
879
+ return operation.startsWith("interaction.") ? `pal.host.${operation}` : `pal.${operation}`;
880
+ }
881
+ var PUBLIC_COMMAND_DEFINITIONS = operations.map((operation) => ({
882
+ id: publicCommandId(operation),
883
+ title: operation,
884
+ visibility: "public",
885
+ // These operations do not themselves modify workspace files. Task targets are
886
+ // admitted independently with the inherited read-only policy and permission budget.
887
+ readOnly: true,
888
+ requiredPermissions: operation.startsWith("notification.") ? ["pal.notifications.show"] : [],
889
+ inputSchema: { type: "object" }
890
+ }));
891
+ var FRONTEND_COMMAND_DEFINITIONS = [
892
+ "context",
893
+ "set-theme",
894
+ "list-models",
895
+ "pick-workspace-directory",
896
+ "focus-composer-draft",
897
+ "request-conversation",
898
+ "materials-upload",
899
+ "materials-resolve",
900
+ "materials-extract",
901
+ "extract-conversation-attachment",
902
+ "focus-conversation-message",
903
+ "copy-text",
904
+ "open-settings",
905
+ "open-conversation",
906
+ "settings",
907
+ "open-panel",
908
+ "open-file"
909
+ ].map((operation) => ({
910
+ id: `pal.frontend.${operation}`,
911
+ title: operation,
912
+ visibility: "public",
913
+ readOnly: !["set-theme", "request-conversation", "settings"].includes(
914
+ operation
915
+ ),
916
+ requiredPermissions: operation === "extract-conversation-attachment" ? ["pal.history.read"] : operation === "copy-text" ? ["pal.clipboard.write"] : [],
917
+ inputSchema: {
918
+ type: "object",
919
+ properties: { args: { type: "array", maxItems: 8 } },
920
+ required: ["args"],
921
+ additionalProperties: false
922
+ }
923
+ }));
924
+ var PLUGIN_UI_MAX_EXPLICIT_CHARS = 32 * 1024 * 1024;
925
+ var PLUGIN_UI_MAX_TRANSPORT_CHARS = 2 * PLUGIN_UI_MAX_EXPLICIT_CHARS + 16384;
926
+ function normalizeLocale(locale) {
927
+ if (!locale) return void 0;
928
+ try {
929
+ return Intl.getCanonicalLocales(locale.replaceAll("_", "-"))[0];
930
+ } catch {
931
+ return void 0;
932
+ }
933
+ }
934
+ function localeFallbacks(locale) {
935
+ const full = normalizeLocale(locale);
936
+ return [.../* @__PURE__ */ new Set([...full ? [full, full.split("-")[0]] : [], "en"])];
937
+ }
938
+ var NETWORK_PROXY_SCHEMES = [
939
+ "http",
940
+ "https",
941
+ "socks",
942
+ "socks5",
943
+ "socks5h"
944
+ ];
945
+ var SCHEME_SET = new Set(NETWORK_PROXY_SCHEMES);
946
+ var HOST_CAPABILITIES = {
947
+ ...Object.fromEntries(
948
+ FRONTEND_COMMAND_DEFINITIONS.map((definition) => [definition.id, 1])
949
+ ),
950
+ ...Object.fromEntries(
951
+ PUBLIC_COMMAND_DEFINITIONS.map((definition) => [definition.id, 1])
952
+ ),
953
+ "pal.plugin.tools.workspaceEffects": 1,
954
+ "pal.plugin.promptSections": 1,
955
+ "pal.plugin.providers.approval": 1,
956
+ "pal.plugin.browser.navigation": 1,
957
+ "pal.frontend.webPreview.tabs": 2,
958
+ "pal.frontend.webPreview.contextMenu": 2,
959
+ "pal.frontend.webPreview.pageTools": 1,
960
+ "pal.command.settings": 1,
961
+ "pal.command.accountMenu": 1,
962
+ "pal.command.accountMenu.dynamic": 1,
963
+ "pal.plugin.process.commands": 2,
964
+ "pal.plugin.runChanges.commands": 1,
965
+ "pal.context.command": 1,
966
+ "pal.context.processPort": 1,
967
+ "pal.context.notification": 1,
968
+ "pal.toast.show": 1,
969
+ "pal.message.show": 1,
970
+ "pal.dialog.alert": 1,
971
+ "pal.dialog.confirm": 1,
972
+ "pal.dialog.prompt": 1,
973
+ "pal.picker.directory": 1,
974
+ "pal.picker.files": 1,
975
+ "pal.notification.publish": 1,
976
+ "pal.notification.update": 1,
977
+ "pal.tasks.submit": 1,
978
+ "pal.tasks.list": 1,
979
+ "pal.tasks.get": 1,
980
+ "pal.interactions": 1,
981
+ "pal.tasks": 1,
982
+ "pal.context.public": 1,
983
+ "pal.frontend.toast": 1,
984
+ "pal.frontend.message": 1,
985
+ "pal.frontend.dialog": 1,
986
+ "pal.frontend.picker": 1,
987
+ "pal.frontend.tasks": 1,
988
+ "pal.frontend.notification": 1,
989
+ "pal.extension.ui.panel": 1,
990
+ "pal.plugin.hostPanel": 1,
991
+ "pal.plugin.hostPanel.message": 2,
992
+ "pal.plugin.hostPanel.workspace": 1,
993
+ "pal.plugin.hostPanel.terminal": 1,
994
+ "pal.plugin.hostPanel.webPreview": 2,
995
+ "pal.frontend.webPreview.annotations": 2,
996
+ "pal.frontend.webPreview.extensions": 3,
997
+ "pal.plugin.hostPanel.overlays": 1,
998
+ "pal.plugin.hostPanel.menu.controls": 1,
999
+ "pal.plugin.hostPanel.menu.content": 1,
1000
+ "pal.command.execute": 1,
1001
+ "pal.ui.command.execute": 1,
1002
+ "pal.ui.audio.prepareCommand": 1,
1003
+ "pal.frontend.command.isAvailable": 1,
1004
+ "pal.host.files.navigation": 1,
1005
+ "pal.frontend.terminal.lifecycle": 1,
1006
+ "pal.command.callable": 1,
1007
+ "pal.plugin.providers": 1,
1008
+ "pal.frontend.providers": 1,
1009
+ "pal.frontend.services": 1,
1010
+ "pal.frontend.httpRoutes": 1,
1011
+ "pal.command.dispatch": 1,
1012
+ "pal.plugin.slots": 1,
1013
+ "pal.plugin.declarations": 2,
1014
+ "pal.plugin.files.commands": 8,
1015
+ "pal.permission.clipboard.write": 1,
1016
+ "pal.permission.fs.read": 1,
1017
+ "pal.permission.fs.write": 1,
1018
+ "pal.permission.desktop.windows": 1,
1019
+ "pal.context.desktopWindows": 1,
1020
+ "pal.context.desktopWindows.open": 1,
1021
+ "pal.plugin.api": 1,
1022
+ "pal.plugin.lightweight": 1,
1023
+ "pal.frontend.workspace.current": 1,
1024
+ "pal.frontend.workspace.readDirectory": 1,
1025
+ "pal.permission.host.inject": 1,
1026
+ "pal.permission.prompts.read": 1,
1027
+ "pal.permission.prompts.write": 1,
1028
+ "pal.permission.plugins.manage": 1,
1029
+ "pal.permission.history.read": 1,
1030
+ "pal.permission.history.write": 1,
1031
+ "pal.permission.app-workspaces.read": 1,
1032
+ "pal.permission.app-workspaces.write": 1,
1033
+ "pal.permission.runs.observe": 1,
1034
+ "pal.permission.tools.intercept": 1,
1035
+ "pal.permission.notifications.show": 1,
1036
+ "pal.permission.runs.schedule": 1,
1037
+ "pal.permission.runs.delegate": 1,
1038
+ "pal.permission.models.generate": 1,
1039
+ "pal.permission.models.background": 1,
1040
+ "pal.context.models": 1,
1041
+ "pal.permission.audio.record": 1,
1042
+ "pal.permission.process.spawn": 1,
1043
+ "pal.permission.network.fetch": 1,
1044
+ "pal.permission.browser.control": 1,
1045
+ "pal.permission.storage.read": 1,
1046
+ "pal.permission.storage.write": 1,
1047
+ "pal.extension.ui.workbench": 1,
1048
+ "pal.extension.conversation.before-composer": 1,
1049
+ "pal.extension.conversation.header": 1,
1050
+ "pal.extension.conversation.composer": 1,
1051
+ "pal.extension.conversation.composer.dock": 1,
1052
+ "pal.extension.sidebar.footer.action": 1,
1053
+ "pal.extension.settings.general.item": 1,
1054
+ "pal.extension.settings.theme.item": 1,
1055
+ "pal.extension.composer.environment": 1,
1056
+ "pal.extension.conversation.stage": 1,
1057
+ "pal.extension.window.overlay": 1,
1058
+ "pal.extension.tool.result": 1,
1059
+ "pal.extension.tool.approval": 1,
1060
+ "pal.extension.ui.settings": 1,
1061
+ "pal.context.scopeSignal": 1,
1062
+ "pal.context.services": 1,
1063
+ "pal.context.serviceEvents": 1,
1064
+ "pal.context.resourcePath": 1,
1065
+ "pal.context.localData": 1,
1066
+ "pal.context.localData.getSecret": 1,
1067
+ "pal.context.localData.hasSecret": 1,
1068
+ "pal.context.localData.setSecret": 1,
1069
+ "pal.context.localData.deleteSecret": 1,
1070
+ "pal.connections.tasks": 1,
1071
+ "pal.resources.images": 1,
1072
+ "pal.context.webPages": 1,
1073
+ "pal.context.panels": 1,
1074
+ "pal.context.config": 1,
1075
+ "pal.context.invalidateUi": 1,
1076
+ "pal.context.runBackground": 1,
1077
+ "pal.context.signal": 1,
1078
+ "pal.context.pluginId": 1,
1079
+ "pal.context.storagePath": 1,
1080
+ "pal.context.grantedPermissions": 1,
1081
+ "pal.context.promptDocuments": 1,
1082
+ "pal.context.localData.protect": 1,
1083
+ "pal.context.localData.unprotect": 1,
1084
+ "pal.context.localData.cookies": 1,
1085
+ "pal.context.localData.setCookie": 1,
1086
+ "pal.context.webPages.execute": 1,
1087
+ "pal.context.panels.open": 1,
1088
+ "pal.context.panels.close": 1,
1089
+ "pal.context.config.read": 1,
1090
+ "pal.context.promptDocuments.inspect": 1
1091
+ };
1092
+ var HOST_CAPABILITY_RELEASES = Object.fromEntries(
1093
+ Object.entries(HOST_CAPABILITIES).map(([id2, revision]) => [
1094
+ id2,
1095
+ Object.fromEntries(
1096
+ Array.from({ length: revision }, (_, index) => [index + 1, null])
1097
+ )
1098
+ ])
1099
+ );
1100
+ var FILE_COMMAND_DEFINITIONS = [
1101
+ "read",
1102
+ "write"
1103
+ ].map((operation) => ({
1104
+ id: `pal.fs.${operation}`,
1105
+ title: operation === "read" ? "\u8BFB\u53D6\u6587\u4EF6" : "\u4FEE\u6539\u6587\u4EF6",
1106
+ visibility: "public",
1107
+ readOnly: operation === "read",
1108
+ requiredPermissions: [`pal.fs.${operation}`],
1109
+ inputSchema: {
1110
+ type: "object",
1111
+ additionalProperties: false,
1112
+ properties: {
1113
+ operation: {
1114
+ type: "string",
1115
+ enum: operation === "read" ? [
1116
+ "read",
1117
+ "stat",
1118
+ "lstat",
1119
+ "readlink",
1120
+ "realpath",
1121
+ "list",
1122
+ "directory",
1123
+ "readVersion",
1124
+ "preview",
1125
+ "readChunk",
1126
+ "watch",
1127
+ "snapshot"
1128
+ ] : [
1129
+ "save",
1130
+ "create",
1131
+ "mkdir",
1132
+ "rename",
1133
+ "remove",
1134
+ "writeVersion",
1135
+ "copyFile",
1136
+ "commit"
1137
+ ]
1138
+ },
1139
+ path: { type: "string", minLength: 1, maxLength: 4096 },
1140
+ offset: { type: "integer", minimum: 0, maximum: Number.MAX_SAFE_INTEGER },
1141
+ length: { type: "integer", minimum: 1, maximum: 1048576 },
1142
+ target: { type: "string", minLength: 1, maxLength: 4096 },
1143
+ content: { type: "string", maxLength: 10485760 },
1144
+ encoding: { type: "string", enum: ["utf8", "base64"] },
1145
+ maxBytes: { type: "integer", minimum: 1, maximum: 2097152 },
1146
+ maxEntries: { type: "integer", minimum: 1, maximum: 5e4 },
1147
+ expectedIdentity: { type: "string", maxLength: 2048 },
1148
+ changes: {
1149
+ type: "array",
1150
+ minItems: 1,
1151
+ maxItems: 16,
1152
+ items: {
1153
+ type: "object",
1154
+ additionalProperties: false,
1155
+ required: ["path", "expectedVersion", "content"],
1156
+ properties: {
1157
+ path: { type: "string", minLength: 1, maxLength: 4096 },
1158
+ expectedVersion: { type: ["string", "null"], maxLength: 4096 },
1159
+ content: { type: "string", maxLength: 2796204 }
1160
+ }
1161
+ }
1162
+ },
1163
+ observed: {
1164
+ type: "array",
1165
+ maxItems: 16,
1166
+ items: {
1167
+ type: "object",
1168
+ additionalProperties: false,
1169
+ required: ["path", "expectedVersion"],
1170
+ properties: {
1171
+ path: { type: "string", minLength: 1, maxLength: 4096 },
1172
+ expectedVersion: { type: ["string", "null"], maxLength: 4096 }
1173
+ }
1174
+ }
1175
+ },
1176
+ cursor: { type: "string", maxLength: 100 },
1177
+ expectedVersion: {}
1178
+ },
1179
+ required: ["path"]
1180
+ }
1181
+ }));
1182
+ var entries = [
1183
+ [
1184
+ "pal.fs.read",
1185
+ "Read files",
1186
+ "\u8BFB\u53D6\u6587\u4EF6",
1187
+ "Read approved files and directories",
1188
+ "\u8BFB\u53D6\u5DF2\u6279\u51C6\u7684\u6587\u4EF6\u548C\u76EE\u5F55",
1189
+ "read",
1190
+ "filesystem"
1191
+ ],
1192
+ [
1193
+ "pal.fs.write",
1194
+ "Modify files",
1195
+ "\u4FEE\u6539\u6587\u4EF6",
1196
+ "Create, save, rename and remove files in an approved area",
1197
+ "\u5728\u5DF2\u6279\u51C6\u8303\u56F4\u5185\u521B\u5EFA\u3001\u4FDD\u5B58\u3001\u91CD\u547D\u540D\u548C\u5220\u9664\u6587\u4EF6",
1198
+ "write",
1199
+ "filesystem"
1200
+ ],
1201
+ [
1202
+ "pal.clipboard.write",
1203
+ "Write clipboard",
1204
+ "\u5199\u5165\u526A\u8D34\u677F",
1205
+ "Copy text to the system clipboard",
1206
+ "\u5C06\u6587\u672C\u590D\u5236\u5230\u7CFB\u7EDF\u526A\u8D34\u677F",
1207
+ "write",
1208
+ "global"
1209
+ ],
1210
+ [
1211
+ "pal.history.read",
1212
+ "Read conversations",
1213
+ "\u8BFB\u53D6\u4F1A\u8BDD",
1214
+ "Read project conversations and messages",
1215
+ "\u8BFB\u53D6\u9879\u76EE\u4F1A\u8BDD\u548C\u6D88\u606F",
1216
+ "read",
1217
+ "project"
1218
+ ],
1219
+ [
1220
+ "pal.history.write",
1221
+ "Modify conversations",
1222
+ "\u4FEE\u6539\u4F1A\u8BDD",
1223
+ "Create or change conversation data",
1224
+ "\u521B\u5EFA\u6216\u4FEE\u6539\u4F1A\u8BDD\u6570\u636E",
1225
+ "write",
1226
+ "project"
1227
+ ],
1228
+ [
1229
+ "pal.runs.observe",
1230
+ "Observe runs",
1231
+ "\u89C2\u5BDF\u8FD0\u884C",
1232
+ "Receive run and tool activity",
1233
+ "\u63A5\u6536\u8FD0\u884C\u548C\u5DE5\u5177\u6D3B\u52A8",
1234
+ "observe",
1235
+ "project"
1236
+ ],
1237
+ [
1238
+ "pal.prompts.read",
1239
+ "Read prompts",
1240
+ "\u8BFB\u53D6\u63D0\u793A\u8BCD",
1241
+ "Read available prompt content",
1242
+ "\u8BFB\u53D6\u53EF\u7528\u7684\u63D0\u793A\u8BCD\u5185\u5BB9",
1243
+ "read",
1244
+ "project"
1245
+ ],
1246
+ [
1247
+ "pal.prompts.write",
1248
+ "Modify prompts",
1249
+ "\u4FEE\u6539\u63D0\u793A\u8BCD",
1250
+ "Create or change prompt content",
1251
+ "\u521B\u5EFA\u6216\u4FEE\u6539\u63D0\u793A\u8BCD\u5185\u5BB9",
1252
+ "write",
1253
+ "project"
1254
+ ],
1255
+ [
1256
+ "pal.storage.read",
1257
+ "Read storage",
1258
+ "\u8BFB\u53D6\u5B58\u50A8",
1259
+ "Read plugin storage",
1260
+ "\u8BFB\u53D6\u63D2\u4EF6\u5B58\u50A8",
1261
+ "read",
1262
+ "global"
1263
+ ],
1264
+ [
1265
+ "pal.storage.write",
1266
+ "Write storage",
1267
+ "\u5199\u5165\u5B58\u50A8",
1268
+ "Change plugin storage",
1269
+ "\u4FEE\u6539\u63D2\u4EF6\u5B58\u50A8",
1270
+ "write",
1271
+ "global"
1272
+ ],
1273
+ [
1274
+ "pal.network.fetch",
1275
+ "Network requests",
1276
+ "\u7F51\u7EDC\u8BF7\u6C42",
1277
+ "Send requests to external addresses",
1278
+ "\u5411\u5916\u90E8\u5730\u5740\u53D1\u9001\u8BF7\u6C42",
1279
+ "external",
1280
+ "global"
1281
+ ],
1282
+ [
1283
+ "pal.process.spawn",
1284
+ "Start processes",
1285
+ "\u542F\u52A8\u8FDB\u7A0B",
1286
+ "Start a local process",
1287
+ "\u542F\u52A8\u672C\u5730\u8FDB\u7A0B",
1288
+ "execute",
1289
+ "global"
1290
+ ],
1291
+ [
1292
+ "pal.browser.control",
1293
+ "Control browser",
1294
+ "\u63A7\u5236\u6D4F\u89C8\u5668",
1295
+ "Interact with browser pages",
1296
+ "\u64CD\u4F5C\u6D4F\u89C8\u5668\u9875\u9762",
1297
+ "execute",
1298
+ "global"
1299
+ ],
1300
+ [
1301
+ "pal.desktop.windows",
1302
+ "Control windows",
1303
+ "\u63A7\u5236\u7A97\u53E3",
1304
+ "Interact with desktop windows",
1305
+ "\u64CD\u4F5C\u684C\u9762\u7A97\u53E3",
1306
+ "execute",
1307
+ "global"
1308
+ ],
1309
+ [
1310
+ "pal.plugins.manage",
1311
+ "Manage plugins",
1312
+ "\u7BA1\u7406\u63D2\u4EF6",
1313
+ "Change plugin installation or state",
1314
+ "\u4FEE\u6539\u63D2\u4EF6\u5B89\u88C5\u6216\u542F\u7528\u72B6\u6001",
1315
+ "write",
1316
+ "global"
1317
+ ],
1318
+ [
1319
+ "pal.host.inject",
1320
+ "Run host UI code",
1321
+ "\u6CE8\u5165\u5BBF\u4E3B\u754C\u9762",
1322
+ "Run plugin UI code in the application",
1323
+ "\u5728\u5E94\u7528\u754C\u9762\u4E2D\u8FD0\u884C\u63D2\u4EF6\u4EE3\u7801",
1324
+ "execute",
1325
+ "global"
1326
+ ],
1327
+ [
1328
+ "pal.tools.intercept",
1329
+ "Intercept tools",
1330
+ "\u62E6\u622A\u5DE5\u5177",
1331
+ "Inspect or change tool calls",
1332
+ "\u68C0\u67E5\u6216\u4FEE\u6539\u5DE5\u5177\u8C03\u7528",
1333
+ "execute",
1334
+ "project"
1335
+ ],
1336
+ [
1337
+ "pal.notifications.show",
1338
+ "Show notifications",
1339
+ "\u663E\u793A\u901A\u77E5",
1340
+ "Display application notifications",
1341
+ "\u663E\u793A\u5E94\u7528\u901A\u77E5",
1342
+ "execute",
1343
+ "global"
1344
+ ],
1345
+ [
1346
+ "pal.runs.schedule",
1347
+ "Schedule runs",
1348
+ "\u5B89\u6392\u8FD0\u884C",
1349
+ "Schedule an agent run",
1350
+ "\u5B89\u6392\u4EE3\u7406\u8FD0\u884C",
1351
+ "execute",
1352
+ "project"
1353
+ ],
1354
+ [
1355
+ "pal.runs.delegate",
1356
+ "Delegate runs",
1357
+ "\u59D4\u6D3E\u8FD0\u884C",
1358
+ "Start a delegated agent run",
1359
+ "\u542F\u52A8\u59D4\u6D3E\u7684\u4EE3\u7406\u8FD0\u884C",
1360
+ "execute",
1361
+ "project"
1362
+ ],
1363
+ [
1364
+ "pal.models.generate",
1365
+ "Generate with models",
1366
+ "\u8C03\u7528\u6A21\u578B\u751F\u6210",
1367
+ "Request model generation",
1368
+ "\u8BF7\u6C42\u6A21\u578B\u751F\u6210",
1369
+ "execute",
1370
+ "project"
1371
+ ],
1372
+ [
1373
+ "pal.models.background",
1374
+ "Use models for background work",
1375
+ "\u540E\u53F0\u4F7F\u7528\u6A21\u578B",
1376
+ "Use configured API models while the plugin is active",
1377
+ "\u63D2\u4EF6\u8FD0\u884C\u671F\u95F4\u4F7F\u7528\u5DF2\u914D\u7F6E\u7684 API \u6A21\u578B",
1378
+ "execute",
1379
+ "global"
1380
+ ],
1381
+ [
1382
+ "pal.audio.record",
1383
+ "Record audio",
1384
+ "\u5F55\u5236\u97F3\u9891",
1385
+ "Capture microphone audio",
1386
+ "\u91C7\u96C6\u9EA6\u514B\u98CE\u97F3\u9891",
1387
+ "read",
1388
+ "global"
1389
+ ]
1390
+ ];
1391
+ var permissionAccess = entries.map(
1392
+ ([id2, title, zhTitle, description, zhDescription, effect, scope2]) => ({
1393
+ id: id2,
1394
+ title,
1395
+ description,
1396
+ locales: { zh: { title: zhTitle, description: zhDescription } },
1397
+ effect,
1398
+ scope: scope2,
1399
+ target: { kind: "permission", id: id2 }
1400
+ })
1401
+ );
1402
+ var BUILTIN_ACCESS_DEFINITIONS = [
1403
+ ...permissionAccess,
1404
+ {
1405
+ id: "pal.files.open",
1406
+ title: "Open a file",
1407
+ description: "Open a file in the application",
1408
+ locales: { zh: { title: "\u6253\u5F00\u6587\u4EF6", description: "\u5728\u5E94\u7528\u4E2D\u6253\u5F00\u6587\u4EF6" } },
1409
+ effect: "execute",
1410
+ scope: "project",
1411
+ target: { kind: "command", id: "pal.files.open" }
1412
+ },
1413
+ {
1414
+ id: "pal.frontend.context",
1415
+ title: "Read page context",
1416
+ description: "Read the current plugin page context",
1417
+ locales: {
1418
+ zh: { title: "\u8BFB\u53D6\u9875\u9762\u4E0A\u4E0B\u6587", description: "\u8BFB\u53D6\u5F53\u524D\u63D2\u4EF6\u9875\u9762\u4E0A\u4E0B\u6587" }
1419
+ },
1420
+ effect: "read",
1421
+ scope: "global",
1422
+ target: { kind: "command", id: "pal.frontend.context" }
1423
+ },
1424
+ {
1425
+ id: "pal.frontend.settings",
1426
+ title: "Use plugin settings",
1427
+ description: "Read or save the plugin's settings",
1428
+ locales: {
1429
+ zh: { title: "\u4F7F\u7528\u63D2\u4EF6\u8BBE\u7F6E", description: "\u8BFB\u53D6\u6216\u4FDD\u5B58\u6B64\u63D2\u4EF6\u7684\u8BBE\u7F6E" }
1430
+ },
1431
+ effect: "execute",
1432
+ scope: "global",
1433
+ target: { kind: "command", id: "pal.frontend.settings" }
1434
+ }
1435
+ ];
1436
+ var id = { type: "string", minLength: 1, maxLength: 100 };
1437
+ var integer = (minimum, maximum) => ({
1438
+ type: "integer",
1439
+ minimum,
1440
+ maximum
1441
+ });
1442
+ var PROCESS_COMMAND_DEFINITIONS = [
1443
+ {
1444
+ name: "start",
1445
+ required: ["mode", "executable", "cwd"],
1446
+ properties: {
1447
+ mode: { enum: ["pipe", "pty"] },
1448
+ executable: { type: "string", minLength: 1, maxLength: 4096 },
1449
+ args: {
1450
+ type: "array",
1451
+ maxItems: 256,
1452
+ items: { type: "string", maxLength: 262144 }
1453
+ },
1454
+ cwd: { type: "string", minLength: 1, maxLength: 4096 },
1455
+ scope: { enum: ["session", "project"] },
1456
+ lifetime: { enum: ["scope", "request"] },
1457
+ stdin: { type: "boolean" },
1458
+ maxBufferChars: integer(65536, 24 * 1024 * 1024),
1459
+ stdoutEncoding: { enum: ["utf8", "base64"] },
1460
+ env: {
1461
+ type: "object",
1462
+ maxProperties: 256,
1463
+ additionalProperties: {
1464
+ anyOf: [{ type: "string", maxLength: 32768 }, { type: "null" }]
1465
+ }
1466
+ },
1467
+ timeoutMs: integer(1, 18e5),
1468
+ cols: integer(2, 500),
1469
+ rows: integer(1, 300)
1470
+ }
1471
+ },
1472
+ {
1473
+ name: "read",
1474
+ required: ["processId"],
1475
+ properties: {
1476
+ processId: id,
1477
+ cursor: integer(0, Number.MAX_SAFE_INTEGER),
1478
+ maxChars: integer(1, 65536),
1479
+ waitMs: integer(0, 1e3)
1480
+ }
1481
+ },
1482
+ {
1483
+ name: "write",
1484
+ required: ["processId", "data"],
1485
+ properties: { processId: id, data: { type: "string", maxLength: 65536 } }
1486
+ },
1487
+ {
1488
+ name: "resize",
1489
+ required: ["processId", "cols", "rows"],
1490
+ properties: {
1491
+ processId: id,
1492
+ cols: integer(2, 500),
1493
+ rows: integer(1, 300)
1494
+ }
1495
+ },
1496
+ { name: "release", required: ["processId"], properties: { processId: id } },
1497
+ { name: "stop", required: ["processId"], properties: { processId: id } },
1498
+ { name: "list", required: [], properties: {} }
1499
+ ].map(({ name, required, properties }) => ({
1500
+ id: `pal.process.${name}`,
1501
+ title: `\u8FDB\u7A0B\uFF1A${name}`,
1502
+ visibility: "public",
1503
+ readOnly: ["read", "list"].includes(name),
1504
+ requiredPermissions: ["pal.process.spawn"],
1505
+ inputSchema: {
1506
+ type: "object",
1507
+ additionalProperties: false,
1508
+ required,
1509
+ properties
1510
+ }
1511
+ }));
1512
+ var FILE_OPEN_CAPABILITY = {
1513
+ id: "pal.files.open",
1514
+ version: 1,
1515
+ title: "Open files",
1516
+ approval: {
1517
+ fields: [{ key: "path", label: "File", format: "workspace-path" }]
1518
+ },
1519
+ locales: { zh: { title: "\u6253\u5F00\u6587\u4EF6", labels: { path: "\u6587\u4EF6" } } },
1520
+ inputSchema: {
1521
+ type: "object",
1522
+ properties: {
1523
+ path: { type: "string", minLength: 1, maxLength: 4096 },
1524
+ ...Object.fromEntries(
1525
+ ["line", "column", "endLine", "endColumn"].map((key2) => [
1526
+ key2,
1527
+ { type: "integer", minimum: 1, maximum: 2147483647 }
1528
+ ])
1529
+ )
1530
+ },
1531
+ required: ["path"],
1532
+ additionalProperties: false
1533
+ }
1534
+ };
1535
+ var import_ipaddr = __toESM2(require_ipaddr(), 1);
1536
+ var bindings = new import_node_async_hooks.AsyncLocalStorage();
1537
+ var moduleBinding;
1538
+ var sharedModule = false;
1539
+ function currentPalBinding(requireActive = true) {
1540
+ const binding = bindings.getStore() ?? (!sharedModule ? moduleBinding : void 0);
1541
+ if (!binding)
1542
+ throw new Error("PAL is only available in a plugin lifecycle or callback");
1543
+ if (requireActive) binding.context.signal.throwIfAborted();
1544
+ return binding;
1545
+ }
1546
+ function bindPalCallbacks(value, binding, seen = /* @__PURE__ */ new WeakMap()) {
1547
+ if (typeof value === "function") {
1548
+ const invoke = (receiver, args) => {
1549
+ binding.context.signal.throwIfAborted();
1550
+ return bindings.run(binding, () => Reflect.apply(value, receiver, args));
1551
+ };
1552
+ return value.constructor.name === "AsyncFunction" ? async function(...args) {
1553
+ return invoke(this, args);
1554
+ } : function(...args) {
1555
+ return invoke(this, args);
1556
+ };
1557
+ }
1558
+ if (!value || typeof value !== "object") return value;
1559
+ const prototype = Object.getPrototypeOf(value);
1560
+ if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null)
1561
+ return value;
1562
+ if (seen.has(value)) return seen.get(value);
1563
+ const output = Array.isArray(value) ? [] : Object.create(prototype);
1564
+ seen.set(value, output);
1565
+ for (const [key2, child] of Object.entries(value))
1566
+ Object.defineProperty(output, key2, {
1567
+ value: bindPalCallbacks(child, binding, seen),
1568
+ enumerable: true,
1569
+ writable: true,
1570
+ configurable: true
1571
+ });
1572
+ return output;
1573
+ }
1574
+ function withPalRegistration(context, registration, callback) {
1575
+ return bindings.run({ context, registration }, callback);
1576
+ }
1577
+ function bindPluginModule(module2) {
1578
+ let active;
1579
+ return {
1580
+ async activate(context) {
1581
+ if (active)
1582
+ throw new Error(
1583
+ "Plugin module is already activated; load a fresh entry"
1584
+ );
1585
+ const binding = { context };
1586
+ if (moduleBinding && moduleBinding.context !== context)
1587
+ sharedModule = true;
1588
+ else moduleBinding ??= binding;
1589
+ active = binding;
1590
+ return bindings.run(
1591
+ binding,
1592
+ async () => bindPalCallbacks(
1593
+ await module2.activate(context),
1594
+ binding
1595
+ )
1596
+ );
1597
+ },
1598
+ ...module2.deactivate ? { deactivate: () => bindings.run(active, () => module2.deactivate()) } : {}
1599
+ };
1600
+ }
1601
+ var publicNames = /* @__PURE__ */ new Set([
1602
+ "toast",
1603
+ "message",
1604
+ "dialog",
1605
+ "picker",
1606
+ "tasks",
1607
+ "notification"
1608
+ ]);
1609
+ var pal = new Proxy({}, {
1610
+ get(_target, key2) {
1611
+ const binding = currentPalBinding(false);
1612
+ const runtime = binding.context;
1613
+ if ([
1614
+ "signal",
1615
+ "pluginId",
1616
+ "storagePath",
1617
+ "resourcePath",
1618
+ "grantedPermissions"
1619
+ ].includes(String(key2)))
1620
+ return runtime[key2];
1621
+ binding.context.signal.throwIfAborted();
1622
+ const registration = binding.registration;
1623
+ if (key2 === "command")
1624
+ return {
1625
+ register: (definition) => {
1626
+ if (!binding.registration)
1627
+ throw new Error("Commands register only during plugin setup");
1628
+ binding.registration.command.register(
1629
+ bindPalCallbacks(definition, binding)
1630
+ );
1631
+ },
1632
+ execute: (id2, input) => {
1633
+ binding.context.signal.throwIfAborted();
1634
+ const client = binding.context.command?.();
1635
+ if (!client) throw new Error("Host commands unavailable");
1636
+ return client.execute(id2, input);
1637
+ }
1638
+ };
1639
+ const source = publicNames.has(String(key2)) ? () => binding.context.public?.()?.[key2] : () => runtime[key2];
1640
+ const item = source();
1641
+ const extra = registration?.[key2];
1642
+ if (item && typeof item === "object" && ![Object.prototype, null].includes(Object.getPrototypeOf(item)))
1643
+ return item;
1644
+ if (item && typeof item === "object" || extra && typeof extra === "object") {
1645
+ return new Proxy(
1646
+ {},
1647
+ {
1648
+ get(_object, method) {
1649
+ binding.context.signal.throwIfAborted();
1650
+ const api = source();
1651
+ const registrationApi = extra;
1652
+ const owner = registrationApi && method in registrationApi ? registrationApi : api;
1653
+ const value = owner?.[method];
1654
+ return typeof value === "function" ? (...args) => {
1655
+ binding.context.signal.throwIfAborted();
1656
+ return Reflect.apply(
1657
+ value,
1658
+ owner,
1659
+ bindPalCallbacks(args, binding)
1660
+ );
1661
+ } : value;
1662
+ }
1663
+ }
1664
+ );
1665
+ }
1666
+ return typeof item === "function" ? (...args) => {
1667
+ binding.context.signal.throwIfAborted();
1668
+ return Reflect.apply(
1669
+ item,
1670
+ binding.context,
1671
+ bindPalCallbacks(args, binding)
1672
+ );
1673
+ } : item ?? extra;
1674
+ },
1675
+ set() {
1676
+ throw new Error("PAL API is read-only");
1677
+ }
1678
+ });
1679
+ function definePlugin(setup) {
1680
+ return {
1681
+ async activate(context) {
1682
+ const commands = [];
1683
+ const capabilities = [];
1684
+ const providers = [];
1685
+ const permissions = [];
1686
+ const ui = [];
1687
+ const kinds = [];
1688
+ const slots = [];
1689
+ const slotContributions = [];
1690
+ let extras;
1691
+ let collecting = true;
1692
+ const check = () => {
1693
+ if (!collecting)
1694
+ throw new Error("Registration is only allowed during activation");
1695
+ };
1696
+ try {
1697
+ const registration = {
1698
+ context,
1699
+ permissions: {
1700
+ define(permission) {
1701
+ check();
1702
+ permissions.push(permission);
1703
+ }
1704
+ },
1705
+ providers: {
1706
+ define(value) {
1707
+ check();
1708
+ capabilities.push(value);
1709
+ },
1710
+ register(value) {
1711
+ check();
1712
+ providers.push(value);
1713
+ }
1714
+ },
1715
+ command: {
1716
+ register(command) {
1717
+ check();
1718
+ commands.push({ ...command });
1719
+ }
1720
+ },
1721
+ kinds: {
1722
+ define(kind) {
1723
+ check();
1724
+ kinds.push(kind);
1725
+ }
1726
+ },
1727
+ slots: {
1728
+ define(slot) {
1729
+ check();
1730
+ slots.push(slot);
1731
+ },
1732
+ contribute(contribution) {
1733
+ check();
1734
+ slotContributions.push(contribution);
1735
+ }
1736
+ },
1737
+ ui: {
1738
+ register(contribution) {
1739
+ check();
1740
+ ui.push(contribution);
1741
+ }
1742
+ }
1743
+ };
1744
+ extras = await withPalRegistration(
1745
+ context,
1746
+ registration,
1747
+ () => setup(registration)
1748
+ );
1749
+ } finally {
1750
+ collecting = false;
1751
+ }
1752
+ return {
1753
+ ...extras,
1754
+ permissions: [...extras?.permissions ?? [], ...permissions],
1755
+ capabilities: [...extras?.capabilities ?? [], ...capabilities],
1756
+ providers: [...extras?.providers ?? [], ...providers],
1757
+ commands: [...extras?.commands ?? [], ...commands],
1758
+ ui: [...extras?.ui ?? [], ...ui],
1759
+ kinds: [...extras?.kinds ?? [], ...kinds],
1760
+ slots: [...extras?.slots ?? [], ...slots],
1761
+ slotContributions: [
1762
+ ...extras?.slotContributions ?? [],
1763
+ ...slotContributions
1764
+ ]
1765
+ };
1766
+ }
1767
+ };
1768
+ }
1769
+ function isRemotePath(path) {
1770
+ return typeof path === "string" && path.startsWith("ssh://");
1771
+ }
1772
+ var sep = import_node_path.default.sep;
1773
+ var key = Symbol.for("pal.workspace-transport.v1");
1774
+ function remoteTransport() {
1775
+ const registry = globalThis;
1776
+ const transport = registry[key];
1777
+ if (!transport)
1778
+ throw new Error(
1779
+ "SSH workspace unavailable; update the host and plugin SDK"
1780
+ );
1781
+ return transport;
1782
+ }
1783
+ function routed(name) {
1784
+ return ((...args) => {
1785
+ if (!args.some(isRemotePath)) return local[name](...args);
1786
+ return remoteTransport().file(name, args);
1787
+ });
1788
+ }
1789
+ var access = routed("access");
1790
+ var chmod = routed("chmod");
1791
+ var copyFile = routed("copyFile");
1792
+ var lstat = routed("lstat");
1793
+ var stat = routed("stat");
1794
+ var mkdir = routed("mkdir");
1795
+ var mkdtemp = routed("mkdtemp");
1796
+ var open = routed("open");
1797
+ var opendir = routed("opendir");
1798
+ var readdir = routed("readdir");
1799
+ var readFile = routed("readFile");
1800
+ var readlink = routed("readlink");
1801
+ var realpath = routed("realpath");
1802
+ var rename = routed("rename");
1803
+ var rm = routed("rm");
1804
+ var rmdir = routed("rmdir");
1805
+ var unlink = routed("unlink");
1806
+ var link = routed("link");
1807
+ var writeFile = routed("writeFile");
1808
+ var appendFile = routed("appendFile");
1809
+ var pal_manifest_default = {
1810
+ title: "Change Review",
1811
+ workspaceTargets: ["local", "ssh"],
1812
+ activationScope: "scoped",
1813
+ extensions: ["pal.ui.panel", "pal.conversation.before-composer"],
1814
+ author: "PAL",
1815
+ category: "development",
1816
+ icon: "git-branch",
1817
+ tools: [],
1818
+ locales: {
1819
+ "zh-CN": {
1820
+ name: "\u53D8\u66F4\u5BA1\u67E5",
1821
+ description: "\u67E5\u770B\u6BCF\u8F6E\u6587\u4EF6\u53D8\u66F4\uFF0C\u652F\u6301 Git \u5DEE\u5F02\u5BF9\u6BD4\u3002"
1822
+ },
1823
+ zh: {
1824
+ name: "\u53D8\u66F4\u5BA1\u67E5",
1825
+ description: "\u67E5\u770B\u6BCF\u8F6E\u6587\u4EF6\u53D8\u66F4\uFF0C\u652F\u6301 Git \u5DEE\u5F02\u5BF9\u6BD4\u3002"
1826
+ }
1827
+ },
1828
+ contributions: ["runChanges"],
1829
+ consumes: {
1830
+ fileChanges: {
1831
+ contract: "pal.filesystem.changes",
1832
+ apiVersion: 1,
1833
+ transport: "reference",
1834
+ optional: true,
1835
+ autoBind: true
1836
+ }
1837
+ },
1838
+ hostRenderers: {
1839
+ review: {
1840
+ root: "dist/ui",
1841
+ entry: "host.js"
1842
+ },
1843
+ indicator: {
1844
+ root: "dist/ui",
1845
+ entry: "indicator-host.js"
1846
+ }
1847
+ },
1848
+ requiresHost: {
1849
+ "pal.command.callable": 1,
1850
+ "pal.command.dispatch": 1,
1851
+ "pal.command.execute": 1,
1852
+ "pal.plugin.hostPanel": 1,
1853
+ "pal.plugin.hostPanel.workspace": 1,
1854
+ "pal.plugin.declarations": 1,
1855
+ "pal.extension.ui.panel": 1,
1856
+ "pal.plugin.files.commands": 3,
1857
+ "pal.plugin.process.commands": 2,
1858
+ "pal.plugin.runChanges.commands": 1,
1859
+ "pal.frontend.command.isAvailable": 1,
1860
+ "pal.host.files.navigation": 1,
1861
+ "pal.plugin.hostPanel.message": 2,
1862
+ "pal.context.panels": 1,
1863
+ "pal.context.services": 1,
1864
+ "pal.extension.conversation.before-composer": 1
1865
+ },
1866
+ declarations: {
1867
+ provides: {
1868
+ commands: [
1869
+ {
1870
+ id: "pal.git.review.load",
1871
+ title: "\u8BFB\u53D6\u53D8\u66F4\u5BA1\u67E5",
1872
+ visibility: "public",
1873
+ readOnly: false,
1874
+ requiredPermissions: ["pal.fs.read", "pal.process.spawn"],
1875
+ inputSchema: {
1876
+ type: "object",
1877
+ properties: {
1878
+ scope: {
1879
+ type: "object",
1880
+ additionalProperties: false,
1881
+ properties: {
1882
+ kind: {
1883
+ enum: [
1884
+ "turn",
1885
+ "uncommitted",
1886
+ "unstaged",
1887
+ "staged",
1888
+ "commit",
1889
+ "branch"
1890
+ ]
1891
+ },
1892
+ ref: {
1893
+ type: "string",
1894
+ maxLength: 500
1895
+ }
1896
+ },
1897
+ required: ["kind"]
1898
+ },
1899
+ path: {
1900
+ type: "string",
1901
+ maxLength: 2e3
1902
+ },
1903
+ runId: {
1904
+ type: "string",
1905
+ maxLength: 200
1906
+ }
1907
+ },
1908
+ additionalProperties: false
1909
+ }
1910
+ },
1911
+ {
1912
+ id: "pal.git.review.patch",
1913
+ title: "\u751F\u6210\u5F53\u524D\u6587\u4EF6\u8865\u4E01",
1914
+ visibility: "public",
1915
+ readOnly: false,
1916
+ requiredPermissions: ["pal.fs.read", "pal.process.spawn"],
1917
+ inputSchema: {
1918
+ type: "object",
1919
+ properties: {
1920
+ scope: {
1921
+ type: "object",
1922
+ additionalProperties: false,
1923
+ properties: {
1924
+ kind: {
1925
+ enum: [
1926
+ "turn",
1927
+ "uncommitted",
1928
+ "unstaged",
1929
+ "staged",
1930
+ "commit",
1931
+ "branch"
1932
+ ]
1933
+ },
1934
+ ref: {
1935
+ type: "string",
1936
+ maxLength: 500
1937
+ }
1938
+ },
1939
+ required: ["kind"]
1940
+ },
1941
+ path: {
1942
+ type: "string",
1943
+ maxLength: 2e3
1944
+ },
1945
+ runId: {
1946
+ type: "string",
1947
+ maxLength: 200
1948
+ }
1949
+ },
1950
+ required: ["path"],
1951
+ additionalProperties: false
1952
+ }
1953
+ },
1954
+ {
1955
+ id: "pal.git.review.preview",
1956
+ title: "\u9884\u89C8\u8F6E\u6B21\u6587\u4EF6\u5DEE\u5F02",
1957
+ visibility: "private",
1958
+ readOnly: true,
1959
+ requiredPermissions: ["pal.fs.read"],
1960
+ inputSchema: {
1961
+ type: "object",
1962
+ properties: {
1963
+ runId: {
1964
+ type: "string",
1965
+ minLength: 1,
1966
+ maxLength: 200
1967
+ },
1968
+ path: {
1969
+ type: "string",
1970
+ minLength: 1,
1971
+ maxLength: 2e3
1972
+ }
1973
+ },
1974
+ required: ["runId", "path"],
1975
+ additionalProperties: false
1976
+ }
1977
+ },
1978
+ {
1979
+ id: "pal.git.review.open",
1980
+ title: "\u6253\u5F00\u8F6E\u6B21\u53D8\u66F4\u5BA1\u67E5",
1981
+ visibility: "private",
1982
+ readOnly: false,
1983
+ requiredPermissions: ["pal.fs.read"],
1984
+ inputSchema: {
1985
+ type: "object",
1986
+ properties: {
1987
+ runId: {
1988
+ type: "string",
1989
+ minLength: 1,
1990
+ maxLength: 200
1991
+ },
1992
+ path: {
1993
+ type: "string",
1994
+ minLength: 1,
1995
+ maxLength: 2e3
1996
+ }
1997
+ },
1998
+ required: ["runId"],
1999
+ additionalProperties: false
2000
+ }
2001
+ }
2002
+ ],
2003
+ ui: [
2004
+ {
2005
+ id: "pal.git.panel",
2006
+ slot: "pal.ui.panel",
2007
+ messagePresentation: true,
2008
+ description: "\u53D8\u66F4\u5BA1\u67E5\u9762\u677F\uFF0C\u56FA\u5B9A\u6253\u5F00\u65F6\u7684\u9879\u76EE\u3001\u4F1A\u8BDD\u548C\u8F6E\u6B21"
2009
+ },
2010
+ {
2011
+ id: "pal.git.indicator",
2012
+ slot: "pal.conversation.before-composer",
2013
+ description: "\u5F53\u524D\u8F6E\u6B21\u7684\u6587\u4EF6\u6539\u52A8\u63D0\u793A"
2014
+ }
2015
+ ]
2016
+ },
2017
+ consumes: {
2018
+ commands: [
2019
+ {
2020
+ id: "pal.fs.read",
2021
+ reason: "\u8BFB\u53D6\u6388\u6743\u8303\u56F4\u5185\u7684\u5DE5\u4F5C\u533A\u6587\u4EF6\u4E0E\u76EE\u5F55\u5143\u6570\u636E"
2022
+ },
2023
+ {
2024
+ id: "pal.process.start",
2025
+ reason: "\u8FD0\u884C\u6709\u754C\u7684 Git \u67E5\u8BE2"
2026
+ },
2027
+ {
2028
+ id: "pal.process.read",
2029
+ reason: "\u8BFB\u53D6 Git \u8F93\u51FA\uFF0C\u5305\u62EC\u56FE\u7247\u539F\u59CB\u5B57\u8282"
2030
+ },
2031
+ {
2032
+ id: "pal.process.release",
2033
+ reason: "\u67E5\u8BE2\u5B8C\u6210\u6216\u5931\u8D25\u540E\u91CA\u653E Git \u8FDB\u7A0B\u4E0E\u8F93\u51FA\u7F13\u5B58"
2034
+ },
2035
+ {
2036
+ id: "pal.clipboard.write",
2037
+ reason: "\u6309\u7528\u6237\u70B9\u51FB\u5C06\u5F53\u524D\u6587\u4EF6\u7684 git apply \u547D\u4EE4\u590D\u5236\u5230\u526A\u8D34\u677F\uFF0C\u4E0D\u8BFB\u53D6\u526A\u8D34\u677F"
2038
+ },
2039
+ {
2040
+ id: "pal.files.open",
2041
+ reason: "\u901A\u8FC7\u5BBF\u4E3B\u9ED8\u8BA4\u6587\u4EF6\u67E5\u770B\u5668\u6253\u5F00\u5BA1\u67E5\u6587\u4EF6\uFF0C\u4E0D\u7ED1\u5B9A\u6587\u4EF6\u7BA1\u7406\u5668\u63D2\u4EF6"
2042
+ },
2043
+ {
2044
+ id: "pal.toast.show",
2045
+ reason: "\u63D0\u793A\u590D\u5236\u6210\u529F\u6216\u5931\u8D25\uFF0C\u4EE5\u53CA\u5237\u65B0\u3001\u5207\u6362\u8303\u56F4\u3001\u6253\u5F00\u6587\u4EF6\u5931\u8D25"
2046
+ },
2047
+ {
2048
+ id: "pal.host.interaction.close",
2049
+ reason: "\u63D0\u793A\u590D\u5236\u6210\u529F\u6216\u5931\u8D25\uFF0C\u4EE5\u53CA\u5237\u65B0\u3001\u5207\u6362\u8303\u56F4\u3001\u6253\u5F00\u6587\u4EF6\u5931\u8D25"
2050
+ },
2051
+ {
2052
+ id: "pal.host.interaction.list",
2053
+ reason: "\u63D0\u793A\u590D\u5236\u6210\u529F\u6216\u5931\u8D25\uFF0C\u4EE5\u53CA\u5237\u65B0\u3001\u5207\u6362\u8303\u56F4\u3001\u6253\u5F00\u6587\u4EF6\u5931\u8D25"
2054
+ },
2055
+ {
2056
+ id: "pal.host.interaction.respond",
2057
+ reason: "\u63D0\u793A\u590D\u5236\u6210\u529F\u6216\u5931\u8D25\uFF0C\u4EE5\u53CA\u5237\u65B0\u3001\u5207\u6362\u8303\u56F4\u3001\u6253\u5F00\u6587\u4EF6\u5931\u8D25"
2058
+ },
2059
+ {
2060
+ id: "pal.host.interaction.action",
2061
+ reason: "\u63D0\u793A\u590D\u5236\u6210\u529F\u6216\u5931\u8D25\uFF0C\u4EE5\u53CA\u5237\u65B0\u3001\u5207\u6362\u8303\u56F4\u3001\u6253\u5F00\u6587\u4EF6\u5931\u8D25"
2062
+ },
2063
+ {
2064
+ id: "pal.frontend.context",
2065
+ reason: "\u4F7F\u7528\u5DF2\u58F0\u660E\u524D\u7AEF\u7684\u5BBF\u4E3B\u80FD\u529B"
2066
+ }
2067
+ ]
2068
+ }
2069
+ }
2070
+ };
2071
+ var scope = new import_node_async_hooks2.AsyncLocalStorage();
2072
+ function withCommands(commands, operation) {
2073
+ if (!commands)
2074
+ throw new Error("Host command access unavailable; upgrade the host");
2075
+ return scope.run(commands, operation);
2076
+ }
2077
+ function execute(id2, input) {
2078
+ const commands = scope.getStore();
2079
+ if (!commands) throw new Error("Operation outside bound command scope");
2080
+ return commands.execute(id2, input);
2081
+ }
2082
+ var info = (value) => ({
2083
+ ...value,
2084
+ isFile: () => value.file,
2085
+ isDirectory: () => value.directory,
2086
+ isSymbolicLink: () => value.symlink
2087
+ });
2088
+ var realpath2 = (path) => execute("pal.fs.read", { operation: "realpath", path });
2089
+ var readlink2 = (path) => execute("pal.fs.read", { operation: "readlink", path });
2090
+ var lstat2 = async (path) => info(await execute("pal.fs.read", { operation: "lstat", path }));
2091
+ async function readFile2(path, encoding) {
2092
+ const result = await execute("pal.fs.read", {
2093
+ path,
2094
+ encoding: encoding ?? "base64"
2095
+ });
2096
+ return encoding ? result.content : Buffer.from(result.content, "base64");
2097
+ }
2098
+ function isRemotePath2(path) {
2099
+ return typeof path === "string" && path.startsWith("ssh://");
2100
+ }
2101
+ function remotePath(path) {
2102
+ const url = new URL(path);
2103
+ if (url.protocol !== "ssh:" || !/^[a-zA-Z0-9-]+$/.test(url.hostname) || url.username || url.password || url.port || url.search || url.hash)
2104
+ throw new Error("Invalid remote workspace path");
2105
+ const decoded = decodeURIComponent(url.pathname);
2106
+ if (decoded.includes("\0") || decoded.includes("\\"))
2107
+ throw new Error("Invalid remote path");
2108
+ return { profileId: url.hostname, path: import_node_path2.posix.normalize(decoded) };
2109
+ }
2110
+ function workspaceUri(profileId, path) {
2111
+ if (!/^[a-zA-Z0-9-]+$/.test(profileId) || !import_node_path2.posix.isAbsolute(path) || /[\0\\]/.test(path))
2112
+ throw new Error("Invalid remote workspace");
2113
+ return `ssh://${profileId}${import_node_path2.posix.normalize(path).split("/").map(encodeURIComponent).join("/")}`;
2114
+ }
2115
+ function join(...parts) {
2116
+ if (!isRemotePath2(parts[0])) return import_node_path2.default.join(...parts);
2117
+ const root = remotePath(parts[0]);
2118
+ return workspaceUri(root.profileId, import_node_path2.posix.join(root.path, ...parts.slice(1)));
2119
+ }
2120
+ function resolve(...parts) {
2121
+ const base = parts.findIndex(isRemotePath2);
2122
+ if (base < 0) return import_node_path2.default.resolve(...parts);
2123
+ const root = remotePath(parts[base]);
2124
+ const rest = parts.slice(base + 1).map((part) => {
2125
+ if (!isRemotePath2(part)) return part;
2126
+ const target = remotePath(part);
2127
+ if (target.profileId !== root.profileId)
2128
+ throw new Error("Different SSH connections");
2129
+ return target.path;
2130
+ });
2131
+ return workspaceUri(root.profileId, import_node_path2.posix.resolve(root.path, ...rest));
2132
+ }
2133
+ function dirname(path) {
2134
+ if (!isRemotePath2(path)) return import_node_path2.default.dirname(path);
2135
+ const root = remotePath(path);
2136
+ return workspaceUri(root.profileId, import_node_path2.posix.dirname(root.path));
2137
+ }
2138
+ function relative(from, to) {
2139
+ if (!isRemotePath2(from) && !isRemotePath2(to))
2140
+ return import_node_path2.default.relative(from, to);
2141
+ if (!isRemotePath2(from)) throw new Error("Mixed local and remote paths");
2142
+ const root = remotePath(from);
2143
+ const target = isRemotePath2(to) ? remotePath(to) : { profileId: root.profileId, path: to };
2144
+ if (target.profileId !== root.profileId)
2145
+ throw new Error("Different SSH connections");
2146
+ return import_node_path2.posix.relative(root.path, target.path);
2147
+ }
2148
+ var isAbsolute = (path) => isRemotePath2(path) || import_node_path2.default.isAbsolute(path) || import_node_path2.posix.isAbsolute(path);
2149
+ var sep2 = import_node_path2.default.sep;
2150
+ async function runGit(cwd, args, signal, binary) {
2151
+ signal.throwIfAborted();
2152
+ const resource = await execute("pal.process.start", {
2153
+ mode: "pipe",
2154
+ lifetime: "request",
2155
+ executable: "git",
2156
+ args: [
2157
+ "--no-pager",
2158
+ "--literal-pathspecs",
2159
+ "-c",
2160
+ "core.hooksPath=",
2161
+ ...args
2162
+ ],
2163
+ cwd,
2164
+ timeoutMs: 3e4,
2165
+ maxBufferChars: 24 * 1024 * 1024,
2166
+ stdoutEncoding: "base64",
2167
+ env: {
2168
+ ...Object.fromEntries(
2169
+ Object.keys(process.env).filter((k) => k.toUpperCase().startsWith("GIT_")).map((k) => [k, null])
2170
+ ),
2171
+ GIT_TERMINAL_PROMPT: "0",
2172
+ GIT_OPTIONAL_LOCKS: "0"
2173
+ }
2174
+ });
2175
+ const chunks = [];
2176
+ let cursor = 0, bytes = 0, stderr = "", encoded = "";
2177
+ const limit = binary ? 16 * 1024 * 1024 : 2 * 1024 * 1024;
2178
+ try {
2179
+ for (; ; ) {
2180
+ signal.throwIfAborted();
2181
+ const result = await execute("pal.process.read", {
2182
+ processId: resource.processId,
2183
+ cursor,
2184
+ maxChars: 65536,
2185
+ waitMs: 1e3
2186
+ });
2187
+ cursor = result.nextCursor;
2188
+ if (result.lostOutput) throw new Error("Git output exceeded host buffer");
2189
+ for (const chunk of result.chunks) {
2190
+ if (chunk.stream === "stdout") {
2191
+ encoded += chunk.data;
2192
+ const frames = encoded.split("\n");
2193
+ encoded = frames.pop();
2194
+ for (const frame of frames) {
2195
+ const value = Buffer.from(frame, "base64");
2196
+ chunks.push(value);
2197
+ bytes += value.length;
2198
+ }
2199
+ } else stderr = (stderr + chunk.data).slice(-8192);
2200
+ }
2201
+ if (bytes > limit) throw new Error("Git output exceeds review limit");
2202
+ if (result.status !== "exited" || result.hasMore) continue;
2203
+ signal.throwIfAborted();
2204
+ if (result.exit?.code !== 0)
2205
+ throw new Error(
2206
+ stderr.trim() || `Git failed (${result.exit?.reason ?? result.exit?.code})`
2207
+ );
2208
+ if (encoded) throw new Error("Incomplete binary output frame");
2209
+ return Buffer.concat(chunks);
2210
+ }
2211
+ } finally {
2212
+ await execute("pal.process.release", { processId: resource.processId }).catch(
2213
+ () => {
2214
+ }
2215
+ );
2216
+ }
2217
+ }
2218
+ async function git(cwd, args, signal) {
2219
+ return (await runGit(cwd, args, signal, false)).toString("utf8");
2220
+ }
2221
+ function gitBytes(cwd, args, signal) {
2222
+ return runGit(cwd, args, signal, true);
2223
+ }
2224
+ async function repository(context) {
2225
+ if (!context.workspacePath)
2226
+ throw new Error("A project workspace is required");
2227
+ const workspace = await realpath2(context.workspacePath);
2228
+ const root = await realpath2(
2229
+ resolve(
2230
+ workspace,
2231
+ (await git(workspace, ["rev-parse", "--show-toplevel"], context.signal)).trim()
2232
+ )
2233
+ );
2234
+ if (relative(workspace, root) !== "")
2235
+ throw new Error("Open the repository root as the project workspace");
2236
+ return root;
2237
+ }
2238
+ function selectedPaths(paths, required = false) {
2239
+ if (paths === void 0 && !required) return [];
2240
+ if (!Array.isArray(paths) || !paths.length || paths.length > 100)
2241
+ throw new Error("Select 1\u2013100 explicit paths");
2242
+ return paths.map((path) => {
2243
+ if (typeof path !== "string" || !path || path.length > 2e3 || isAbsolute(path) || /^[A-Za-z]:/.test(path) || path.includes("\0") || path.split(/[\\/]/).some((part) => part === ".." || part.toLowerCase() === ".git"))
2244
+ throw new Error("Invalid repository-relative path");
2245
+ return path;
2246
+ });
2247
+ }
2248
+ async function reviewOptions(context, rootHint) {
2249
+ const root = rootHint ?? await repository(context).catch(() => void 0);
2250
+ if (!root) return void 0;
2251
+ const [log, refs, currentBranch] = await Promise.all([
2252
+ git(root, ["log", "-20", "--format=%H%x09%s%x09%aI"], context.signal).catch(
2253
+ () => ""
2254
+ ),
2255
+ git(
2256
+ root,
2257
+ [
2258
+ "for-each-ref",
2259
+ "--count=100",
2260
+ "--format=%(refname)%09%(refname:short)%09%(symref)",
2261
+ "refs/heads/",
2262
+ "refs/remotes/"
2263
+ ],
2264
+ context.signal
2265
+ ),
2266
+ git(root, ["symbolic-ref", "--short", "HEAD"], context.signal).catch(
2267
+ () => "HEAD"
2268
+ )
2269
+ ]);
2270
+ const parse = (value) => value.trim().split("\n").filter(Boolean).map((line) => {
2271
+ const [ref, label, target] = line.trim().split(" ");
2272
+ return { ref, label, target };
2273
+ });
2274
+ const branches = parse(refs).filter((item) => !item.target);
2275
+ const defaultTargetBranch = parse(refs).find(
2276
+ (item) => item.ref === "refs/remotes/origin/HEAD"
2277
+ )?.target;
2278
+ return {
2279
+ ...defaultTargetBranch && branches.some((item) => item.ref === defaultTargetBranch) ? { defaultTargetBranch } : {},
2280
+ commits: log.trim().split("\n").filter(Boolean).map((line) => {
2281
+ const [ref, label, date] = line.split(" ");
2282
+ return { ref, label, date };
2283
+ }),
2284
+ branches: branches.map(({ ref, label }) => ({ ref, label })),
2285
+ currentBranch: currentBranch.trim()
2286
+ };
2287
+ }
2288
+ var ReviewCommands = class {
2289
+ constructor(changes) {
2290
+ this.changes = changes;
2291
+ }
2292
+ async card(input, execution) {
2293
+ if (!input.runId) throw new Error("Missing turn resource");
2294
+ const review = await this.changes.load(execution.context, input.runId);
2295
+ execution.context.signal.throwIfAborted();
2296
+ const summary = this.changes.summary(review);
2297
+ const files = summary.files.filter(
2298
+ (file) => !/^generated-images\/[0-9a-f-]{36}\/(?:image\.(?:png|jpg)|metadata\.json)$/.test(
2299
+ file.path.replaceAll("\\", "/")
2300
+ )
2301
+ );
2302
+ return {
2303
+ ...summary,
2304
+ runId: review.runId,
2305
+ files,
2306
+ added: files.reduce((total, file) => total + file.added, 0),
2307
+ removed: files.reduce((total, file) => total + file.removed, 0)
2308
+ };
2309
+ }
2310
+ /** Hover only reads the captured turn; it never queries the working tree. */
2311
+ async preview(input, execution) {
2312
+ if (!input.runId || !input.path)
2313
+ throw new Error("Missing preview resource");
2314
+ const review = await this.changes.load(execution.context, input.runId);
2315
+ execution.context.signal.throwIfAborted();
2316
+ const file = review.files.find((item) => item.path === input.path);
2317
+ if (!file) return { preview: true };
2318
+ const {
2319
+ beforeImage: _beforeImage,
2320
+ afterImage: _afterImage,
2321
+ ...selected
2322
+ } = file;
2323
+ const text = (file.before ?? "") + (file.after ?? "");
2324
+ if (text.length > 3e5 || text.split("\n").length > 6e3) {
2325
+ return {
2326
+ preview: true,
2327
+ selected: {
2328
+ path: file.path,
2329
+ added: file.added,
2330
+ removed: file.removed,
2331
+ status: file.status,
2332
+ unavailable: "large"
2333
+ }
2334
+ };
2335
+ }
2336
+ return { preview: true, selected };
2337
+ }
2338
+ load(input, execution) {
2339
+ return withCommands(execution.command, async () => {
2340
+ const context = execution.context;
2341
+ const resource = execution.request.resource ? JSON.parse(execution.request.resource) : {};
2342
+ const runId = input.runId ?? resource.runId;
2343
+ let gitError = false;
2344
+ const failedGit = (cause) => {
2345
+ context.signal.throwIfAborted();
2346
+ if (!/not a git repository/i.test(String(cause))) {
2347
+ gitError = true;
2348
+ console.warn("Review Git discovery failed", cause);
2349
+ }
2350
+ return void 0;
2351
+ };
2352
+ const root = await repository(context).catch(failedGit);
2353
+ const optionsPending = root ? reviewOptions(context, root).catch(failedGit) : Promise.resolve(void 0);
2354
+ void optionsPending.catch(() => {
2355
+ });
2356
+ const options = input.scope?.kind === "branch" || input.scope?.kind === "commit" ? await optionsPending : void 0;
2357
+ context.signal.throwIfAborted();
2358
+ let scope2 = input.scope ?? {
2359
+ kind: runId || !root ? "turn" : "uncommitted"
2360
+ };
2361
+ if (scope2.kind === "branch" && !scope2.ref && options?.defaultTargetBranch)
2362
+ scope2 = { kind: "branch", ref: options.defaultTargetBranch };
2363
+ const review = scope2.kind === "branch" && !scope2.ref ? {
2364
+ projectId: context.projectId,
2365
+ sessionId: context.sessionId,
2366
+ runId: "",
2367
+ files: [],
2368
+ added: 0,
2369
+ removed: 0
2370
+ } : scope2.kind === "turn" ? (runId ? await this.changes.load(context, runId) : await this.changes.latest(context)) ?? {
2371
+ projectId: context.projectId,
2372
+ sessionId: context.sessionId,
2373
+ runId: "",
2374
+ files: [],
2375
+ added: 0,
2376
+ removed: 0
2377
+ } : await this.changes.current(context, scope2, root, options);
2378
+ const requested = input.path ?? resource.path;
2379
+ const path = review.files.some((file) => file.path === requested) ? requested : review.files[0]?.path;
2380
+ const pending = /* @__PURE__ */ new Map();
2381
+ const loadFile = (path2) => {
2382
+ let file = pending.get(path2);
2383
+ if (!file) {
2384
+ file = this.changes.currentFile(context, review, path2, root);
2385
+ pending.set(path2, file);
2386
+ }
2387
+ return file;
2388
+ };
2389
+ const [selectedFile, contents] = await Promise.all([
2390
+ path ? loadFile(path) : void 0,
2391
+ review.files.length <= 8 ? review.runId ? review.files : Promise.all(review.files.map((file) => loadFile(file.path))) : void 0
2392
+ ]);
2393
+ let selected = selectedFile;
2394
+ if (selected && Buffer.byteLength(JSON.stringify(selected)) > 6 * 1024 * 1024) {
2395
+ const { beforeImage, afterImage, ...metadata } = selected;
2396
+ selected = { ...metadata, unavailable: "budget" };
2397
+ }
2398
+ const complete = contents?.filter((file) => !!file);
2399
+ const overview = complete && complete.reduce(
2400
+ (sum, file) => sum + Buffer.byteLength(file.before ?? "") + Buffer.byteLength(file.after ?? "") + Buffer.byteLength(file.beforeImage ?? "") + Buffer.byteLength(file.afterImage ?? ""),
2401
+ 0
2402
+ ) <= 2 * 1024 * 1024 ? complete : void 0;
2403
+ const resolvedOptions = options ?? await optionsPending;
2404
+ context.signal.throwIfAborted();
2405
+ return {
2406
+ mode: review.runId ? "turn" : "workspace",
2407
+ ...resource.path ? { navigation: { path: resource.path } } : {},
2408
+ runId: review.runId,
2409
+ scope: scope2,
2410
+ ...resolvedOptions ? { git: resolvedOptions } : {},
2411
+ ...gitError ? { gitError: true } : {},
2412
+ ...overview ? { overview } : {},
2413
+ files: review.files.map(
2414
+ ({ before, after, beforeImage, afterImage, ...file }) => file
2415
+ ),
2416
+ added: review.added,
2417
+ removed: review.removed,
2418
+ incomplete: review.incomplete,
2419
+ ...selected ? { selected } : {}
2420
+ };
2421
+ });
2422
+ }
2423
+ async patch(input, execution) {
2424
+ const review = await this.load(input, execution);
2425
+ const file = review.selected;
2426
+ if (!file || file.path !== input.path || file.unavailable)
2427
+ throw new Error("No patch available for this file");
2428
+ const patch = (0, import_diff.createTwoFilesPatch)(
2429
+ file.status === "added" ? "/dev/null" : `a/${file.path}`,
2430
+ file.status === "deleted" ? "/dev/null" : `b/${file.path}`,
2431
+ file.before ?? "",
2432
+ file.after ?? ""
2433
+ );
2434
+ if (Buffer.byteLength(patch) > 1024 * 1024)
2435
+ throw new Error("Patch is too large to copy");
2436
+ execution.context.signal.throwIfAborted();
2437
+ return { patch };
2438
+ }
2439
+ };
2440
+ var FILE_LIMIT = 1024 * 1024;
2441
+ var contentLimit = (path) => /\.(png|jpe?g|webp|gif)$/i.test(path) ? 8 * 1024 * 1024 : FILE_LIMIT;
2442
+ var TOTAL_LIMIT = 32 * 1024 * 1024;
2443
+ var digest = (value) => (0, import_node_crypto.createHash)("sha256").update(value).digest("hex");
2444
+ function content(buffer) {
2445
+ const hash = digest(buffer);
2446
+ const mime = buffer.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])) ? "image/png" : buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255 ? "image/jpeg" : buffer.toString("ascii", 0, 4) === "RIFF" && buffer.toString("ascii", 8, 12) === "WEBP" ? "image/webp" : /^GIF8[79]a$/.test(buffer.toString("ascii", 0, 6)) ? "image/gif" : void 0;
2447
+ if (mime)
2448
+ return {
2449
+ hash,
2450
+ unavailable: "binary",
2451
+ image: `data:${mime};base64,${buffer.toString("base64")}`
2452
+ };
2453
+ if (buffer.includes(0)) return { hash, unavailable: "binary" };
2454
+ try {
2455
+ return {
2456
+ hash,
2457
+ text: new TextDecoder("utf-8", { fatal: true }).decode(buffer)
2458
+ };
2459
+ } catch {
2460
+ return { hash, unavailable: "encoding" };
2461
+ }
2462
+ }
2463
+ async function workingFile(root, path) {
2464
+ selectedPaths([path], true);
2465
+ const target = join(root, path);
2466
+ const stat2 = await lstat2(target).catch((error) => {
2467
+ if (error.code === "ENOENT" || error.code === "ENOTDIR") return null;
2468
+ throw error;
2469
+ });
2470
+ if (!stat2) return null;
2471
+ if (stat2.isSymbolicLink())
2472
+ return { hash: digest(await readlink2(target)), unavailable: "symlink" };
2473
+ if (!stat2.isFile())
2474
+ return { hash: String(stat2.mtimeMs), unavailable: "directory" };
2475
+ if (stat2.size > contentLimit(path))
2476
+ return { hash: `${stat2.size}:${stat2.mtimeMs}`, unavailable: "large" };
2477
+ return content(await readFile2(target));
2478
+ }
2479
+ async function headFile(root, head, path, signal, knownExists = false) {
2480
+ if (!head) return null;
2481
+ if (head === "INDEX") {
2482
+ const entries2 = await git(
2483
+ root,
2484
+ ["ls-files", "--stage", "-z", "--", path],
2485
+ signal
2486
+ );
2487
+ const item = entries2.split("\0").find((line) => line.split(" ")[0]?.endsWith(" 0"));
2488
+ if (!item) return null;
2489
+ const id3 = item.split(" ")[0].split(" ")[1];
2490
+ if (Number((await git(root, ["cat-file", "-s", id3], signal)).trim()) > contentLimit(path))
2491
+ return { hash: id3, unavailable: "large" };
2492
+ return content(await gitBytes(root, ["cat-file", "blob", id3], signal));
2493
+ }
2494
+ if (knownExists) {
2495
+ const object2 = `${head}:${path}`;
2496
+ const size2 = Number(
2497
+ (await git(root, ["cat-file", "-s", object2], signal)).trim()
2498
+ );
2499
+ if (size2 > contentLimit(path))
2500
+ return { hash: object2, unavailable: "large" };
2501
+ return content(await gitBytes(root, ["cat-file", "blob", object2], signal));
2502
+ }
2503
+ const object = await git(root, ["ls-tree", "-z", head, "--", path], signal);
2504
+ if (!object) return null;
2505
+ const id2 = object.split(" ")[0].split(" ").at(-1);
2506
+ const size = Number((await git(root, ["cat-file", "-s", id2], signal)).trim());
2507
+ if (size > contentLimit(path)) return { hash: id2, unavailable: "large" };
2508
+ return content(await gitBytes(root, ["cat-file", "blob", id2], signal));
2509
+ }
2510
+ async function headOf(root, signal) {
2511
+ return git(root, ["rev-parse", "--verify", "HEAD"], signal).then(
2512
+ (value) => value.trim(),
2513
+ () => void 0
2514
+ );
2515
+ }
2516
+ function changed(path, before, after) {
2517
+ if (before?.hash === after?.hash || !before && !after) return void 0;
2518
+ const status = !before ? "added" : !after ? "deleted" : "modified";
2519
+ const unavailable = before?.unavailable ?? after?.unavailable;
2520
+ const left = before?.text ?? "", right = after?.text ?? "";
2521
+ const diff = unavailable ? void 0 : (0, import_diff2.diffLines)(left, right, { timeout: 150, maxEditLength: 2e4 });
2522
+ return {
2523
+ path,
2524
+ status,
2525
+ added: diff?.reduce((sum, part) => sum + (part.added ? part.count : 0), 0) ?? 0,
2526
+ removed: diff?.reduce((sum, part) => sum + (part.removed ? part.count : 0), 0) ?? 0,
2527
+ ...unavailable || !diff ? { unavailable: unavailable ?? "complex" } : {},
2528
+ ...!unavailable ? { before: left, after: right } : {},
2529
+ ...before?.image ? { beforeImage: before.image } : {},
2530
+ ...after?.image ? { afterImage: after.image } : {}
2531
+ };
2532
+ }
2533
+ var WorkspaceChangeReview = class {
2534
+ constructor(storage) {
2535
+ this.storage = storage;
2536
+ }
2537
+ active = /* @__PURE__ */ new Map();
2538
+ activeReview(sessionId) {
2539
+ return this.active.get(sessionId);
2540
+ }
2541
+ path(session, run) {
2542
+ return join(
2543
+ this.storage,
2544
+ "turn-changes",
2545
+ digest(session),
2546
+ digest(run) + ".json"
2547
+ );
2548
+ }
2549
+ beginEvents(context, service, changedUi) {
2550
+ const review = {
2551
+ projectId: context.projectId,
2552
+ sessionId: context.sessionId,
2553
+ runId: context.runId,
2554
+ files: [],
2555
+ added: 0,
2556
+ removed: 0
2557
+ };
2558
+ const originals = /* @__PURE__ */ new Map();
2559
+ const pending = /* @__PURE__ */ new Map();
2560
+ const virtualAfter = /* @__PURE__ */ new Map();
2561
+ const sizes = /* @__PURE__ */ new Map();
2562
+ let storedBytes = 0;
2563
+ const stream = service.subscribe("applied", {
2564
+ projectId: context.projectId,
2565
+ sessionId: context.sessionId,
2566
+ signal: context.lifetimeSignal ?? context.signal
2567
+ });
2568
+ this.active.set(context.sessionId, review);
2569
+ let barrier;
2570
+ let incomplete = false;
2571
+ void (async () => {
2572
+ try {
2573
+ for await (const raw of stream) {
2574
+ const event = raw;
2575
+ if (event.runId !== context.runId) continue;
2576
+ if (event.type === "barrier") {
2577
+ if (event.token === barrier?.token) barrier.done();
2578
+ continue;
2579
+ }
2580
+ if (event.type === "preview" || event.type === "preview-clear") {
2581
+ if (event.type === "preview" && event.path)
2582
+ pending.set(event.toolCallId, {
2583
+ toolCallId: event.toolCallId,
2584
+ path: event.path,
2585
+ added: event.added ?? 0,
2586
+ removed: event.removed ?? 0
2587
+ });
2588
+ else pending.delete(event.toolCallId);
2589
+ review.pending = [...pending.values()];
2590
+ changedUi();
2591
+ continue;
2592
+ }
2593
+ if (event.toolCallId) pending.delete(event.toolCallId);
2594
+ review.pending = [...pending.values()];
2595
+ if (!originals.has(event.path) && originals.size >= 2e3) {
2596
+ incomplete = true;
2597
+ continue;
2598
+ }
2599
+ const previous = virtualAfter.get(event.path);
2600
+ let after = event.after;
2601
+ if (previous !== void 0 && previous !== event.before) {
2602
+ const patch = (0, import_diff2.createTwoFilesPatch)(
2603
+ event.path,
2604
+ event.path,
2605
+ event.before ?? "",
2606
+ event.after
2607
+ );
2608
+ const merged = (0, import_diff2.applyPatch)(previous, patch);
2609
+ if (merged === false) {
2610
+ incomplete = true;
2611
+ continue;
2612
+ }
2613
+ after = merged;
2614
+ }
2615
+ const before = originals.has(event.path) ? originals.get(event.path) ?? null : event.before;
2616
+ const nextBytes = Buffer.byteLength(before ?? "") + Buffer.byteLength(after);
2617
+ if (storedBytes - (sizes.get(event.path) ?? 0) + nextBytes > TOTAL_LIMIT) {
2618
+ incomplete = true;
2619
+ continue;
2620
+ }
2621
+ storedBytes += nextBytes - (sizes.get(event.path) ?? 0);
2622
+ sizes.set(event.path, nextBytes);
2623
+ if (!originals.has(event.path)) originals.set(event.path, before);
2624
+ virtualAfter.set(event.path, after);
2625
+ const file = changed(
2626
+ event.path,
2627
+ before === null ? null : content(Buffer.from(before)),
2628
+ content(Buffer.from(after))
2629
+ );
2630
+ review.files = review.files.filter(
2631
+ (item) => item.path !== event.path
2632
+ );
2633
+ if (file) review.files.push(file);
2634
+ review.added = review.files.reduce(
2635
+ (sum, item) => sum + item.added,
2636
+ 0
2637
+ );
2638
+ review.removed = review.files.reduce(
2639
+ (sum, item) => sum + item.removed,
2640
+ 0
2641
+ );
2642
+ changedUi();
2643
+ }
2644
+ } catch {
2645
+ incomplete = true;
2646
+ }
2647
+ })();
2648
+ return {
2649
+ finish: async (signal) => {
2650
+ pending.clear();
2651
+ review.pending = [];
2652
+ changedUi();
2653
+ if (!signal.aborted && !(context.lifetimeSignal ?? context.signal).aborted) {
2654
+ const token = (0, import_node_crypto.randomUUID)();
2655
+ const arrival = new Promise((resolve2) => {
2656
+ barrier = { token, done: resolve2 };
2657
+ });
2658
+ try {
2659
+ await service.call(
2660
+ "barrier",
2661
+ { runId: context.runId, token },
2662
+ {
2663
+ projectId: context.projectId,
2664
+ sessionId: context.sessionId,
2665
+ signal
2666
+ }
2667
+ );
2668
+ let timer;
2669
+ try {
2670
+ await Promise.race([
2671
+ arrival,
2672
+ new Promise((_, reject) => {
2673
+ timer = setTimeout(
2674
+ () => reject(new Error("Change event barrier timed out")),
2675
+ 1e4
2676
+ );
2677
+ })
2678
+ ]);
2679
+ } finally {
2680
+ clearTimeout(timer);
2681
+ }
2682
+ } catch {
2683
+ incomplete = true;
2684
+ }
2685
+ } else incomplete = true;
2686
+ try {
2687
+ await stream.return?.();
2688
+ } catch {
2689
+ incomplete = true;
2690
+ }
2691
+ if (this.active.get(context.sessionId) === review)
2692
+ this.active.delete(context.sessionId);
2693
+ changedUi();
2694
+ if (!review.files.length) return void 0;
2695
+ if (incomplete) review.incomplete = true;
2696
+ const target = this.path(context.sessionId, context.runId);
2697
+ await (0, import_promises.mkdir)(dirname(target), { recursive: true });
2698
+ const temporary = `${target}.${(0, import_node_crypto.randomUUID)()}.tmp`;
2699
+ await (0, import_promises.writeFile)(temporary, JSON.stringify(review));
2700
+ await (0, import_promises.rename)(temporary, target);
2701
+ await (0, import_promises.writeFile)(
2702
+ join(dirname(target), "latest.json"),
2703
+ JSON.stringify({ runId: context.runId })
2704
+ );
2705
+ return this.summary(review);
2706
+ },
2707
+ dispose: () => {
2708
+ void stream.return?.();
2709
+ if (this.active.get(context.sessionId) === review)
2710
+ this.active.delete(context.sessionId);
2711
+ }
2712
+ };
2713
+ }
2714
+ summary(review) {
2715
+ return {
2716
+ panelId: "pal.git.panel",
2717
+ resource: JSON.stringify({ runId: review.runId }),
2718
+ files: review.files.map(
2719
+ ({
2720
+ before: _before,
2721
+ after: _after,
2722
+ beforeImage: _bi,
2723
+ afterImage: _ai,
2724
+ ...file
2725
+ }) => ({
2726
+ ...file,
2727
+ resource: JSON.stringify({ runId: review.runId, path: file.path })
2728
+ })
2729
+ ),
2730
+ added: review.added,
2731
+ removed: review.removed,
2732
+ ...review.incomplete ? { incomplete: true } : {}
2733
+ };
2734
+ }
2735
+ async load(context, runId) {
2736
+ const active = this.active.get(context.sessionId);
2737
+ if (active?.runId === runId && active.projectId === context.projectId)
2738
+ return structuredClone(active);
2739
+ const review = JSON.parse(
2740
+ await (0, import_promises.readFile)(this.path(context.sessionId, runId), "utf8")
2741
+ );
2742
+ if (review.projectId !== context.projectId || review.sessionId !== context.sessionId || review.runId !== runId)
2743
+ throw new Error("Change review scope mismatch");
2744
+ return review;
2745
+ }
2746
+ async current(context, scope2 = { kind: "uncommitted" }, rootHint, optionsHint) {
2747
+ const root = rootHint ?? await repository(context).catch(() => void 0);
2748
+ if (!root) {
2749
+ if (!["turn", "uncommitted"].includes(scope2.kind))
2750
+ throw Error("Git comparison is unavailable in this workspace");
2751
+ const latest = await (0, import_promises.readFile)(
2752
+ join(dirname(this.path(context.sessionId, "")), "latest.json"),
2753
+ "utf8"
2754
+ ).then(
2755
+ (value) => JSON.parse(value),
2756
+ () => void 0
2757
+ );
2758
+ if (latest) return this.load(context, latest.runId);
2759
+ return {
2760
+ projectId: context.projectId,
2761
+ sessionId: context.sessionId,
2762
+ runId: "",
2763
+ files: [],
2764
+ added: 0,
2765
+ removed: 0
2766
+ };
2767
+ }
2768
+ let head = await headOf(root, context.signal), targetRef;
2769
+ let comparison = ["diff"];
2770
+ if (!head && scope2.kind === "uncommitted") comparison.push("--cached");
2771
+ if (scope2.kind === "staged") {
2772
+ targetRef = "INDEX";
2773
+ comparison.push("--cached");
2774
+ }
2775
+ if (scope2.kind === "unstaged") head = "INDEX";
2776
+ if (scope2.kind === "commit" || scope2.kind === "branch") {
2777
+ const options = optionsHint ?? await reviewOptions(context, root);
2778
+ const list = scope2.kind === "commit" ? options?.commits : options?.branches;
2779
+ if (!scope2.ref || !list?.some((item) => item.ref === scope2.ref))
2780
+ throw Error("Selected revision is unavailable");
2781
+ if (scope2.kind === "commit") {
2782
+ targetRef = scope2.ref;
2783
+ head = (await git(
2784
+ root,
2785
+ ["rev-list", "--parents", "-n", "1", scope2.ref],
2786
+ context.signal
2787
+ )).trim().split(" ")[1];
2788
+ if (!head) comparison = ["diff-tree", "--root", "--no-commit-id", "-r"];
2789
+ } else {
2790
+ if (!head) throw Error("Create a commit before comparing branches");
2791
+ targetRef = head;
2792
+ head = (await git(root, ["merge-base", "HEAD", scope2.ref], context.signal)).trim();
2793
+ }
2794
+ }
2795
+ const revisions = comparison[0] === "diff-tree" ? [targetRef] : [
2796
+ ...head && head !== "INDEX" ? [head] : [],
2797
+ ...targetRef && targetRef !== "INDEX" ? [targetRef] : []
2798
+ ];
2799
+ const command = (format) => [
2800
+ ...comparison,
2801
+ format,
2802
+ "-z",
2803
+ "--no-renames",
2804
+ ...revisions,
2805
+ "--"
2806
+ ];
2807
+ const [numbers, statusOutput, untracked] = await Promise.all([
2808
+ git(root, command("--numstat"), context.signal),
2809
+ git(root, command("--name-status"), context.signal),
2810
+ !targetRef ? git(
2811
+ root,
2812
+ ["ls-files", "-z", "--others", "--exclude-standard"],
2813
+ context.signal
2814
+ ) : ""
2815
+ ]);
2816
+ const statuses = statusOutput.split("\0");
2817
+ const kinds = /* @__PURE__ */ new Map();
2818
+ for (let i = 0; i < statuses.length - 1; i += 2)
2819
+ kinds.set(statuses[i + 1], statuses[i]);
2820
+ const paths = [
2821
+ .../* @__PURE__ */ new Set([...kinds.keys(), ...untracked.split("\0").filter(Boolean)])
2822
+ ];
2823
+ const files = [];
2824
+ const stats = new Map(
2825
+ numbers.split("\0").filter(Boolean).map((record) => {
2826
+ const [added, removed, ...path] = record.split(" ");
2827
+ return [path.join(" "), { added, removed }];
2828
+ })
2829
+ );
2830
+ for (const path of paths.slice(0, 2e3)) {
2831
+ const stat2 = stats.get(path);
2832
+ if (stat2 && (head || targetRef))
2833
+ files.push({
2834
+ path,
2835
+ status: kinds.get(path) === "D" ? "deleted" : kinds.get(path) === "A" ? "added" : "modified",
2836
+ added: Number(stat2.added) || 0,
2837
+ removed: Number(stat2.removed) || 0,
2838
+ ...stat2.added === "-" ? { unavailable: "binary" } : {}
2839
+ });
2840
+ else {
2841
+ const file = changed(path, null, await workingFile(root, path));
2842
+ if (file) {
2843
+ delete file.before;
2844
+ delete file.after;
2845
+ delete file.beforeImage;
2846
+ delete file.afterImage;
2847
+ files.push(file);
2848
+ }
2849
+ }
2850
+ }
2851
+ return {
2852
+ projectId: context.projectId,
2853
+ sessionId: context.sessionId,
2854
+ runId: "",
2855
+ files,
2856
+ ...head ? { baseHead: head } : {},
2857
+ ...targetRef ? { targetRef } : {},
2858
+ added: files.reduce((sum, file) => sum + file.added, 0),
2859
+ removed: files.reduce((sum, file) => sum + file.removed, 0),
2860
+ ...paths.length > 2e3 ? { incomplete: true } : {}
2861
+ };
2862
+ }
2863
+ async currentFile(context, review, path, rootHint) {
2864
+ const file = review.files.find((file2) => file2.path === path);
2865
+ if (!file) throw new Error("File is not in this review");
2866
+ if (review.runId) return review.files.find((file2) => file2.path === path);
2867
+ const root = rootHint ?? await repository(context);
2868
+ const [before, after] = await Promise.all([
2869
+ file.status === "added" ? null : headFile(root, review.baseHead, path, context.signal, true),
2870
+ file.status === "deleted" ? null : review.targetRef ? headFile(root, review.targetRef, path, context.signal, true) : workingFile(root, path)
2871
+ ]);
2872
+ return changed(path, before, after);
2873
+ }
2874
+ async latest(context) {
2875
+ const index = await (0, import_promises.readFile)(
2876
+ join(dirname(this.path(context.sessionId, "")), "latest.json"),
2877
+ "utf8"
2878
+ ).then(
2879
+ (value) => JSON.parse(value),
2880
+ () => void 0
2881
+ );
2882
+ return index ? this.load(context, index.runId) : void 0;
2883
+ }
2884
+ };
2885
+ var en = {
2886
+ "review.error.gitDiscovery": "Git ranges could not be loaded. Refresh to retry.",
2887
+ "review.summary.label": "Files changed this turn",
2888
+ "review.summary.single": "Edited $",
2889
+ "review.summary.edited_one": "Edited $ file",
2890
+ "review.summary.edited_other": "Edited $ files",
2891
+ "review.summary.view": "View changes",
2892
+ "review.summary.incomplete": "Some changes were not recorded.",
2893
+ "review.summary.collapse": "Collapse files",
2894
+ "review.summary.more_one": "Show $ more file",
2895
+ "review.summary.more_other": "Show $ more files",
2896
+ "review.summary.loading": "Loading diff\u2026",
2897
+ "review.summary.previewFailed": "Preview unavailable. Open the file to review changes.",
2898
+ "review.summary.openFailed": "Could not open changes.",
2899
+ "review.diff.unchanged": "$ unchanged lines",
2900
+ "review.scope.lastTurn": "Last turn",
2901
+ "review.scope.uncommitted": "Uncommitted",
2902
+ "review.scope.unstaged": "Unstaged",
2903
+ "review.scope.staged": "Staged",
2904
+ "review.scope.commit": "Commit",
2905
+ "review.scope.commits": "Commits",
2906
+ "review.scope.branches": "Branch comparison",
2907
+ "review.scope.branch": "Branch comparison",
2908
+ "review.scope.label": "Review scope",
2909
+ "review.options.words": "Word diffs",
2910
+ "review.options.whitespace": "Ignore whitespace",
2911
+ "review.options.copy": "Copy git apply command",
2912
+ "review.options.expandAll": "Expand all",
2913
+ "review.options.collapseAll": "Collapse all",
2914
+ "review.options.label": "View options",
2915
+ "review.branch.select": "Select target branch",
2916
+ "review.branch.search": "Search branches",
2917
+ "review.branch.noMatch": "No matching branches",
2918
+ "review.copy.success": "Command copied",
2919
+ "review.unavailable.binary": "Binary file. Text diff unavailable.",
2920
+ "review.unavailable.large": "File too large. Text diff wasn\u2019t stored.",
2921
+ "review.unavailable.symlink": "Symbolic link changed",
2922
+ "review.unavailable.encoding": "Non-UTF-8 text. Diff unavailable.",
2923
+ "review.unavailable.budget": "Preview limit exceeded",
2924
+ "review.unavailable.complex": "Diff too complex for exact line counts",
2925
+ "review.unavailable.text": "Text diff unavailable",
2926
+ "review.title.turn": "Turn changes",
2927
+ "review.title.workspace": "Working tree changes",
2928
+ "review.toolbar.label": "Changes controls",
2929
+ "review.toolbar.find": "Find file",
2930
+ "review.toolbar.full": "Show full files",
2931
+ "review.mode.label": "Diff mode",
2932
+ "review.mode.auto": "Auto",
2933
+ "review.mode.split": "Split",
2934
+ "review.mode.unified": "Unified",
2935
+ "review.toolbar.preview": "Preview",
2936
+ "review.toolbar.files": "File list",
2937
+ "review.toolbar.refresh": "Refresh",
2938
+ "review.notice.large": "Large diff. Showing one file at a time.",
2939
+ "review.notice.incomplete": "Some changes weren\u2019t recorded. Totals may be incomplete.",
2940
+ "review.state.loading": "Loading\u2026",
2941
+ "review.branch.prompt": "Select a target branch",
2942
+ "review.state.empty": "No changes",
2943
+ "review.file.open": "Open file",
2944
+ "review.error.open": "Couldn\u2019t open file. Check your file viewer.",
2945
+ "review.file.before": "Before",
2946
+ "review.file.after": "After",
2947
+ "review.file.noImage": "No image",
2948
+ "review.file.previous": "Previous file",
2949
+ "review.file.next": "Next file",
2950
+ "review.files.resize": "Resize file list",
2951
+ "review.files.filterLabel": "Filter changed files",
2952
+ "review.files.filter": "Filter files\u2026",
2953
+ "review.files.label": "Changed files",
2954
+ "review.title": "Change Review",
2955
+ "review.description": "Review file changes by turn and compare Git diffs.",
2956
+ "review.branch.empty": "No available branches",
2957
+ "review.file.expand": "Expand",
2958
+ "review.file.collapse": "Collapse",
2959
+ "review.file.diff": "File diff",
2960
+ "review.preview.before": "Before preview",
2961
+ "review.preview.copyCode": "Copy code",
2962
+ "review.preview.copiedCode": "Copied",
2963
+ "review.preview.copyCodeFailed": "Copy failed",
2964
+ "review.preview.diagramSource": "Diagram source",
2965
+ "review.preview.after": "After preview",
2966
+ "review.preview.image": "Image",
2967
+ "review.error.load": "Couldn\u2019t load changes",
2968
+ "review.error.copy": "Couldn\u2019t copy command",
2969
+ "review.error.details": "Error details",
2970
+ "review.error.noPatch": "No patch available for this file",
2971
+ "review.error.patchLarge": "Patch too large to copy"
2972
+ };
2973
+ var zhCN = {
2974
+ "review.error.gitDiscovery": "\u672A\u80FD\u52A0\u8F7D Git \u8303\u56F4\uFF0C\u8BF7\u5237\u65B0\u91CD\u8BD5\u3002",
2975
+ "review.summary.label": "\u672C\u8F6E\u6587\u4EF6\u53D8\u66F4",
2976
+ "review.summary.single": "\u5DF2\u7F16\u8F91 $",
2977
+ "review.summary.edited_one": "\u5DF2\u7F16\u8F91 $ \u4E2A\u6587\u4EF6",
2978
+ "review.summary.edited_other": "\u5DF2\u7F16\u8F91 $ \u4E2A\u6587\u4EF6",
2979
+ "review.summary.view": "\u67E5\u770B\u53D8\u66F4",
2980
+ "review.summary.incomplete": "\u90E8\u5206\u53D8\u66F4\u672A\u8BB0\u5F55\u3002",
2981
+ "review.summary.collapse": "\u6536\u8D77\u6587\u4EF6",
2982
+ "review.summary.more_one": "\u518D\u663E\u793A $ \u4E2A\u6587\u4EF6",
2983
+ "review.summary.more_other": "\u518D\u663E\u793A $ \u4E2A\u6587\u4EF6",
2984
+ "review.summary.loading": "\u6B63\u5728\u52A0\u8F7D\u5DEE\u5F02\u2026",
2985
+ "review.summary.previewFailed": "\u6682\u65F6\u65E0\u6CD5\u9884\u89C8\uFF0C\u8BF7\u70B9\u51FB\u6587\u4EF6\u67E5\u770B\u53D8\u66F4\u3002",
2986
+ "review.summary.openFailed": "\u6682\u65F6\u65E0\u6CD5\u6253\u5F00\u53D8\u66F4\u5BA1\u67E5\u3002",
2987
+ "review.diff.unchanged": "$ \u884C\u672A\u53D8",
2988
+ "review.scope.lastTurn": "\u6700\u8FD1\u4E00\u8F6E",
2989
+ "review.scope.uncommitted": "\u672A\u63D0\u4EA4",
2990
+ "review.scope.unstaged": "\u672A\u6682\u5B58",
2991
+ "review.scope.staged": "\u5DF2\u6682\u5B58",
2992
+ "review.scope.commit": "\u63D0\u4EA4",
2993
+ "review.scope.commits": "\u63D0\u4EA4",
2994
+ "review.scope.branches": "\u5206\u652F\u5BF9\u6BD4",
2995
+ "review.scope.branch": "\u5206\u652F\u5BF9\u6BD4",
2996
+ "review.scope.label": "\u5BA1\u67E5\u8303\u56F4",
2997
+ "review.options.words": "\u8BCD\u7EA7\u5DEE\u5F02",
2998
+ "review.options.whitespace": "\u5FFD\u7565\u7A7A\u767D\u5DEE\u5F02",
2999
+ "review.options.copy": "\u590D\u5236 git apply \u547D\u4EE4",
3000
+ "review.options.expandAll": "\u5C55\u5F00\u5168\u90E8",
3001
+ "review.options.collapseAll": "\u6298\u53E0\u5168\u90E8",
3002
+ "review.options.label": "\u67E5\u770B\u9009\u9879",
3003
+ "review.branch.select": "\u9009\u62E9\u76EE\u6807\u5206\u652F",
3004
+ "review.branch.search": "\u641C\u7D22\u5206\u652F",
3005
+ "review.branch.noMatch": "\u672A\u627E\u5230\u5206\u652F",
3006
+ "review.copy.success": "\u547D\u4EE4\u5DF2\u590D\u5236",
3007
+ "review.unavailable.binary": "\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u4E0D\u652F\u6301\u6587\u672C\u5BF9\u6BD4",
3008
+ "review.unavailable.large": "\u6587\u4EF6\u8FC7\u5927\uFF0C\u672A\u4FDD\u5B58\u6587\u672C\u5DEE\u5F02",
3009
+ "review.unavailable.symlink": "\u7B26\u53F7\u94FE\u63A5\u5DF2\u53D8\u66F4",
3010
+ "review.unavailable.encoding": "\u975E UTF-8 \u6587\u672C\uFF0C\u65E0\u6CD5\u5BF9\u6BD4",
3011
+ "review.unavailable.budget": "\u5185\u5BB9\u8D85\u8FC7\u9884\u89C8\u4E0A\u9650",
3012
+ "review.unavailable.complex": "\u5DEE\u5F02\u8FC7\u4E8E\u590D\u6742\uFF0C\u65E0\u6CD5\u7CBE\u786E\u7EDF\u8BA1\u884C\u6570",
3013
+ "review.unavailable.text": "\u65E0\u6CD5\u663E\u793A\u6587\u672C\u5DEE\u5F02",
3014
+ "review.title.turn": "\u672C\u8F6E\u53D8\u66F4",
3015
+ "review.title.workspace": "\u5DE5\u4F5C\u533A\u53D8\u66F4",
3016
+ "review.toolbar.label": "\u5BA1\u67E5\u64CD\u4F5C",
3017
+ "review.toolbar.find": "\u5B9A\u4F4D\u6587\u4EF6",
3018
+ "review.toolbar.full": "\u663E\u793A\u5B8C\u6574\u6587\u4EF6",
3019
+ "review.mode.label": "\u5BF9\u6BD4\u6A21\u5F0F",
3020
+ "review.mode.auto": "\u81EA\u52A8",
3021
+ "review.mode.split": "\u5E76\u6392",
3022
+ "review.mode.unified": "\u884C\u5185",
3023
+ "review.toolbar.preview": "\u9884\u89C8",
3024
+ "review.toolbar.files": "\u6587\u4EF6\u5217\u8868",
3025
+ "review.toolbar.refresh": "\u5237\u65B0",
3026
+ "review.notice.large": "\u53D8\u66F4\u8F83\u591A\uFF0C\u9010\u4E2A\u663E\u793A\u6587\u4EF6",
3027
+ "review.notice.incomplete": "\u90E8\u5206\u53D8\u66F4\u672A\u8BB0\u5F55\uFF0C\u7EDF\u8BA1\u53EF\u80FD\u4E0D\u5B8C\u6574",
3028
+ "review.state.loading": "\u52A0\u8F7D\u4E2D\u2026",
3029
+ "review.branch.prompt": "\u9009\u62E9\u76EE\u6807\u5206\u652F",
3030
+ "review.state.empty": "\u6682\u65E0\u53D8\u66F4",
3031
+ "review.file.open": "\u6253\u5F00\u6587\u4EF6",
3032
+ "review.error.open": "\u65E0\u6CD5\u6253\u5F00\u6587\u4EF6\uFF0C\u8BF7\u68C0\u67E5\u6587\u4EF6\u67E5\u770B\u5668",
3033
+ "review.file.before": "\u4FEE\u6539\u524D",
3034
+ "review.file.after": "\u4FEE\u6539\u540E",
3035
+ "review.file.noImage": "\u65E0\u56FE\u7247",
3036
+ "review.file.previous": "\u4E0A\u4E00\u4E2A\u6587\u4EF6",
3037
+ "review.file.next": "\u4E0B\u4E00\u4E2A\u6587\u4EF6",
3038
+ "review.files.resize": "\u8C03\u6574\u6587\u4EF6\u5217\u8868\u5BBD\u5EA6",
3039
+ "review.files.filterLabel": "\u7B5B\u9009\u53D8\u66F4\u6587\u4EF6",
3040
+ "review.files.filter": "\u7B5B\u9009\u6587\u4EF6\u2026",
3041
+ "review.files.label": "\u53D8\u66F4\u6587\u4EF6",
3042
+ "review.title": "\u53D8\u66F4\u5BA1\u67E5",
3043
+ "review.description": "\u67E5\u770B\u6BCF\u8F6E\u6587\u4EF6\u53D8\u66F4\uFF0C\u652F\u6301 Git \u5DEE\u5F02\u5BF9\u6BD4\u3002",
3044
+ "review.branch.empty": "\u65E0\u53EF\u9009\u5206\u652F",
3045
+ "review.file.expand": "\u5C55\u5F00",
3046
+ "review.file.collapse": "\u6298\u53E0",
3047
+ "review.file.diff": "\u6587\u4EF6\u5DEE\u5F02",
3048
+ "review.preview.before": "\u4FEE\u6539\u524D\u9884\u89C8",
3049
+ "review.preview.copyCode": "\u590D\u5236\u4EE3\u7801",
3050
+ "review.preview.copiedCode": "\u5DF2\u590D\u5236",
3051
+ "review.preview.copyCodeFailed": "\u590D\u5236\u5931\u8D25",
3052
+ "review.preview.diagramSource": "\u56FE\u8868\u6E90\u7801",
3053
+ "review.preview.after": "\u4FEE\u6539\u540E\u9884\u89C8",
3054
+ "review.preview.image": "\u56FE\u7247",
3055
+ "review.error.load": "\u65E0\u6CD5\u52A0\u8F7D\u53D8\u66F4",
3056
+ "review.error.copy": "\u65E0\u6CD5\u590D\u5236\u547D\u4EE4",
3057
+ "review.error.details": "\u9519\u8BEF\u8BE6\u60C5",
3058
+ "review.error.noPatch": "\u6B64\u6587\u4EF6\u6CA1\u6709\u53EF\u7528\u8865\u4E01",
3059
+ "review.error.patchLarge": "\u8865\u4E01\u8FC7\u5927\uFF0C\u65E0\u6CD5\u590D\u5236"
3060
+ };
3061
+ var dictionaries = {
3062
+ en,
3063
+ "zh-CN": zhCN,
3064
+ zh: zhCN
3065
+ };
3066
+ function reviewTranslator(locale) {
3067
+ const chain = localeFallbacks(locale);
3068
+ return (key2) => {
3069
+ for (const language of chain) {
3070
+ const value = dictionaries[language]?.[key2];
3071
+ if (value !== void 0) return value;
3072
+ }
3073
+ return en[key2];
3074
+ };
3075
+ }
3076
+ function registerReviewPanel(pal2, commands, changes) {
3077
+ pal2.ui.register({
3078
+ id: "pal.git.panel",
3079
+ slot: "pal.ui.panel",
3080
+ scope: "conversation",
3081
+ hostRenderer: "review",
3082
+ messagePresentation: pal_manifest_default.declarations.provides.ui[0].messagePresentation,
3083
+ restoreVersion: 1,
3084
+ commands: [
3085
+ ...pal_manifest_default.declarations.provides.commands.map((command) => command.id),
3086
+ "pal.clipboard.write",
3087
+ "pal.files.open"
3088
+ ],
3089
+ commandLimits: {
3090
+ maxInputChars: 8e3,
3091
+ maxResultChars: 1e7,
3092
+ maxResultValues: 12e4,
3093
+ timeoutMs: 15e4
3094
+ },
3095
+ viewLimits: { maxChars: 1e7, maxValues: 12e4 },
3096
+ launcher: {
3097
+ title: reviewTranslator("en")("review.title"),
3098
+ icon: "git-diff",
3099
+ locales: Object.fromEntries(
3100
+ Object.keys(dictionaries).map((locale) => [
3101
+ locale,
3102
+ { title: reviewTranslator(locale)("review.title") }
3103
+ ])
3104
+ )
3105
+ },
3106
+ requiredPermissions: [
3107
+ "pal.fs.read",
3108
+ "pal.process.spawn",
3109
+ "pal.clipboard.write"
3110
+ ],
3111
+ async render(request, context, execution) {
3112
+ if (!execution) throw new Error("Host command execution unavailable");
3113
+ const resource = request.resource ? JSON.parse(request.resource) : void 0;
3114
+ const data = request.presentation === "message" ? await commands.card(resource ?? {}, execution) : resource?.preview === true ? await commands.preview(resource, execution) : await commands.load({}, execution);
3115
+ return {
3116
+ title: reviewTranslator(request.locale)("review.title"),
3117
+ children: [],
3118
+ data: {
3119
+ ...data,
3120
+ reviewScope: JSON.stringify([
3121
+ execution.context.projectId,
3122
+ execution.context.sessionId
3123
+ ])
3124
+ }
3125
+ };
3126
+ }
3127
+ });
3128
+ pal2.ui.register({
3129
+ id: "pal.git.indicator",
3130
+ slot: "pal.conversation.before-composer",
3131
+ beforeComposerLayout: "floating",
3132
+ hostRenderer: "indicator",
3133
+ actions: ["open"],
3134
+ requiredPermissions: ["pal.fs.read"],
3135
+ async act(action, context) {
3136
+ const review = changes.activeReview(context.sessionId);
3137
+ if (action.id !== "open" || !review || review.projectId !== context.projectId || review.runId !== action.value || !pal2.context.panels)
3138
+ return;
3139
+ await pal2.context.panels.open(
3140
+ "pal.git.panel",
3141
+ JSON.stringify({ runId: review.runId }),
3142
+ context
3143
+ );
3144
+ },
3145
+ async render(_request, context) {
3146
+ const review = changes.activeReview(context.sessionId);
3147
+ const active = review?.projectId === context.projectId ? review : void 0;
3148
+ const pending = active?.pending ?? [];
3149
+ const displayedFiles = new Map(
3150
+ active?.files.map(({ path, added, removed }) => [
3151
+ path,
3152
+ { path, added, removed }
3153
+ ]) ?? []
3154
+ );
3155
+ for (const file of pending) {
3156
+ const committed = displayedFiles.get(file.path);
3157
+ displayedFiles.set(file.path, {
3158
+ path: file.path,
3159
+ added: (committed?.added ?? 0) + file.added,
3160
+ removed: (committed?.removed ?? 0) + file.removed
3161
+ });
3162
+ }
3163
+ return {
3164
+ title: active ? "\u672C\u8F6E\u6539\u52A8" : "",
3165
+ hidden: !active?.files.length && !pending.length,
3166
+ children: [],
3167
+ data: active ? {
3168
+ kind: "indicator",
3169
+ reviewScope: JSON.stringify([
3170
+ context.projectId,
3171
+ context.sessionId
3172
+ ]),
3173
+ runId: active.runId,
3174
+ files: [...displayedFiles.values()],
3175
+ pendingPaths: pending.map((file) => file.path),
3176
+ added: active.added + pending.reduce((sum, file) => sum + file.added, 0),
3177
+ removed: active.removed + pending.reduce((sum, file) => sum + file.removed, 0)
3178
+ } : { kind: "indicator", files: [] }
3179
+ };
3180
+ }
3181
+ });
3182
+ }
3183
+ var activate = async (host) => {
3184
+ const changes = new WorkspaceChangeReview(host.storagePath);
3185
+ const commands = new ReviewCommands(changes);
3186
+ const plugin = definePlugin((pal2) => {
3187
+ for (const definition of pal_manifest_default.declarations.provides.commands) {
3188
+ pal2.command.register({
3189
+ ...definition,
3190
+ visibility: definition.visibility,
3191
+ run: async (input, execution) => {
3192
+ if (definition.id === "pal.git.review.preview")
3193
+ return commands.preview(input, execution);
3194
+ if (definition.id === "pal.git.review.open") {
3195
+ const { runId } = input;
3196
+ if (!runId || !host.panels)
3197
+ throw new Error("Review navigation unavailable");
3198
+ await host.panels.open(
3199
+ "pal.git.panel",
3200
+ void 0,
3201
+ execution.context
3202
+ );
3203
+ return { opened: true };
3204
+ }
3205
+ return definition.id === "pal.git.review.patch" ? commands.patch(input, execution) : commands.load(input, execution);
3206
+ }
3207
+ });
3208
+ }
3209
+ registerReviewPanel(pal2, commands, changes);
3210
+ });
3211
+ return {
3212
+ ...await plugin.activate(host),
3213
+ runChanges: {
3214
+ async begin(context) {
3215
+ const service = host.services?.fileChanges;
3216
+ if (!service) return void 0;
3217
+ const capture = changes.beginEvents(
3218
+ context,
3219
+ service,
3220
+ () => host.invalidateUi?.(context.sessionId)
3221
+ );
3222
+ if (!capture) return void 0;
3223
+ return {
3224
+ finish: (signal, commands2) => withCommands(commands2, () => capture.finish(signal)),
3225
+ dispose: () => capture.dispose()
3226
+ };
3227
+ }
3228
+ }
3229
+ };
3230
+ };
3231
+ var bound = bindPluginModule(src_exports);
3232
+ var activate2 = bound.activate;
3233
+ var deactivate = bound.deactivate;