farming-code 2.2.14 → 2.2.17
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 +3 -3
- package/README.zh_cn.md +3 -3
- package/THIRD_PARTY_NOTICES.md +17 -1
- package/backend/acp/packaged-codex-acp.js +13 -0
- package/backend/acp-runtime.js +413 -24
- package/backend/agent-manager.js +572 -557
- package/backend/agent-provider-session.js +15 -1
- package/backend/agent-runtime-binding.js +9 -55
- package/backend/chat-runtime.js +28 -0
- package/backend/codex-rollout-follower.js +83 -0
- package/backend/codex-session-archive.js +12 -1
- package/backend/codex-session-history.js +94 -0
- package/backend/codex-transcript.js +2 -1
- package/backend/config-manager.js +25 -17
- package/backend/control-api.js +3 -1
- package/backend/farming-app-cli.js +21 -0
- package/backend/farming-session-store.js +2 -1
- package/backend/native-pty-host-client.js +59 -2
- package/backend/npm-update-helper.js +65 -7
- package/backend/provider-adapters.js +123 -38
- package/backend/provider-session-service.js +138 -34
- package/backend/server.js +94 -105
- package/backend/storage-layout.js +5 -16
- package/backend/update-service.js +94 -5
- package/backend/usage-history-client.js +305 -0
- package/backend/usage-history-scanner.generated.js +2250 -0
- package/backend/usage-history-scanner.ts +2718 -0
- package/backend/usage-history-smoke.js +64 -0
- package/backend/usage-history-worker.js +34 -0
- package/backend/usage-monitor.js +188 -588
- package/backend/vendor/usage-parsers/CC_STATISTICS_LICENSE +21 -0
- package/backend/vendor/usage-parsers/CODEXBAR_LICENSE +21 -0
- package/backend/vendor/usage-parsers/VENDOR.json +45 -0
- package/dist/acp/LICENSE.codex-acp +190 -0
- package/dist/acp/codex-acp-1.1.4.js +30718 -0
- package/dist/assets/App-6yWdwzj8.js +210 -0
- package/dist/assets/{FileEditorMarkdownPreview-UlVd0O4D.js → FileEditorMarkdownPreview-R0jwwLME.js} +4 -4
- package/dist/assets/FileEditorPane-DNy3LAqS.js +2 -0
- package/dist/assets/{IconGlyphs-AU22gPDY.js → IconGlyphs-BsUfqpKN.js} +1 -1
- package/dist/assets/ProjectFilesSection-BhDEUVHA.js +12 -0
- package/dist/assets/{ReviewPage-CeDKDyZh.js → ReviewPage-ChtByBe3.js} +1 -1
- package/dist/assets/{abnfDiagram-VRR7QNED-BgawzDQT.js → abnfDiagram-VRR7QNED-nnglrXFi.js} +1 -1
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-DUShwPg0.js → architectureDiagram-ZJ3FMSHR-BEXMaFfY.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-CeGZviXR.js → blockDiagram-677ZJIJ3-1mCezSBk.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-CLhYht6S.js → c4Diagram-LMCZKHZV-DhTiI6Uv.js} +1 -1
- package/dist/assets/channel-BVWNatUB.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-LFYpT-Cu.js → chunk-32BRIVSS-CCdsKd73.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-BH6jDw9J.js → chunk-52WLFC77-Gncjk4LF.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-B_mIUlb7.js → chunk-C7G6YPKG-CiDVUP82.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-C63hVuAJ.js → chunk-EX3LRPZG-z6gXP2_N.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-CboX-WF_.js → chunk-FWX5IMBZ-DMZBccQa.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-BOgSd6Un.js → chunk-HOUHSVGY-D8tIeoPk.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-C0K-pgZt.js → chunk-ICXQ74PX-b6oQ2Q17.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-CVMfwN_7.js → chunk-MOJQB5TN-DAVH_p2a.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-DLT3pxyw.js → chunk-OGEWGWER-DxoiMCI-.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-Cd079yIQ.js → chunk-PUDLZKDR-NsOWh7HM.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-D0jHa6SO.js → chunk-Q4XR5HBZ-Di4H7L21.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-CVDtR75H.js → chunk-V7JOEXUC-DttpZg9Y.js} +1 -1
- package/dist/assets/{chunk-VAUOI2AC-B-W2_9Ot.js → chunk-VAUOI2AC-UHNr_yhX.js} +1 -1
- package/dist/assets/{chunk-VR4S4FIN-FD3kWh32.js → chunk-VR4S4FIN-D-Fmtd4Z.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-C2bGaS5r.js → chunk-WYO6CB5R-CUxMtfK2.js} +4 -4
- package/dist/assets/{chunk-ZGVPDNZ5-ymgts0zo.js → chunk-ZGVPDNZ5-CoV2QEl0.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Db0ib5iE.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-Bkf69XF9.js +1 -0
- package/dist/assets/code-dark-5esj0bRu.css +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-CwpobXIl.js → cynefinDiagram-TSTJHNR4-0xPI92Lg.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-Dkhlfjna.js → dagre-VKFMJZFB-DfuMG4gU.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-hA8dicp6.js → diagram-FQU43EPY-CT00bLZ6.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-BTY6JTzO.js → diagram-G47NLZAW-Xbh7zXUx.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-xkaHHX9M.js → diagram-NH7WQ7WH-SRDVPfn7.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-gk_fg9UU.js → diagram-OA4YK3LP-CQRli4Np.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-BvC8xd6T.js → diagram-WEI45ONY-DMf17WQi.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-CR7RaNat.js → ebnfDiagram-CCIWWBDH-DhpFkgJ5.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-_M-JFPbj.js → erDiagram-Q63AITRT-1IwxWmJo.js} +1 -1
- package/dist/assets/file-icons-DpbrD5ZP.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-DYFo2xmB.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-Bl8P1yf_.js → ganttDiagram-NO4QXBWP-BNCdfyr1.js} +1 -1
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-DoHa5ysz.js → gitGraphDiagram-IHSO6WYX-pbyWZuiX.js} +1 -1
- package/dist/assets/{index-BA-iH2Kg.js → index-C8ZFKye1.js} +2 -2
- package/dist/assets/{infoDiagram-FWYZ7A6U-DSFcSuUs.js → infoDiagram-FWYZ7A6U-BcTOgDbe.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-DdkqullI.js → ishikawaDiagram-FXEZZL3T-DCdvGKrn.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-B4hRnQJr.js → journeyDiagram-5HDEW3XC-BZ-1q_IT.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-tm2FZB2E.js → kanban-definition-HUTT4EX6-BIgejCjj.js} +1 -1
- package/dist/assets/{line-CmsjK4kn.js → line-CfptFMmX.js} +1 -1
- package/dist/assets/main-DSO3i_Gs.css +1 -0
- package/dist/assets/{mermaid.core-C7UT_EEL.js → mermaid.core-gSpX30pV.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-DplfjGms.js → mindmap-definition-LN4V7U3C-BKBaI4LW.js} +1 -1
- package/dist/assets/{pegDiagram-2B236MQR-lu3SdkQs.js → pegDiagram-2B236MQR-sBvDY3VX.js} +1 -1
- package/dist/assets/{pieDiagram-ENE6RG2P-3fHbmDf9.js → pieDiagram-ENE6RG2P-DWlWcu08.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-a5qoWz-X.js → quadrantDiagram-ABIIQ3AL-DZutUd3J.js} +1 -1
- package/dist/assets/{railroadDiagram-RFXS5EU6-D2TOuXW9.js → railroadDiagram-RFXS5EU6-DQb3lXGM.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE-LQBWpUvd.js → requirementDiagram-TGXJPOKE-DqFGXu2e.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-B1ohYoyK.js → sankeyDiagram-HTMAVEWB-d7ECahnO.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-C3vM-hMq.js → sequenceDiagram-DBY2YBRQ-DdsbKqct.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-BvFhOryI.js → stateDiagram-2N3HPSRC-P6iSrgwR.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-DIYSf_qh.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-DKF_b-2s.js → swimlanes-5IMT3BWC-BGnZJx1M.js} +1 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-BIkrlKrZ.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-vAs11ux_.js → timeline-definition-FHXFAJF6-rA-r3aUR.js} +1 -1
- package/dist/assets/{vennDiagram-L72KCM5P-BybTX_9B.js → vennDiagram-L72KCM5P-DiVKUjA9.js} +1 -1
- package/dist/assets/{wardleyDiagram-EHGQE667-CicUmMBR.js → wardleyDiagram-EHGQE667-Cfxh7UOn.js} +1 -1
- package/dist/assets/workspace-editor-model-D0Im34S5.js +1 -0
- package/dist/assets/{workspace-editor-monaco-BICJESG0.js → workspace-editor-monaco-BIpqcWf1.js} +1 -1
- package/dist/assets/workspace-editor-monaco-DLlws5Ig.js +1 -0
- package/dist/assets/{workspace-view-state-DvYG_9PH.js → workspace-view-state-BpPINu84.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG-BhWDyCX-.js → xychartDiagram-FW5EYKEG--hmryQeL.js} +1 -1
- package/dist/crt-mermaid-renderer.js +313 -313
- package/dist/index.html +1 -1
- package/frontend/session-bridge.js +24 -2
- package/frontend/skins/crt/app.js +203 -85
- package/frontend/skins/crt/index.html +2 -11
- package/frontend/skins/crt/styles/effects.css +2 -34
- package/package.json +30 -12
- package/shared/backend-connection-status.d.ts +25 -0
- package/shared/backend-connection-status.js +40 -0
- package/shared/browser-protocol.js +3 -3
- package/backend/app-server-api.js +0 -917
- package/backend/codex-app-server-home.js +0 -39
- package/backend/codex-app-server-runtime.js +0 -901
- package/dist/assets/App-Bumi772v.js +0 -206
- package/dist/assets/FileEditorPane-Dxx4rKOg.js +0 -2
- package/dist/assets/ProjectFilesSection-DE7Nb9Jk.js +0 -12
- package/dist/assets/channel-Uw90AO0b.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DKW_dtku.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-C8Fi7-yv.js +0 -1
- package/dist/assets/code-dark-DPiuyeSp.css +0 -1
- package/dist/assets/code-mobile-3C2Rr-CN.css +0 -1
- package/dist/assets/file-icons-Bw2qd5iT.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-DAiS5Y7G.js +0 -1
- package/dist/assets/main-Bqtb5kuz.css +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-WMrz4PNo.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-BGswC9oC.js +0 -8
- package/dist/assets/workspace-editor-model-BQol4qbA.js +0 -1
- package/dist/assets/workspace-editor-monaco-DRJ7IaXk.js +0 -1
- package/scripts/sync-ghostty-vendor.js +0 -66
- /package/dist/assets/{core-D0LFJkDt.js → core-B9MwRjDE.js} +0 -0
|
@@ -14,7 +14,9 @@ const {
|
|
|
14
14
|
allocateNativePtyControllerGeneration,
|
|
15
15
|
positiveGeneration,
|
|
16
16
|
} = require('./native-pty-controller-generation');
|
|
17
|
+
const { isTemporaryProviderSessionId } = require('./provider-session-id');
|
|
17
18
|
const storageLayout = require('./storage-layout');
|
|
19
|
+
const { deserializeTerminalState } = require('./terminal-state-serialization');
|
|
18
20
|
|
|
19
21
|
const DEFAULT_CONNECT_RETRIES = 300;
|
|
20
22
|
const DEFAULT_CONNECT_RETRY_MS = 50;
|
|
@@ -463,6 +465,23 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
463
465
|
});
|
|
464
466
|
}
|
|
465
467
|
|
|
468
|
+
async requirePreparedHostRotationResume(preparationToken, actual, primaryError) {
|
|
469
|
+
if (!preparationToken) return;
|
|
470
|
+
try {
|
|
471
|
+
await this.resumePreparedHostRotation(preparationToken);
|
|
472
|
+
} catch (resumeError) {
|
|
473
|
+
const recoveryError = new Error(
|
|
474
|
+
`Cannot confirm recovery of incompatible native PTY host (${actual}) after aborting rotation`
|
|
475
|
+
);
|
|
476
|
+
recoveryError.code = 'FARMING_NATIVE_HOST_ROTATION_RECOVERY_FAILED';
|
|
477
|
+
recoveryError.cause = new AggregateError(
|
|
478
|
+
[primaryError, resumeError].filter(Boolean),
|
|
479
|
+
'Native PTY rotation failed and the prepared host could not be resumed'
|
|
480
|
+
);
|
|
481
|
+
throw recoveryError;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
466
485
|
async rotateMismatchedHost(hostInfo) {
|
|
467
486
|
const expected = runtimeIdentityLabel(this.expectedRuntimeIdentity);
|
|
468
487
|
const actual = runtimeIdentityLabel(hostInfo && hostInfo.runtimeIdentity);
|
|
@@ -513,7 +532,11 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
513
532
|
throw new Error('The native PTY host returned an invalid rotation checkpoint');
|
|
514
533
|
}
|
|
515
534
|
} catch (error) {
|
|
516
|
-
|
|
535
|
+
if (preparationToken) {
|
|
536
|
+
await this.requirePreparedHostRotationResume(preparationToken, actual, error);
|
|
537
|
+
} else {
|
|
538
|
+
await this.resumePreparedHostRotation('').catch(() => {});
|
|
539
|
+
}
|
|
517
540
|
const recovered = await this.requestOnce('recoverSessions', {}, {
|
|
518
541
|
ensureConnected: false,
|
|
519
542
|
retryOnDisconnect: false,
|
|
@@ -532,6 +555,40 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
532
555
|
}
|
|
533
556
|
}
|
|
534
557
|
|
|
558
|
+
let unresumableCodex;
|
|
559
|
+
try {
|
|
560
|
+
unresumableCodex = deserializeTerminalState(serializedTerminalState).find(entry => {
|
|
561
|
+
const metadata = entry.metadata || {};
|
|
562
|
+
const provider = String(metadata.providerSessionProvider || metadata.provider || '').trim();
|
|
563
|
+
return provider === 'codex'
|
|
564
|
+
&& metadata.terminalInputReceived === true
|
|
565
|
+
&& (
|
|
566
|
+
metadata.providerSessionTemporary === true
|
|
567
|
+
|| isTemporaryProviderSessionId(metadata.providerSessionId)
|
|
568
|
+
);
|
|
569
|
+
});
|
|
570
|
+
} catch (error) {
|
|
571
|
+
await this.requirePreparedHostRotationResume(preparationToken, actual, error);
|
|
572
|
+
const mismatchError = new Error(
|
|
573
|
+
`Cannot rotate incompatible native PTY host (${actual}) with an invalid terminal checkpoint`
|
|
574
|
+
);
|
|
575
|
+
mismatchError.code = 'FARMING_NATIVE_HOST_RUNTIME_MISMATCH';
|
|
576
|
+
mismatchError.cause = error;
|
|
577
|
+
throw mismatchError;
|
|
578
|
+
}
|
|
579
|
+
if (unresumableCodex) {
|
|
580
|
+
const unresumableError = new Error(
|
|
581
|
+
`Codex session ${unresumableCodex.id} has user input but no exact resume id`
|
|
582
|
+
);
|
|
583
|
+
await this.requirePreparedHostRotationResume(preparationToken, actual, unresumableError);
|
|
584
|
+
const mismatchError = new Error(
|
|
585
|
+
`Cannot rotate incompatible native PTY host (${actual}) while Codex session ${unresumableCodex.id} has user input but no exact resume id`
|
|
586
|
+
);
|
|
587
|
+
mismatchError.code = 'FARMING_NATIVE_HOST_UNRESUMABLE_SESSION';
|
|
588
|
+
mismatchError.cause = unresumableError;
|
|
589
|
+
throw mismatchError;
|
|
590
|
+
}
|
|
591
|
+
|
|
535
592
|
const socket = this.socket;
|
|
536
593
|
if (socket) this.suppressedDisconnectSockets.add(socket);
|
|
537
594
|
let shutdownUncertain = false;
|
|
@@ -546,7 +603,7 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
546
603
|
});
|
|
547
604
|
} catch (error) {
|
|
548
605
|
if (!isConnectRetryable(error)) {
|
|
549
|
-
await this.
|
|
606
|
+
await this.requirePreparedHostRotationResume(preparationToken, actual, error);
|
|
550
607
|
const mismatchError = new Error(
|
|
551
608
|
`Cannot rotate incompatible native PTY host (${actual}); stop the old host and restart Farming`
|
|
552
609
|
);
|
|
@@ -64,12 +64,23 @@ function validatePayload(payload) {
|
|
|
64
64
|
if (!/^[A-Za-z0-9@/._-]+$/.test(String(payload.packageName || ''))) throw new Error('Invalid npm package name');
|
|
65
65
|
if (!/^[0-9A-Za-z.+-]+$/.test(String(payload.targetVersion || ''))) throw new Error('Invalid npm target version');
|
|
66
66
|
if (!/^[0-9A-Za-z.+-]+$/.test(String(payload.previousVersion || ''))) throw new Error('Invalid npm previous version');
|
|
67
|
-
for (const key of ['stateFile', 'logPath', 'cliPath', 'configDir']) {
|
|
67
|
+
for (const key of ['stateFile', 'logPath', 'cliPath', 'packageRoot', 'configDir']) {
|
|
68
68
|
if (!path.isAbsolute(String(payload[key] || ''))) throw new Error(`Invalid npm update ${key}`);
|
|
69
69
|
}
|
|
70
70
|
if (payload.npmPrefix && !path.isAbsolute(String(payload.npmPrefix))) {
|
|
71
71
|
throw new Error('Invalid npm update npmPrefix');
|
|
72
72
|
}
|
|
73
|
+
if (payload.npmFallbackRegistryUrl) {
|
|
74
|
+
let registry;
|
|
75
|
+
try {
|
|
76
|
+
registry = new URL(String(payload.npmFallbackRegistryUrl));
|
|
77
|
+
} catch {
|
|
78
|
+
throw new Error('Invalid npm update registry');
|
|
79
|
+
}
|
|
80
|
+
if (!['http:', 'https:'].includes(registry.protocol)) {
|
|
81
|
+
throw new Error('Invalid npm update registry');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
73
84
|
return payload;
|
|
74
85
|
}
|
|
75
86
|
|
|
@@ -109,15 +120,59 @@ function commandEnvironment() {
|
|
|
109
120
|
|
|
110
121
|
async function installPackage(payload, version) {
|
|
111
122
|
const packageSpec = `${payload.packageName}@${version}`;
|
|
112
|
-
|
|
123
|
+
return installPackageFromRegistry(payload, packageSpec);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function verifyInstalledVersion(payload, expectedVersion) {
|
|
127
|
+
const packageJsonPath = path.join(payload.packageRoot, 'package.json');
|
|
128
|
+
let metadata;
|
|
129
|
+
try {
|
|
130
|
+
metadata = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
131
|
+
} catch (error) {
|
|
132
|
+
throw new Error(`Installed ${payload.packageName} package metadata is unreadable: ${error.message || String(error)}`, { cause: error });
|
|
133
|
+
}
|
|
134
|
+
const actualVersion = String(metadata && metadata.version || '');
|
|
135
|
+
if (actualVersion !== expectedVersion) {
|
|
136
|
+
throw new Error(`Installed ${payload.packageName} version mismatch: expected ${expectedVersion}, found ${actualVersion || 'missing'}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function logSize(filePath) {
|
|
141
|
+
try {
|
|
142
|
+
return fs.statSync(filePath).size;
|
|
143
|
+
} catch {
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function logSince(filePath, offset) {
|
|
149
|
+
try {
|
|
150
|
+
return fs.readFileSync(filePath, 'utf8').slice(offset);
|
|
151
|
+
} catch {
|
|
152
|
+
return '';
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function installPackageFromRegistry(payload, packageSpec, registryUrl = '') {
|
|
157
|
+
appendLog(payload.logPath, `Installing ${packageSpec}${registryUrl ? ' from the update-status registry' : ''}`);
|
|
113
158
|
const args = ['install', '--global'];
|
|
114
159
|
if (payload.npmPrefix) args.push('--prefix', payload.npmPrefix);
|
|
160
|
+
if (registryUrl) args.push('--registry', registryUrl);
|
|
115
161
|
args.push(packageSpec, '--no-audit', '--no-fund');
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
162
|
+
const offset = logSize(payload.logPath);
|
|
163
|
+
try {
|
|
164
|
+
await runCommand(payload.npmCommand || 'npm', args, {
|
|
165
|
+
cwd: payload.configDir,
|
|
166
|
+
env: commandEnvironment(),
|
|
167
|
+
logPath: payload.logPath,
|
|
168
|
+
});
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (!registryUrl && payload.npmFallbackRegistryUrl && /(?:ETARGET|No matching version found)/.test(logSince(payload.logPath, offset))) {
|
|
171
|
+
appendLog(payload.logPath, `Configured npm registry has no ${packageSpec}; retrying from the update-status registry`);
|
|
172
|
+
return installPackageFromRegistry(payload, packageSpec, payload.npmFallbackRegistryUrl);
|
|
173
|
+
}
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
121
176
|
}
|
|
122
177
|
|
|
123
178
|
async function startServer(payload, version = payload.targetVersion) {
|
|
@@ -134,6 +189,7 @@ async function runNpmUpdate(rawPayload) {
|
|
|
134
189
|
try {
|
|
135
190
|
writeJsonAtomic(payload.stateFile, stateFor(payload, 'installing'));
|
|
136
191
|
await installPackage(payload, payload.targetVersion);
|
|
192
|
+
verifyInstalledVersion(payload, payload.targetVersion);
|
|
137
193
|
|
|
138
194
|
writeJsonAtomic(payload.stateFile, stateFor(payload, 'restarting'));
|
|
139
195
|
await stopProcess(Number(payload.serverPid));
|
|
@@ -151,6 +207,7 @@ async function runNpmUpdate(rawPayload) {
|
|
|
151
207
|
try {
|
|
152
208
|
writeJsonAtomic(payload.stateFile, stateFor(payload, 'rolling-back', { error: message }));
|
|
153
209
|
await installPackage(payload, payload.previousVersion);
|
|
210
|
+
verifyInstalledVersion(payload, payload.previousVersion);
|
|
154
211
|
await startServer(payload, payload.previousVersion);
|
|
155
212
|
writeJsonAtomic(payload.stateFile, stateFor(payload, 'rolled-back', {
|
|
156
213
|
version: payload.previousVersion,
|
|
@@ -196,5 +253,6 @@ module.exports = {
|
|
|
196
253
|
runNpmUpdate,
|
|
197
254
|
stopProcess,
|
|
198
255
|
validatePayload,
|
|
256
|
+
verifyInstalledVersion,
|
|
199
257
|
writeJsonAtomic,
|
|
200
258
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
+
const { chatCapabilitiesForProvider } = require('./chat-runtime');
|
|
2
3
|
const {
|
|
3
4
|
createProviderSessionId,
|
|
4
5
|
createTemporaryProviderSessionId,
|
|
@@ -6,45 +7,73 @@ const {
|
|
|
6
7
|
} = require('./provider-session-id');
|
|
7
8
|
|
|
8
9
|
const CODEX_VALUE_OPTIONS = new Set([
|
|
9
|
-
'-a', '-c', '-C', '-m', '-s', '--ask-for-approval', '--cd', '--config',
|
|
10
|
-
'--config-profile', '--model', '--profile', '--sandbox',
|
|
10
|
+
'-a', '-c', '-C', '-m', '-p', '-s', '--ask-for-approval', '--cd', '--config',
|
|
11
|
+
'--config-profile', '--model', '--profile', '--sandbox', '--add-dir',
|
|
12
|
+
'--enable', '--disable', '--remote', '--remote-auth-token-env',
|
|
13
|
+
'--local-provider', '-i', '--image',
|
|
11
14
|
]);
|
|
15
|
+
const OPENCODE_VALUE_OPTIONS = new Set([
|
|
16
|
+
'-m', '-s', '--agent', '--hostname', '--log-level', '--mdns-domain',
|
|
17
|
+
'--model', '--port', '--prompt', '--replay-limit', '--session',
|
|
18
|
+
]);
|
|
19
|
+
const CODEX_SUBCOMMANDS = new Set([
|
|
20
|
+
'exec', 'e', 'review', 'login', 'logout', 'mcp', 'plugin', 'mcp-server',
|
|
21
|
+
'app-server', 'remote-control', 'app', 'completion', 'update', 'doctor',
|
|
22
|
+
'sandbox', 'debug', 'apply', 'a', 'resume', 'archive', 'delete', 'unarchive',
|
|
23
|
+
'fork', 'cloud', 'exec-server', 'features', 'help',
|
|
24
|
+
]);
|
|
25
|
+
const OPENCODE_SUBCOMMANDS = new Set([
|
|
26
|
+
'completion', 'acp', 'mcp', 'attach', 'run', 'debug', 'providers', 'auth',
|
|
27
|
+
'agent', 'upgrade', 'uninstall', 'serve', 'web', 'models', 'stats', 'export',
|
|
28
|
+
'import', 'github', 'pr', 'session', 'plugin', 'plug', 'db',
|
|
29
|
+
]);
|
|
30
|
+
const CODEX_SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12
31
|
|
|
13
32
|
function optionTakesValue(option, valueOptions) {
|
|
14
33
|
return Boolean(option && !option.includes('=') && valueOptions.has(option));
|
|
15
34
|
}
|
|
16
35
|
|
|
17
|
-
function
|
|
36
|
+
function scanPositionals(args, valueOptions, options = {}) {
|
|
37
|
+
const positionals = [];
|
|
18
38
|
for (let index = 0; index < args.length; index += 1) {
|
|
19
|
-
const arg = args[index];
|
|
39
|
+
const arg = String(args[index] || '');
|
|
20
40
|
if (!arg) continue;
|
|
41
|
+
if (arg === '--') {
|
|
42
|
+
for (let positionalIndex = index + 1; positionalIndex < args.length; positionalIndex += 1) {
|
|
43
|
+
const value = String(args[positionalIndex] || '');
|
|
44
|
+
if (value) positionals.push({ value, index: positionalIndex, afterDelimiter: true });
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
21
48
|
if (arg.startsWith('-')) {
|
|
22
|
-
if (
|
|
49
|
+
if (
|
|
50
|
+
options.multiValueOptions?.has(arg)
|
|
51
|
+
&& !arg.includes('=')
|
|
52
|
+
) {
|
|
53
|
+
while (index + 1 < args.length && !String(args[index + 1] || '').startsWith('-')) index += 1;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (optionTakesValue(arg, valueOptions)) index += 1;
|
|
23
57
|
continue;
|
|
24
58
|
}
|
|
25
|
-
|
|
59
|
+
positionals.push({ value: arg, index, afterDelimiter: false });
|
|
26
60
|
}
|
|
27
|
-
return
|
|
61
|
+
return positionals;
|
|
28
62
|
}
|
|
29
63
|
|
|
30
64
|
function codexSessionIdAfterSubcommand(args, subcommandIndex) {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
positional.push(arg);
|
|
40
|
-
}
|
|
41
|
-
const sessionId = positional.at(-1) || '';
|
|
42
|
-
return isSafeProviderSessionId(sessionId) ? sessionId : '';
|
|
65
|
+
const sessionId = scanPositionals(
|
|
66
|
+
args.slice(subcommandIndex + 1),
|
|
67
|
+
CODEX_VALUE_OPTIONS,
|
|
68
|
+
{ multiValueOptions: new Set(['-i', '--image']) },
|
|
69
|
+
)[0]?.value || '';
|
|
70
|
+
return CODEX_SESSION_ID_RE.test(sessionId) ? sessionId.toLowerCase() : '';
|
|
43
71
|
}
|
|
44
72
|
|
|
45
73
|
function argValue(args, names) {
|
|
46
74
|
for (let index = 0; index < args.length; index += 1) {
|
|
47
75
|
const arg = args[index];
|
|
76
|
+
if (arg === '--') break;
|
|
48
77
|
for (const name of names) {
|
|
49
78
|
if (arg === name) return args[index + 1] || '';
|
|
50
79
|
if (arg.startsWith(`${name}=`)) return arg.slice(name.length + 1);
|
|
@@ -54,13 +83,26 @@ function argValue(args, names) {
|
|
|
54
83
|
}
|
|
55
84
|
|
|
56
85
|
function hasArg(args, names) {
|
|
57
|
-
|
|
86
|
+
for (const arg of args) {
|
|
87
|
+
if (arg === '--') break;
|
|
88
|
+
if (names.includes(arg) || names.some(name => arg.startsWith(`${name}=`))) return true;
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
58
91
|
}
|
|
59
92
|
|
|
60
|
-
function codexSessionPlan(rawArgs) {
|
|
61
|
-
const
|
|
93
|
+
function codexSessionPlan(rawArgs, _launchArgs) {
|
|
94
|
+
const positional = scanPositionals(rawArgs, CODEX_VALUE_OPTIONS, {
|
|
95
|
+
multiValueOptions: new Set(['-i', '--image']),
|
|
96
|
+
});
|
|
97
|
+
const subcommand = positional[0]
|
|
98
|
+
&& positional[0].afterDelimiter !== true
|
|
99
|
+
&& CODEX_SUBCOMMANDS.has(positional[0].value)
|
|
100
|
+
? positional[0]
|
|
101
|
+
: null;
|
|
62
102
|
if (subcommand?.value === 'resume') {
|
|
63
|
-
const id =
|
|
103
|
+
const id = hasArg(rawArgs.slice(subcommand.index + 1), ['--last'])
|
|
104
|
+
? ''
|
|
105
|
+
: codexSessionIdAfterSubcommand(rawArgs, subcommand.index);
|
|
64
106
|
if (id) return { id, temporary: false, source: 'resume' };
|
|
65
107
|
}
|
|
66
108
|
if (subcommand?.value === 'fork') {
|
|
@@ -68,11 +110,22 @@ function codexSessionPlan(rawArgs) {
|
|
|
68
110
|
id: createTemporaryProviderSessionId(),
|
|
69
111
|
temporary: true,
|
|
70
112
|
source: 'codex-fork-temporary',
|
|
71
|
-
forkedFromProviderSessionId:
|
|
113
|
+
forkedFromProviderSessionId: hasArg(rawArgs.slice(subcommand.index + 1), ['--last'])
|
|
114
|
+
? ''
|
|
115
|
+
: codexSessionIdAfterSubcommand(rawArgs, subcommand.index),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (subcommand) return null;
|
|
119
|
+
if (hasArg(rawArgs, ['--remote'])) {
|
|
120
|
+
return {
|
|
121
|
+
error: 'A fresh Codex --remote Terminal cannot be correlated with a local resumable session id; resume an explicit remote session id instead',
|
|
72
122
|
};
|
|
73
123
|
}
|
|
74
|
-
|
|
75
|
-
|
|
124
|
+
return {
|
|
125
|
+
id: createTemporaryProviderSessionId(),
|
|
126
|
+
temporary: true,
|
|
127
|
+
source: 'codex-temporary',
|
|
128
|
+
};
|
|
76
129
|
}
|
|
77
130
|
|
|
78
131
|
function explicitSessionPlan(provider, rawArgs, launchArgs) {
|
|
@@ -102,17 +155,35 @@ function explicitSessionPlan(provider, rawArgs, launchArgs) {
|
|
|
102
155
|
};
|
|
103
156
|
}
|
|
104
157
|
|
|
105
|
-
function openCodeSessionPlan(rawArgs) {
|
|
158
|
+
function openCodeSessionPlan(rawArgs, launchArgs) {
|
|
106
159
|
const id = argValue(rawArgs, ['--session', '-s']);
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
160
|
+
if (id && isSafeProviderSessionId(id)) {
|
|
161
|
+
return hasArg(rawArgs, ['--fork'])
|
|
162
|
+
? {
|
|
163
|
+
id: createTemporaryProviderSessionId(),
|
|
164
|
+
temporary: true,
|
|
165
|
+
source: 'opencode-fork-temporary',
|
|
166
|
+
forkedFromProviderSessionId: id,
|
|
167
|
+
}
|
|
168
|
+
: { id, temporary: false, source: 'resume' };
|
|
169
|
+
}
|
|
170
|
+
if (hasArg(rawArgs, ['--session', '-s', '--continue', '-c', '--fork'])) return null;
|
|
171
|
+
const positional = scanPositionals(rawArgs, OPENCODE_VALUE_OPTIONS, {
|
|
172
|
+
multiValueOptions: new Set(['--cors']),
|
|
173
|
+
});
|
|
174
|
+
if (
|
|
175
|
+
positional[0]
|
|
176
|
+
&& positional[0].afterDelimiter !== true
|
|
177
|
+
&& OPENCODE_SUBCOMMANDS.has(positional[0].value)
|
|
178
|
+
) return null;
|
|
179
|
+
return {
|
|
180
|
+
id: '',
|
|
181
|
+
precreate: true,
|
|
182
|
+
temporary: false,
|
|
183
|
+
source: 'opencode-precreate',
|
|
184
|
+
identityWorkspace: positional[0]?.value || '',
|
|
185
|
+
resumeInsertIndex: launchArgs.length,
|
|
186
|
+
};
|
|
116
187
|
}
|
|
117
188
|
|
|
118
189
|
function codexAcpEnvironment(options = {}) {
|
|
@@ -145,11 +216,12 @@ const PROVIDER_ADAPTERS = Object.freeze([
|
|
|
145
216
|
interruptInput: '\x1b',
|
|
146
217
|
freshAcpSessionSources: ['codex-temporary'],
|
|
147
218
|
commands: ['codex'],
|
|
148
|
-
supportedRuntimes: ['terminal', 'acp', 'json'
|
|
219
|
+
supportedRuntimes: ['terminal', 'acp', 'json'],
|
|
149
220
|
planSession: codexSessionPlan,
|
|
221
|
+
terminalResumeArgs: (args, sessionId) => ['resume', sessionId, ...args],
|
|
150
222
|
acp: { packageName: '@agentclientprotocol/codex-acp', version: '1.1.4' },
|
|
151
223
|
prepareAcpEnvironment: codexAcpEnvironment,
|
|
152
|
-
capabilities: { runtimeSwitch: true, terminalProfile: true, goals:
|
|
224
|
+
capabilities: { runtimeSwitch: true, terminalProfile: true, goals: false },
|
|
153
225
|
},
|
|
154
226
|
{
|
|
155
227
|
id: 'claude',
|
|
@@ -174,6 +246,16 @@ const PROVIDER_ADAPTERS = Object.freeze([
|
|
|
174
246
|
commands: ['opencode'],
|
|
175
247
|
supportedRuntimes: ['terminal', 'acp', 'json'],
|
|
176
248
|
planSession: openCodeSessionPlan,
|
|
249
|
+
terminalResumeArgs: (args, sessionId) => {
|
|
250
|
+
const delimiterIndex = args.indexOf('--');
|
|
251
|
+
const insertIndex = delimiterIndex >= 0 ? delimiterIndex : args.length;
|
|
252
|
+
return [
|
|
253
|
+
...args.slice(0, insertIndex),
|
|
254
|
+
'--session',
|
|
255
|
+
sessionId,
|
|
256
|
+
...args.slice(insertIndex),
|
|
257
|
+
];
|
|
258
|
+
},
|
|
177
259
|
acp: {
|
|
178
260
|
version: 'native',
|
|
179
261
|
launch: options => ({
|
|
@@ -225,6 +307,9 @@ function providerCapabilities(provider) {
|
|
|
225
307
|
runtimeSwitch: adapter?.capabilities?.runtimeSwitch === true,
|
|
226
308
|
terminalProfile: adapter?.capabilities?.terminalProfile === true,
|
|
227
309
|
goals: adapter?.capabilities?.goals === true,
|
|
310
|
+
...(adapter
|
|
311
|
+
? chatCapabilitiesForProvider(provider)
|
|
312
|
+
: { chatRuntime: '', supportsChat: false, supportsSteer: false }),
|
|
228
313
|
};
|
|
229
314
|
}
|
|
230
315
|
|