diffsplain 0.8.3 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -5
- package/dist/assets/{angular-html-e4D_THVy.js → angular-html-m_m91ZYB.js} +1 -1
- package/dist/assets/{angular-ts-Cx3870JF.js → angular-ts-CO5Z--Rb.js} +1 -1
- package/dist/assets/{apl-DZuu22Wh.js → apl-ogYYgLUu.js} +1 -1
- package/dist/assets/{astro-K-NemFAk.js → astro-DAfY3cNR.js} +1 -1
- package/dist/assets/{blade-ConbVu3U.js → blade-E6RzsLUV.js} +1 -1
- package/dist/assets/{c-DtmaBqln.js → c-kKdxhtHF.js} +1 -1
- package/dist/assets/{cobol-BMHoPOfB.js → cobol-3oDDyFNf.js} +1 -1
- package/dist/assets/{coffee-DfweJ19Y.js → coffee-dsiILuWe.js} +1 -1
- package/dist/assets/{cpp-CPh_zIOW.js → cpp-DYyNFq__.js} +1 -1
- package/dist/assets/{crystal-CAEX7C1J.js → crystal-B7dVp9TF.js} +1 -1
- package/dist/assets/{css-C8ihGqCA.js → css-DlxJ0aex.js} +1 -1
- package/dist/assets/{edge-DVZPwQ9j.js → edge-BjEVphkC.js} +1 -1
- package/dist/assets/{elixir-D03TKulP.js → elixir-0xTOtMcM.js} +1 -1
- package/dist/assets/{elm-JUX-2xVV.js → elm-iQk_Wrxq.js} +1 -1
- package/dist/assets/{erb-HbktAFZJ.js → erb-BO74ztiE.js} +1 -1
- package/dist/assets/{git-rebase-Ccd_ELAP.js → git-rebase-BN667QRY.js} +1 -1
- package/dist/assets/{glimmer-js-BcinUfi2.js → glimmer-js-DTGUIHeS.js} +1 -1
- package/dist/assets/{glimmer-ts-DuN2UkN9.js → glimmer-ts-BU3oQn2d.js} +1 -1
- package/dist/assets/{glsl-BWmCEPsR.js → glsl-KLiqLJi2.js} +1 -1
- package/dist/assets/{graphql-DJGYoBFW.js → graphql-D_idcsoJ.js} +1 -1
- package/dist/assets/{hack-ZPqBE9w3.js → hack-BXlsgPIr.js} +1 -1
- package/dist/assets/{haml-CZDZk6Gw.js → haml-fP0aUg4-.js} +1 -1
- package/dist/assets/{handlebars-d23PDS0n.js → handlebars-C1ZEaot-.js} +1 -1
- package/dist/assets/{html-BgzX2DyB.js → html-D04qIuup.js} +1 -1
- package/dist/assets/{html-derivative-Bq6M-ZFw.js → html-derivative-C6ai-9QL.js} +1 -1
- package/dist/assets/{http-DVhMl_cW.js → http-C7bz3ZvQ.js} +1 -1
- package/dist/assets/{hurl-CbspBAqF.js → hurl-jL6B6Ahr.js} +1 -1
- package/dist/assets/index-BPaJGi-m.js +1574 -0
- package/dist/assets/index-VAyBpb3u.css +2 -0
- package/dist/assets/{java--YZbq0z2.js → java-BVzvLCON.js} +1 -1
- package/dist/assets/{javascript-cvRuifRJ.js → javascript-UDbZHxCI.js} +1 -1
- package/dist/assets/{jinja-BeZmr3LP.js → jinja-DB-QKo2A.js} +1 -1
- package/dist/assets/{jison-qrpGZaxs.js → jison-B1ZbR2FF.js} +1 -1
- package/dist/assets/{json-4xUzsNJn.js → json-DV4WwJzT.js} +1 -1
- package/dist/assets/{jsx-BlXrTlSg.js → jsx-DS6_VTvW.js} +1 -1
- package/dist/assets/{julia-IN3jzmBc.js → julia-C4tevET0.js} +1 -1
- package/dist/assets/{just-C_50nLQH.js → just-CWMjefzB.js} +1 -1
- package/dist/assets/{latex-Cd-_2IS1.js → latex-tyEFf_Af.js} +1 -1
- package/dist/assets/{liquid-CEJf6Xg5.js → liquid-C3d1X1rL.js} +1 -1
- package/dist/assets/{lua-BlaV_n8i.js → lua-sXvrzLQY.js} +1 -1
- package/dist/assets/{marko-Cb-NPdc_.js → marko-CQweucif.js} +1 -1
- package/dist/assets/{mdc-Dt4ywVAS.js → mdc-TrxLWF7s.js} +1 -1
- package/dist/assets/{nginx-C_6SKViP.js → nginx-ChE2nSNJ.js} +1 -1
- package/dist/assets/{nim-BbkBjoeZ.js → nim-BY1CTRfx.js} +1 -1
- package/dist/assets/{perl-CYPU6TVa.js → perl-Cvj2PQQH.js} +1 -1
- package/dist/assets/{php-B6Oqilrc.js → php-CGmHp8HW.js} +1 -1
- package/dist/assets/{pug-C9Poo2KU.js → pug-DM4S0bRr.js} +1 -1
- package/dist/assets/{qml-DkMURMPv.js → qml-DI89Al9K.js} +1 -1
- package/dist/assets/{r-Bm-Gfi0p.js → r-Bs5_4yYh.js} +1 -1
- package/dist/assets/{razor-B0LqOok3.js → razor-DimzayhZ.js} +1 -1
- package/dist/assets/{regexp-jAbMHzwe.js → regexp-BLACz0cx.js} +1 -1
- package/dist/assets/{rst-BlWHfg8c.js → rst-DcWzxQh2.js} +1 -1
- package/dist/assets/{ruby-Bt5lKwPL.js → ruby-Dlat5E8d.js} +1 -1
- package/dist/assets/{sas-TuY2-8EF.js → sas-CCDmMaBY.js} +1 -1
- package/dist/assets/{scss-Dh1SsWlK.js → scss-BPiU2nu6.js} +1 -1
- package/dist/assets/{shellscript-CThiwmnp.js → shellscript-CKinVNrN.js} +1 -1
- package/dist/assets/{shellsession-DQ5iRUWd.js → shellsession-Cea8Pu5d.js} +1 -1
- package/dist/assets/{soy-BfM-BrZG.js → soy--BRAPY4-.js} +1 -1
- package/dist/assets/{sql-F617W1uN.js → sql-DjKiCyWK.js} +1 -1
- package/dist/assets/{stata-Ctov3ki2.js → stata-CDvo3J6y.js} +1 -1
- package/dist/assets/{surrealql-C-i2bJGB.js → surrealql-C7b7E5sh.js} +1 -1
- package/dist/assets/{svelte-oZT41pTl.js → svelte-DO0tKtiK.js} +1 -1
- package/dist/assets/{templ-CxX9Hf3e.js → templ-DhhmR_rv.js} +1 -1
- package/dist/assets/{tex-GyzJq8GJ.js → tex-Cn_V-Gg4.js} +1 -1
- package/dist/assets/{ts-tags-BugzKu0x.js → ts-tags-B6c-FTmA.js} +1 -1
- package/dist/assets/{tsx-DLqwDEUq.js → tsx-Cvtt2sJ-.js} +1 -1
- package/dist/assets/{twig-DADiR9Vq.js → twig-B7ZbCUmB.js} +1 -1
- package/dist/assets/{typescript-BlDIG_FO.js → typescript-i3C6um2B.js} +1 -1
- package/dist/assets/{vue-COXmmg2A.js → vue-DyPX0Vum.js} +1 -1
- package/dist/assets/{vue-html-Cy_3KYj1.js → vue-html-D362KpK3.js} +1 -1
- package/dist/assets/{vue-vine-CUqOY8dY.js → vue-vine-D34cBbwO.js} +1 -1
- package/dist/assets/{xml-C9JY7Wf6.js → xml-DJEk7u4n.js} +1 -1
- package/dist/assets/{xsl-DBCl8hSu.js → xsl-CoTtf90f.js} +1 -1
- package/dist/assets/{yaml-BbMebKkS.js → yaml-Cv5epQ4-.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +11 -3
- package/scripts/agent-exclusions.mjs +10 -0
- package/scripts/agent-review.mjs +94 -0
- package/scripts/build-diff-data.mjs +211 -49
- package/scripts/cli-args.mjs +36 -9
- package/scripts/coding-agents.mjs +206 -79
- package/scripts/generate-summaries.mjs +864 -425
- package/scripts/local-target.mjs +106 -0
- package/scripts/present.mjs +205 -72
- package/scripts/review-chat-context.mjs +510 -0
- package/scripts/review-chat-controller.mjs +568 -0
- package/scripts/review-chat-provider.mjs +352 -0
- package/scripts/review-chat.mjs +8 -0
- package/scripts/serve-built.mjs +206 -24
- package/scripts/summary-path.mjs +32 -11
- package/dist/assets/index-C2p_1iAk.css +0 -2
- package/dist/assets/index-divlsuKs.js +0 -1568
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { constants } from 'node:fs';
|
|
2
2
|
import { access } from 'node:fs/promises';
|
|
3
3
|
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { createInterface } from 'node:readline';
|
|
4
5
|
import {
|
|
5
|
-
basename,
|
|
6
6
|
delimiter,
|
|
7
7
|
dirname,
|
|
8
8
|
isAbsolute,
|
|
@@ -207,7 +207,7 @@ export async function findCommand(
|
|
|
207
207
|
return findOnPath(command, env, platform);
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
|
|
210
|
+
async function commandAvailable(command, options) {
|
|
211
211
|
return Boolean(await findCommand(command, options));
|
|
212
212
|
}
|
|
213
213
|
|
|
@@ -234,44 +234,127 @@ export async function codingAgentAvailability(
|
|
|
234
234
|
};
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
) {
|
|
242
|
-
if (
|
|
243
|
-
|
|
244
|
-
throw new Error(
|
|
245
|
-
`Unsupported agent "${requested}". Choose ${enabledCodingAgents.join(', ')}.`,
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
const result = await available(requested);
|
|
249
|
-
const availableResult = typeof result === 'object'
|
|
250
|
-
? result.available
|
|
251
|
-
: result;
|
|
252
|
-
if (!availableResult) {
|
|
253
|
-
if (typeof result === 'object' && result.reason) {
|
|
254
|
-
throw new Error(result.reason);
|
|
255
|
-
}
|
|
256
|
-
throw new Error(`Coding agent "${requested}" is not available.`);
|
|
257
|
-
}
|
|
258
|
-
return requested;
|
|
237
|
+
function availableResult(result) {
|
|
238
|
+
return typeof result === 'object' ? result.available : result;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function unavailableAgentError(requested, result) {
|
|
242
|
+
if (typeof result === 'object' && result.reason) {
|
|
243
|
+
return new Error(result.reason);
|
|
259
244
|
}
|
|
245
|
+
return new Error(`Coding agent "${requested}" is not available.`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function noAvailableAgentError(cursorReason) {
|
|
249
|
+
return new Error(
|
|
250
|
+
`No coding agent is available. Install one of: ${enabledCodingAgents.join(', ')}. Pass --agent NAME to choose an agent or --no-agent for a plain review.${cursorReason ? ` ${cursorReason}` : ''}`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
260
253
|
|
|
254
|
+
function selectionCancelledError() {
|
|
255
|
+
return new Error(
|
|
256
|
+
'Agent selection was cancelled. Pass --agent NAME to choose an agent or --no-agent for a plain review.',
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function nonInteractiveSelectionError() {
|
|
261
|
+
return new Error(
|
|
262
|
+
'An interactive terminal is required to choose a coding agent. Pass --agent NAME to choose an agent or --no-agent for a plain review.',
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async function selectRequestedCodingAgent(requested, available) {
|
|
267
|
+
if (!codingAgents.includes(requested)) {
|
|
268
|
+
throw new Error(
|
|
269
|
+
`Unsupported agent "${requested}". Choose ${enabledCodingAgents.join(', ')}.`,
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
const result = await available(requested);
|
|
273
|
+
if (!availableResult(result)) {
|
|
274
|
+
throw unavailableAgentError(requested, result);
|
|
275
|
+
}
|
|
276
|
+
return requested;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async function usableCodingAgents(available) {
|
|
280
|
+
const usable = [];
|
|
261
281
|
let cursorReason;
|
|
262
282
|
for (const agent of enabledCodingAgents) {
|
|
263
283
|
const result = await available(agent);
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
if (availableResult) return agent;
|
|
268
|
-
if (agent === 'cursor' && typeof result === 'object') {
|
|
284
|
+
if (availableResult(result)) {
|
|
285
|
+
usable.push(agent);
|
|
286
|
+
} else if (agent === 'cursor' && typeof result === 'object') {
|
|
269
287
|
cursorReason = result.reason;
|
|
270
288
|
}
|
|
271
289
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
290
|
+
return { usable, cursorReason };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function selectFromTerminal(agents, { input, output, signal }) {
|
|
294
|
+
output.write('Choose a coding agent:\n');
|
|
295
|
+
for (const [index, agent] of agents.entries()) {
|
|
296
|
+
output.write(`${index + 1}. ${agent}\n`);
|
|
297
|
+
}
|
|
298
|
+
output.write('Enter a number, or press Ctrl+C to cancel: ');
|
|
299
|
+
|
|
300
|
+
return new Promise((resolve, reject) => {
|
|
301
|
+
const picker = createInterface({ input, output, terminal: true });
|
|
302
|
+
let settled = false;
|
|
303
|
+
const finish = (callback, value) => {
|
|
304
|
+
if (settled) return;
|
|
305
|
+
settled = true;
|
|
306
|
+
signal?.removeEventListener('abort', onAbort);
|
|
307
|
+
picker.close();
|
|
308
|
+
callback(value);
|
|
309
|
+
};
|
|
310
|
+
const onAbort = () => {
|
|
311
|
+
finish(reject, selectionCancelledError());
|
|
312
|
+
};
|
|
313
|
+
const promptAgain = () => {
|
|
314
|
+
output.write(`Choose a number from 1 to ${agents.length}, or press Ctrl+C to cancel: `);
|
|
315
|
+
};
|
|
316
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
317
|
+
if (signal?.aborted) onAbort();
|
|
318
|
+
picker.on('SIGINT', () => {
|
|
319
|
+
finish(reject, selectionCancelledError());
|
|
320
|
+
});
|
|
321
|
+
picker.on('close', () => {
|
|
322
|
+
finish(reject, selectionCancelledError());
|
|
323
|
+
});
|
|
324
|
+
picker.on('line', (line) => {
|
|
325
|
+
const selected = Number(line.trim());
|
|
326
|
+
if (
|
|
327
|
+
!Number.isInteger(selected) ||
|
|
328
|
+
selected < 1 ||
|
|
329
|
+
selected > agents.length
|
|
330
|
+
) {
|
|
331
|
+
promptAgain();
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
finish(resolve, agents[selected - 1]);
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export async function selectCodingAgent(
|
|
340
|
+
requested,
|
|
341
|
+
{
|
|
342
|
+
available = commandAvailable,
|
|
343
|
+
input = process.stdin,
|
|
344
|
+
output = process.stderr,
|
|
345
|
+
signal,
|
|
346
|
+
} = {},
|
|
347
|
+
) {
|
|
348
|
+
if (requested) {
|
|
349
|
+
return selectRequestedCodingAgent(requested, available);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (!input?.isTTY || !output?.isTTY) {
|
|
353
|
+
throw nonInteractiveSelectionError();
|
|
354
|
+
}
|
|
355
|
+
const { usable, cursorReason } = await usableCodingAgents(available);
|
|
356
|
+
if (!usable.length) throw noAvailableAgentError(cursorReason);
|
|
357
|
+
return selectFromTerminal(usable, { input, output, signal });
|
|
275
358
|
}
|
|
276
359
|
|
|
277
360
|
// fallow-ignore-next-line complexity -- each supported agent has one override rule.
|
|
@@ -391,6 +474,33 @@ export function parseAgentResponse(agent, stdout) {
|
|
|
391
474
|
return parseJsonText(stdout, label);
|
|
392
475
|
}
|
|
393
476
|
|
|
477
|
+
function codexIsolationArgs(snapshotOnly) {
|
|
478
|
+
return snapshotOnly
|
|
479
|
+
? ['--ignore-user-config', '--ignore-rules']
|
|
480
|
+
: [];
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function codexConfigArgs(snapshotOnly) {
|
|
484
|
+
return snapshotOnly
|
|
485
|
+
? [
|
|
486
|
+
'--config',
|
|
487
|
+
'mcp_servers={}',
|
|
488
|
+
'--config',
|
|
489
|
+
'plugins={}',
|
|
490
|
+
'--config',
|
|
491
|
+
'shell_environment_policy.inherit="none"',
|
|
492
|
+
'--config',
|
|
493
|
+
'sandbox_workspace_write.network_access=false',
|
|
494
|
+
'--config',
|
|
495
|
+
'web_search="disabled"',
|
|
496
|
+
]
|
|
497
|
+
: [];
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function codexRepoArgs(snapshotOnly) {
|
|
501
|
+
return snapshotOnly ? ['--skip-git-repo-check'] : [];
|
|
502
|
+
}
|
|
503
|
+
|
|
394
504
|
function codexCommand({
|
|
395
505
|
binary,
|
|
396
506
|
model,
|
|
@@ -399,31 +509,22 @@ function codexCommand({
|
|
|
399
509
|
schemaPath,
|
|
400
510
|
summaryDirectory,
|
|
401
511
|
summaryEnv,
|
|
512
|
+
snapshotOnly,
|
|
402
513
|
}) {
|
|
403
514
|
const args = [
|
|
404
515
|
'exec',
|
|
405
516
|
'--ephemeral',
|
|
406
517
|
'--sandbox',
|
|
407
518
|
'read-only',
|
|
408
|
-
|
|
409
|
-
'--ignore-rules',
|
|
519
|
+
...codexIsolationArgs(snapshotOnly),
|
|
410
520
|
'--color',
|
|
411
521
|
'never',
|
|
412
|
-
|
|
522
|
+
...codexRepoArgs(snapshotOnly),
|
|
413
523
|
'-C',
|
|
414
524
|
summaryDirectory,
|
|
415
525
|
'--output-schema',
|
|
416
526
|
schemaPath,
|
|
417
|
-
|
|
418
|
-
'mcp_servers={}',
|
|
419
|
-
'--config',
|
|
420
|
-
'plugins={}',
|
|
421
|
-
'--config',
|
|
422
|
-
'shell_environment_policy.inherit="none"',
|
|
423
|
-
'--config',
|
|
424
|
-
'sandbox_workspace_write.network_access=false',
|
|
425
|
-
'--config',
|
|
426
|
-
'web_search="disabled"',
|
|
527
|
+
...codexConfigArgs(snapshotOnly),
|
|
427
528
|
];
|
|
428
529
|
if (model) args.push('--model', model);
|
|
429
530
|
if (reasoning) {
|
|
@@ -449,6 +550,7 @@ function claudeCommand({
|
|
|
449
550
|
schema,
|
|
450
551
|
summaryDirectory,
|
|
451
552
|
summaryEnv,
|
|
553
|
+
snapshotOnly,
|
|
452
554
|
}) {
|
|
453
555
|
const args = [
|
|
454
556
|
'--print',
|
|
@@ -456,8 +558,7 @@ function claudeCommand({
|
|
|
456
558
|
'json',
|
|
457
559
|
'--json-schema',
|
|
458
560
|
JSON.stringify(schema),
|
|
459
|
-
'--tools',
|
|
460
|
-
'',
|
|
561
|
+
...(snapshotOnly ? ['--tools', ''] : ['--permission-mode', 'plan']),
|
|
461
562
|
'--no-session-persistence',
|
|
462
563
|
];
|
|
463
564
|
if (model) args.push('--model', model);
|
|
@@ -479,13 +580,14 @@ function copilotCommand({
|
|
|
479
580
|
schema,
|
|
480
581
|
summaryDirectory,
|
|
481
582
|
summaryEnv,
|
|
583
|
+
snapshotOnly,
|
|
482
584
|
}) {
|
|
483
585
|
const schemaText = JSON.stringify(schema);
|
|
484
586
|
const args = [
|
|
485
587
|
'--silent',
|
|
486
|
-
'--no-ask-user',
|
|
588
|
+
...(snapshotOnly ? ['--no-ask-user'] : []),
|
|
487
589
|
'--no-color',
|
|
488
|
-
'--no-custom-instructions',
|
|
590
|
+
...(snapshotOnly ? ['--no-custom-instructions'] : []),
|
|
489
591
|
'--no-remote',
|
|
490
592
|
'--no-remote-export',
|
|
491
593
|
`--add-dir=${dirname(inputPath)}`,
|
|
@@ -504,6 +606,26 @@ function copilotCommand({
|
|
|
504
606
|
};
|
|
505
607
|
}
|
|
506
608
|
|
|
609
|
+
function openCodeIsolationArgs(snapshotOnly) {
|
|
610
|
+
return snapshotOnly ? ['--pure'] : [];
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function openCodeEnvironment(snapshotOnly, summaryEnv) {
|
|
614
|
+
if (!snapshotOnly) return summaryEnv;
|
|
615
|
+
return {
|
|
616
|
+
...summaryEnv,
|
|
617
|
+
OPENCODE_DB: ':memory:',
|
|
618
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify({
|
|
619
|
+
permission: { '*': 'deny' },
|
|
620
|
+
agent: {
|
|
621
|
+
build: {
|
|
622
|
+
permission: { '*': 'deny' },
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
}),
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
|
|
507
629
|
function openCodeCommand({
|
|
508
630
|
binary,
|
|
509
631
|
model,
|
|
@@ -512,10 +634,11 @@ function openCodeCommand({
|
|
|
512
634
|
schema,
|
|
513
635
|
summaryDirectory,
|
|
514
636
|
summaryEnv,
|
|
637
|
+
snapshotOnly,
|
|
515
638
|
}) {
|
|
516
639
|
const args = [
|
|
517
640
|
'run',
|
|
518
|
-
|
|
641
|
+
...openCodeIsolationArgs(snapshotOnly),
|
|
519
642
|
'--format',
|
|
520
643
|
'json',
|
|
521
644
|
'--dir',
|
|
@@ -533,24 +656,12 @@ function openCodeCommand({
|
|
|
533
656
|
args,
|
|
534
657
|
input: 'stdin',
|
|
535
658
|
cwd: summaryDirectory,
|
|
536
|
-
env:
|
|
537
|
-
...summaryEnv,
|
|
538
|
-
OPENCODE_DB: ':memory:',
|
|
539
|
-
OPENCODE_CONFIG_CONTENT: JSON.stringify({
|
|
540
|
-
permission: { '*': 'deny' },
|
|
541
|
-
agent: {
|
|
542
|
-
build: {
|
|
543
|
-
permission: { '*': 'deny' },
|
|
544
|
-
},
|
|
545
|
-
},
|
|
546
|
-
}),
|
|
547
|
-
},
|
|
659
|
+
env: openCodeEnvironment(snapshotOnly, summaryEnv),
|
|
548
660
|
};
|
|
549
661
|
}
|
|
550
662
|
|
|
551
663
|
function cursorCommand({
|
|
552
664
|
binary,
|
|
553
|
-
inputPath,
|
|
554
665
|
model,
|
|
555
666
|
prompt,
|
|
556
667
|
schema,
|
|
@@ -572,26 +683,28 @@ function cursorCommand({
|
|
|
572
683
|
];
|
|
573
684
|
if (model) args.push('--model', model);
|
|
574
685
|
args.push(
|
|
575
|
-
`${prompt}\n\
|
|
686
|
+
`${prompt}\n\nThe snapshot JSON follows this prompt on standard input. Return JSON that matches this schema:\n${JSON.stringify(schema)}`,
|
|
576
687
|
);
|
|
577
688
|
return {
|
|
578
689
|
command: binary,
|
|
579
690
|
args,
|
|
580
691
|
input: 'stdin',
|
|
581
692
|
cwd: summaryDirectory,
|
|
582
|
-
env:
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
693
|
+
env: summaryEnv === sourceEnv
|
|
694
|
+
? summaryEnv
|
|
695
|
+
: {
|
|
696
|
+
...summaryEnv,
|
|
697
|
+
...(sourceEnv.XDG_CONFIG_HOME
|
|
698
|
+
? { XDG_CONFIG_HOME: sourceEnv.XDG_CONFIG_HOME }
|
|
699
|
+
: {}),
|
|
700
|
+
...(sourceEnv.APPDATA ? { APPDATA: sourceEnv.APPDATA } : {}),
|
|
701
|
+
...(sourceEnv.CURSOR_API_KEY
|
|
702
|
+
? { CURSOR_API_KEY: sourceEnv.CURSOR_API_KEY }
|
|
703
|
+
: {}),
|
|
704
|
+
...(sourceEnv.CURSOR_AUTH_TOKEN
|
|
705
|
+
? { CURSOR_AUTH_TOKEN: sourceEnv.CURSOR_AUTH_TOKEN }
|
|
706
|
+
: {}),
|
|
707
|
+
},
|
|
595
708
|
};
|
|
596
709
|
}
|
|
597
710
|
|
|
@@ -604,8 +717,11 @@ export function agentCommand({
|
|
|
604
717
|
schema,
|
|
605
718
|
schemaPath,
|
|
606
719
|
inputPath,
|
|
720
|
+
accessMode,
|
|
607
721
|
env = process.env,
|
|
608
722
|
}) {
|
|
723
|
+
const snapshotDirectory = dirname(inputPath);
|
|
724
|
+
const checkoutAccess = accessMode?.mode === 'checkout-read-only';
|
|
609
725
|
const options = {
|
|
610
726
|
binary,
|
|
611
727
|
inputPath,
|
|
@@ -614,8 +730,9 @@ export function agentCommand({
|
|
|
614
730
|
reasoning,
|
|
615
731
|
schema,
|
|
616
732
|
schemaPath,
|
|
617
|
-
summaryDirectory:
|
|
618
|
-
summaryEnv: summaryAgentEnvironment(env),
|
|
733
|
+
summaryDirectory: checkoutAccess ? accessMode.root : snapshotDirectory,
|
|
734
|
+
summaryEnv: checkoutAccess ? env : summaryAgentEnvironment(env),
|
|
735
|
+
snapshotOnly: !checkoutAccess,
|
|
619
736
|
sourceEnv: env,
|
|
620
737
|
};
|
|
621
738
|
if (agent === 'codex') return codexCommand(options);
|
|
@@ -624,3 +741,13 @@ export function agentCommand({
|
|
|
624
741
|
if (agent === 'cursor') return cursorCommand(options);
|
|
625
742
|
return openCodeCommand(options);
|
|
626
743
|
}
|
|
744
|
+
|
|
745
|
+
const readOnlyWarnings = {
|
|
746
|
+
copilot: 'Warning: Copilot has no proven native read-only mode. It runs with your normal permissions.',
|
|
747
|
+
opencode: 'Warning: OpenCode has no proven native read-only mode. It runs with your normal permissions.',
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
export function agentReadOnlyWarning(agent, accessMode) {
|
|
751
|
+
if (accessMode?.mode !== 'checkout-read-only') return undefined;
|
|
752
|
+
return readOnlyWarnings[agent];
|
|
753
|
+
}
|