farming-code 2.2.13 → 2.2.16
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 +81 -105
- package/README.zh_cn.md +82 -106
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/backend/acp/packaged-codex-acp.js +13 -0
- package/backend/acp-runtime.js +192 -14
- package/backend/agent-manager.js +176 -510
- package/backend/agent-runtime-binding.js +9 -55
- package/backend/chat-runtime.js +28 -0
- package/backend/codex-transcript.js +2 -1
- package/backend/config-manager.js +22 -14
- package/backend/control-api.js +3 -1
- package/backend/farming-app-cli.js +13 -0
- package/backend/farming-session-store.js +2 -1
- package/backend/npm-update-helper.js +65 -7
- package/backend/provider-adapters.js +6 -2
- package/backend/server.js +89 -104
- package/backend/storage-layout.js +0 -16
- package/backend/update-service.js +94 -5
- package/dist/acp/LICENSE.codex-acp +190 -0
- package/dist/acp/codex-acp-1.1.4.js +30718 -0
- package/dist/assets/App-y6p2yRar.js +206 -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-DKBGxoPX.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-CYZKdoqi.js → index-iKBvPjWS.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-CdkLOXYl.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 +194 -82
- package/frontend/skins/crt/index.html +2 -11
- package/frontend/skins/crt/styles/effects.css +2 -34
- package/package.json +23 -9
- 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-xASd_Y0F.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
package/backend/server.js
CHANGED
|
@@ -50,7 +50,6 @@ const { discoverSlashCommands } = require('./slash-command-discovery');
|
|
|
50
50
|
const { FarmingUpdateService } = require('./update-service');
|
|
51
51
|
const { isRestartBlockingAgent } = require('./agent-activity');
|
|
52
52
|
const { inputPartsFromMessage } = require('./input-parts');
|
|
53
|
-
const { AppServerApiBridge, createAppServerApiRouter } = require('./app-server-api');
|
|
54
53
|
const { cleanupTerminalRuntime } = require('./terminal-runtime-cleanup');
|
|
55
54
|
const { QrShareTicketStore, SHARE_TICKET_TTL_MS } = require('./qr-share-tickets');
|
|
56
55
|
const { ReviewStateStore } = require('./review-state-store');
|
|
@@ -123,7 +122,6 @@ const updateService = new FarmingUpdateService({
|
|
|
123
122
|
packagedRuntime: Boolean(process.pkg || process.env.FARMING_PACKAGED_RUNTIME === '1'),
|
|
124
123
|
getUpdateUrl: () => configManager.getSettings().updateUrl || '',
|
|
125
124
|
});
|
|
126
|
-
const appServerApiBridge = new AppServerApiBridge();
|
|
127
125
|
const usageMonitor = new UsageMonitor({ agentManager, getProviderHomes: configuredProviderHomes });
|
|
128
126
|
const codexContextWindowReader = new CodexContextWindowReader();
|
|
129
127
|
const usageSummaryCache = new AsyncCache(() => usageMonitor.getUsageSummary(), {
|
|
@@ -531,10 +529,6 @@ app.use(routePath(BASE_PATH, '/api/control'), createControlRouter(agentManager,
|
|
|
531
529
|
&& process.env.FARMING_E2E_FAKE_EXECUTABLES === '1',
|
|
532
530
|
}));
|
|
533
531
|
|
|
534
|
-
app.use(routePath(BASE_PATH, '/api/app-server'), createAppServerApiRouter({
|
|
535
|
-
bridge: appServerApiBridge,
|
|
536
|
-
}));
|
|
537
|
-
|
|
538
532
|
app.get([
|
|
539
533
|
BASE_PATH || '/',
|
|
540
534
|
`${BASE_PATH || ''}/`,
|
|
@@ -602,9 +596,21 @@ const IMAGE_ATTACHMENT_EXTENSIONS = {
|
|
|
602
596
|
'image/gif': 'gif',
|
|
603
597
|
'image/webp': 'webp',
|
|
604
598
|
};
|
|
599
|
+
const AUDIO_ATTACHMENT_EXTENSIONS = {
|
|
600
|
+
'audio/aac': 'aac',
|
|
601
|
+
'audio/flac': 'flac',
|
|
602
|
+
'audio/mp4': 'm4a',
|
|
603
|
+
'audio/mpeg': 'mp3',
|
|
604
|
+
'audio/ogg': 'ogg',
|
|
605
|
+
'audio/wav': 'wav',
|
|
606
|
+
'audio/wave': 'wav',
|
|
607
|
+
'audio/webm': 'webm',
|
|
608
|
+
'audio/x-wav': 'wav',
|
|
609
|
+
};
|
|
605
610
|
const IMAGE_ATTACHMENT_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
|
|
606
611
|
const IMAGE_ATTACHMENT_GC_INTERVAL_MS = 60 * 60 * 1000;
|
|
607
612
|
const IMAGE_ATTACHMENT_FILENAME_RE = /^pasted-image-\d+-[a-f0-9]{8}\.(?:png|jpg|gif|webp)$/;
|
|
613
|
+
const AUDIO_ATTACHMENT_FILENAME_RE = /^pasted-audio-\d+-[a-f0-9]{8}\.(?:aac|flac|m4a|mp3|ogg|wav|webm)$/;
|
|
608
614
|
let lastImageAttachmentGcAt = 0;
|
|
609
615
|
|
|
610
616
|
function imageAttachmentExtension(contentType) {
|
|
@@ -612,6 +618,11 @@ function imageAttachmentExtension(contentType) {
|
|
|
612
618
|
return IMAGE_ATTACHMENT_EXTENSIONS[normalized] || '';
|
|
613
619
|
}
|
|
614
620
|
|
|
621
|
+
function audioAttachmentExtension(contentType) {
|
|
622
|
+
const normalized = String(contentType || '').split(';')[0].trim().toLowerCase();
|
|
623
|
+
return AUDIO_ATTACHMENT_EXTENSIONS[normalized] || '';
|
|
624
|
+
}
|
|
625
|
+
|
|
615
626
|
function imageAttachmentsDir() {
|
|
616
627
|
return path.join(configManager.farmingDir, 'attachments');
|
|
617
628
|
}
|
|
@@ -634,7 +645,7 @@ async function cleanupExpiredImageAttachments(options = {}) {
|
|
|
634
645
|
|
|
635
646
|
const cutoff = now - IMAGE_ATTACHMENT_RETENTION_MS;
|
|
636
647
|
await Promise.all(entries.map(async (entry) => {
|
|
637
|
-
if (!entry.isFile() || !IMAGE_ATTACHMENT_FILENAME_RE.test(entry.name)) return;
|
|
648
|
+
if (!entry.isFile() || (!IMAGE_ATTACHMENT_FILENAME_RE.test(entry.name) && !AUDIO_ATTACHMENT_FILENAME_RE.test(entry.name))) return;
|
|
638
649
|
|
|
639
650
|
const filePath = path.join(attachmentsDir, entry.name);
|
|
640
651
|
try {
|
|
@@ -684,6 +695,30 @@ app.post(
|
|
|
684
695
|
}
|
|
685
696
|
);
|
|
686
697
|
|
|
698
|
+
app.post(
|
|
699
|
+
routePath(BASE_PATH, '/api/attachments/audio'),
|
|
700
|
+
express.raw({ type: 'audio/*', limit: '25mb' }),
|
|
701
|
+
(req, res) => {
|
|
702
|
+
const contentType = String(req.headers['content-type'] || '').split(';')[0].trim().toLowerCase();
|
|
703
|
+
const extension = audioAttachmentExtension(contentType);
|
|
704
|
+
if (!extension) {
|
|
705
|
+
res.status(415).json({ error: 'unsupported audio type' });
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
if (!Buffer.isBuffer(req.body) || req.body.length === 0) {
|
|
709
|
+
res.status(400).json({ error: 'empty audio attachment' });
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
const attachmentsDir = imageAttachmentsDir();
|
|
713
|
+
fs.mkdirSync(attachmentsDir, { recursive: true });
|
|
714
|
+
const filename = `pasted-audio-${Date.now()}-${crypto.randomBytes(4).toString('hex')}.${extension}`;
|
|
715
|
+
const filePath = path.join(attachmentsDir, filename);
|
|
716
|
+
fs.writeFileSync(filePath, req.body);
|
|
717
|
+
void cleanupExpiredImageAttachments();
|
|
718
|
+
res.status(201).json({ path: filePath, name: filename, type: contentType, size: req.body.length });
|
|
719
|
+
}
|
|
720
|
+
);
|
|
721
|
+
|
|
687
722
|
app.get(routePath(BASE_PATH, '/api/codex/models'), async (req, res) => {
|
|
688
723
|
try {
|
|
689
724
|
const catalog = await codexModelOptionsCache.get('catalog');
|
|
@@ -968,8 +1003,8 @@ app.get(routePath(BASE_PATH, '/api/agents/:agentId/session-view'), async (req, r
|
|
|
968
1003
|
});
|
|
969
1004
|
|
|
970
1005
|
app.get(routePath(BASE_PATH, '/api/agents/:agentId/codex-transcript'), async (req, res) => {
|
|
971
|
-
// Legacy JSONL transcript reader.
|
|
972
|
-
//
|
|
1006
|
+
// Legacy JSONL transcript reader. ACP Chat uses the dedicated ACP endpoint;
|
|
1007
|
+
// Terminal Agents stay in their terminal UI.
|
|
973
1008
|
const providerSession = agentManager.getAgentProviderSession(req.params.agentId);
|
|
974
1009
|
if (!providerSession) {
|
|
975
1010
|
res.status(404).json({ error: 'Agent not found' });
|
|
@@ -999,9 +1034,7 @@ app.get(routePath(BASE_PATH, '/api/agents/:agentId/codex-transcript'), async (re
|
|
|
999
1034
|
: DEFAULT_CODEX_TRANSCRIPT_MAX_TURNS;
|
|
1000
1035
|
const transcript = await readCodexTranscript(providerSession.sessionId, {
|
|
1001
1036
|
maxTurns,
|
|
1002
|
-
codexHome:
|
|
1003
|
-
? (providerSession.codexAppServerHomePath || providerSession.providerHomePath || '')
|
|
1004
|
-
: (providerSession.providerHomePath || ''),
|
|
1037
|
+
codexHome: providerSession.providerHomePath || '',
|
|
1005
1038
|
});
|
|
1006
1039
|
res.json({ transcript });
|
|
1007
1040
|
} catch (error) {
|
|
@@ -1010,20 +1043,6 @@ app.get(routePath(BASE_PATH, '/api/agents/:agentId/codex-transcript'), async (re
|
|
|
1010
1043
|
}
|
|
1011
1044
|
});
|
|
1012
1045
|
|
|
1013
|
-
app.get(routePath(BASE_PATH, '/api/agents/:agentId/codex-app-server-transcript'), async (req, res) => {
|
|
1014
|
-
try {
|
|
1015
|
-
const requestedMaxTurns = Number.parseInt(String(req.query.maxTurns || ''), 10);
|
|
1016
|
-
const maxTurns = Number.isFinite(requestedMaxTurns)
|
|
1017
|
-
? Math.min(MAX_CODEX_TRANSCRIPT_TURNS, Math.max(20, requestedMaxTurns))
|
|
1018
|
-
: DEFAULT_CODEX_TRANSCRIPT_MAX_TURNS;
|
|
1019
|
-
const transcript = agentManager.getCodexAppServerTranscript(req.params.agentId, { maxTurns });
|
|
1020
|
-
res.json({ transcript });
|
|
1021
|
-
} catch (error) {
|
|
1022
|
-
const message = error && error.message ? error.message : 'Failed to read Codex App Server transcript';
|
|
1023
|
-
res.status(/not using the Codex App Server runtime/i.test(message) ? 409 : 500).json({ error: message });
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
|
-
|
|
1027
1046
|
app.get(routePath(BASE_PATH, '/api/agents/:agentId/json-cli-transcript'), async (req, res) => {
|
|
1028
1047
|
try {
|
|
1029
1048
|
const transcript = agentManager.getJsonCliTranscript(req.params.agentId, {
|
|
@@ -1191,6 +1210,15 @@ app.post(routePath(BASE_PATH, '/api/agents/:agentId/acp-session/authenticate'),
|
|
|
1191
1210
|
}
|
|
1192
1211
|
});
|
|
1193
1212
|
|
|
1213
|
+
app.post(routePath(BASE_PATH, '/api/agents/:agentId/acp-session/logout'), async (req, res) => {
|
|
1214
|
+
try {
|
|
1215
|
+
res.json(await agentManager.logoutAcpAgent(req.params.agentId));
|
|
1216
|
+
} catch (error) {
|
|
1217
|
+
const message = error && error.message ? error.message : 'Failed to log out ACP Agent';
|
|
1218
|
+
res.status(message === 'Agent not found' ? 404 : 409).json({ error: message });
|
|
1219
|
+
}
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1194
1222
|
app.post(routePath(BASE_PATH, '/api/agents/:agentId/acp-session/fork'), express.json(), async (req, res) => {
|
|
1195
1223
|
try {
|
|
1196
1224
|
res.json(await agentManager.forkAcpSession(req.params.agentId, req.body || {}));
|
|
@@ -1243,41 +1271,6 @@ app.patch(routePath(BASE_PATH, '/api/agents/:agentId/acp-session'), express.json
|
|
|
1243
1271
|
}
|
|
1244
1272
|
});
|
|
1245
1273
|
|
|
1246
|
-
app.get(routePath(BASE_PATH, '/api/agents/:agentId/codex-goal'), async (req, res) => {
|
|
1247
|
-
try {
|
|
1248
|
-
const goal = await agentManager.getCodexAppServerGoal(req.params.agentId);
|
|
1249
|
-
res.json({ goal });
|
|
1250
|
-
} catch (error) {
|
|
1251
|
-
const message = error && error.message ? error.message : 'Failed to read Codex goal';
|
|
1252
|
-
res.status(message === 'Agent not found' ? 404 : 400).json({ error: message });
|
|
1253
|
-
}
|
|
1254
|
-
});
|
|
1255
|
-
|
|
1256
|
-
app.patch(routePath(BASE_PATH, '/api/agents/:agentId/codex-goal'), express.json(), async (req, res) => {
|
|
1257
|
-
try {
|
|
1258
|
-
const body = req.body || {};
|
|
1259
|
-
const goal = await agentManager.setCodexAppServerGoal(req.params.agentId, {
|
|
1260
|
-
objective: typeof body.objective === 'string' ? body.objective : undefined,
|
|
1261
|
-
status: typeof body.status === 'string' ? body.status : undefined,
|
|
1262
|
-
...(Object.prototype.hasOwnProperty.call(body, 'tokenBudget') ? { tokenBudget: body.tokenBudget } : {}),
|
|
1263
|
-
});
|
|
1264
|
-
res.json({ goal });
|
|
1265
|
-
} catch (error) {
|
|
1266
|
-
const message = error && error.message ? error.message : 'Failed to update Codex goal';
|
|
1267
|
-
res.status(message === 'Agent not found' ? 404 : 400).json({ error: message });
|
|
1268
|
-
}
|
|
1269
|
-
});
|
|
1270
|
-
|
|
1271
|
-
app.delete(routePath(BASE_PATH, '/api/agents/:agentId/codex-goal'), async (req, res) => {
|
|
1272
|
-
try {
|
|
1273
|
-
await agentManager.clearCodexAppServerGoal(req.params.agentId);
|
|
1274
|
-
res.json({ goal: null });
|
|
1275
|
-
} catch (error) {
|
|
1276
|
-
const message = error && error.message ? error.message : 'Failed to clear Codex goal';
|
|
1277
|
-
res.status(message === 'Agent not found' ? 404 : 400).json({ error: message });
|
|
1278
|
-
}
|
|
1279
|
-
});
|
|
1280
|
-
|
|
1281
1274
|
app.post(routePath(BASE_PATH, '/api/agents/:agentId/codex-terminal-profile'), express.json(), async (req, res) => {
|
|
1282
1275
|
const requestAbort = new globalThis.AbortController();
|
|
1283
1276
|
const abortRequest = () => requestAbort.abort(new Error('Terminal profile request was canceled'));
|
|
@@ -1710,7 +1703,7 @@ async function resumeAgentSessionById(provider, rawSessionId, options = {}) {
|
|
|
1710
1703
|
requiredCliVersion: normalizedProvider === 'codex' && session ? session.cliVersion : '',
|
|
1711
1704
|
projectWorkspace: session ? (session.workspace || session.cwd || '') : '',
|
|
1712
1705
|
source: shouldFork ? resumeSource.replace('-history:', '-history-fork:') : resumeSource,
|
|
1713
|
-
agentRuntimeMode:
|
|
1706
|
+
agentRuntimeMode: ['chat', 'acp'].includes(options.agentRuntimeMode) ? 'chat' : 'terminal',
|
|
1714
1707
|
acpHistoryMode: options.acpHistoryMode === 'resume' ? 'resume' : 'load',
|
|
1715
1708
|
providerHomeId: resolvedProviderHomeId,
|
|
1716
1709
|
providerHomePath: session ? (session.providerHomePath || '') : '',
|
|
@@ -1754,7 +1747,7 @@ async function startResumedAgentSession(req, res, provider, rawSessionId) {
|
|
|
1754
1747
|
allowUnarchiveArchived,
|
|
1755
1748
|
providerHomeId: req.body && typeof req.body.providerHomeId === 'string' ? req.body.providerHomeId : '',
|
|
1756
1749
|
customTitle: req.body && typeof req.body.customTitle === 'string' ? req.body.customTitle : '',
|
|
1757
|
-
agentRuntimeMode: req.body && req.body.agentRuntimeMode
|
|
1750
|
+
agentRuntimeMode: req.body && ['chat', 'acp'].includes(req.body.agentRuntimeMode) ? 'chat' : 'terminal',
|
|
1758
1751
|
acpHistoryMode: req.body && req.body.acpHistoryMode === 'resume' ? 'resume' : 'load',
|
|
1759
1752
|
});
|
|
1760
1753
|
|
|
@@ -2018,66 +2011,66 @@ async function sendInputMessage(ws, data) {
|
|
|
2018
2011
|
|
|
2019
2012
|
async function sendComposerInputMessage(ws, data) {
|
|
2020
2013
|
const targetAgentId = resolveInputTargetAgentId(ws, data);
|
|
2014
|
+
const requestId = typeof data.requestId === 'string' ? data.requestId : '';
|
|
2015
|
+
const responseAgentId = targetAgentId || (typeof data.agentId === 'string' ? data.agentId : '');
|
|
2016
|
+
const respond = (accepted, message = '') => {
|
|
2017
|
+
if (!requestId || !responseAgentId) return;
|
|
2018
|
+
ws.send(JSON.stringify({
|
|
2019
|
+
type: 'composer-input-result',
|
|
2020
|
+
requestId,
|
|
2021
|
+
agentId: responseAgentId,
|
|
2022
|
+
accepted,
|
|
2023
|
+
...(message ? { message } : {}),
|
|
2024
|
+
}));
|
|
2025
|
+
};
|
|
2021
2026
|
const message = typeof data.message === 'string' ? data.message : '';
|
|
2022
2027
|
const content = [];
|
|
2023
2028
|
if (message.trim()) content.push({ type: 'text', text: message });
|
|
2024
2029
|
const attachmentsRoot = path.resolve(imageAttachmentsDir());
|
|
2025
2030
|
const attachments = Array.isArray(data.attachments) ? data.attachments.slice(0, 8) : [];
|
|
2026
2031
|
for (const attachment of attachments) {
|
|
2027
|
-
if (attachment?.kind
|
|
2032
|
+
if (!['image', 'audio'].includes(attachment?.kind) || typeof attachment.path !== 'string') continue;
|
|
2028
2033
|
const filePath = path.resolve(attachment.path);
|
|
2029
2034
|
if (!filePath.startsWith(`${attachmentsRoot}${path.sep}`)) continue;
|
|
2030
|
-
const mimeType = typeof attachment.type === 'string' && /^image\/(?:png|jpe?g|gif|webp)$/i.test(attachment.type)
|
|
2035
|
+
const mimeType = typeof attachment.type === 'string' && attachment.kind === 'image' && /^image\/(?:png|jpe?g|gif|webp)$/i.test(attachment.type)
|
|
2031
2036
|
? attachment.type.toLowerCase()
|
|
2032
|
-
: ''
|
|
2037
|
+
: (typeof attachment.type === 'string' && attachment.kind === 'audio' && Object.hasOwn(AUDIO_ATTACHMENT_EXTENSIONS, attachment.type.toLowerCase())
|
|
2038
|
+
? attachment.type.toLowerCase()
|
|
2039
|
+
: '');
|
|
2033
2040
|
if (!mimeType) continue;
|
|
2034
2041
|
try {
|
|
2035
2042
|
const data = await fs.promises.readFile(filePath);
|
|
2036
2043
|
if (data.length === 0 || data.length > 12 * 1024 * 1024) continue;
|
|
2037
2044
|
content.push({
|
|
2038
|
-
type:
|
|
2045
|
+
type: attachment.kind,
|
|
2039
2046
|
data: data.toString('base64'),
|
|
2040
2047
|
mimeType,
|
|
2048
|
+
path: filePath,
|
|
2041
2049
|
uri: pathToFileURL(filePath).href,
|
|
2042
2050
|
});
|
|
2043
2051
|
} catch {
|
|
2044
2052
|
// The text fallback already explains failed or unavailable uploads.
|
|
2045
2053
|
}
|
|
2046
2054
|
}
|
|
2047
|
-
if (!targetAgentId || content.length === 0)
|
|
2055
|
+
if (!targetAgentId || content.length === 0) {
|
|
2056
|
+
respond(false, 'Composer message is empty');
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2048
2059
|
const targetAgent = agentManager.getState().agents.find(agent => agent.id === targetAgentId);
|
|
2049
2060
|
const structuredRuntime = targetAgent && runtimeKind(targetAgent) !== 'terminal';
|
|
2050
2061
|
if (!structuredRuntime) {
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
}));
|
|
2062
|
+
const error = 'Terminal Composer input requires the active terminal owner';
|
|
2063
|
+
if (requestId) respond(false, error);
|
|
2064
|
+
else ws.send(JSON.stringify({ type: 'error', message: error }));
|
|
2055
2065
|
return;
|
|
2056
2066
|
}
|
|
2057
2067
|
try {
|
|
2058
2068
|
await agentManager.sendComposerMessage(targetAgentId, content);
|
|
2069
|
+
respond(true);
|
|
2059
2070
|
} catch (error) {
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
}));
|
|
2064
|
-
}
|
|
2065
|
-
}
|
|
2066
|
-
|
|
2067
|
-
async function respondToAppServerRequest(ws, data) {
|
|
2068
|
-
const targetAgentId = resolveInputTargetAgentId(ws, data);
|
|
2069
|
-
const requestId = typeof data.requestId === 'string' ? data.requestId : '';
|
|
2070
|
-
if (!targetAgentId || !requestId) return;
|
|
2071
|
-
try {
|
|
2072
|
-
agentManager.respondToCodexAppServerRequest(targetAgentId, requestId, data.result, {
|
|
2073
|
-
reject: data.reject === true,
|
|
2074
|
-
reason: typeof data.reason === 'string' ? data.reason : '',
|
|
2075
|
-
});
|
|
2076
|
-
} catch (error) {
|
|
2077
|
-
ws.send(JSON.stringify({
|
|
2078
|
-
type: 'error',
|
|
2079
|
-
message: error && error.message ? error.message : 'Failed to respond to Codex App Server request',
|
|
2080
|
-
}));
|
|
2071
|
+
const message = error && error.message ? error.message : 'Failed to send Composer message';
|
|
2072
|
+
if (requestId) respond(false, message);
|
|
2073
|
+
else ws.send(JSON.stringify({ type: 'error', message }));
|
|
2081
2074
|
}
|
|
2082
2075
|
}
|
|
2083
2076
|
|
|
@@ -2107,12 +2100,11 @@ function handleMessage(ws, data) {
|
|
|
2107
2100
|
workflowTemplate: typeof data.workflowTemplate === 'string' ? data.workflowTemplate : '',
|
|
2108
2101
|
customTitle: typeof data.customTitle === 'string' ? data.customTitle : '',
|
|
2109
2102
|
codexApprovalMode: typeof data.codexApprovalMode === 'string' ? data.codexApprovalMode : undefined,
|
|
2110
|
-
|
|
2111
|
-
? data.codexRuntimeMode
|
|
2112
|
-
: undefined,
|
|
2113
|
-
agentRuntimeMode: ['json', 'acp'].includes(data.agentRuntimeMode) ? data.agentRuntimeMode : 'terminal',
|
|
2103
|
+
agentRuntimeMode: ['json', 'acp', 'chat'].includes(data.agentRuntimeMode) ? data.agentRuntimeMode : 'terminal',
|
|
2114
2104
|
acpHistoryMode: data.acpHistoryMode === 'resume' ? 'resume' : 'load',
|
|
2115
2105
|
providerHomeId: typeof data.providerHomeId === 'string' ? data.providerHomeId : '',
|
|
2106
|
+
...(Array.isArray(data.additionalDirectories) ? { additionalDirectories: data.additionalDirectories } : {}),
|
|
2107
|
+
...(Array.isArray(data.mcpServers) ? { mcpServers: data.mcpServers } : {}),
|
|
2116
2108
|
...(data.dangerouslySkipPermissions === true ? { dangerouslySkipPermissions: true } : {}),
|
|
2117
2109
|
});
|
|
2118
2110
|
break;
|
|
@@ -2129,12 +2121,6 @@ function handleMessage(ws, data) {
|
|
|
2129
2121
|
}
|
|
2130
2122
|
break;
|
|
2131
2123
|
|
|
2132
|
-
case 'app-server-request-response':
|
|
2133
|
-
{
|
|
2134
|
-
void respondToAppServerRequest(ws, data);
|
|
2135
|
-
}
|
|
2136
|
-
break;
|
|
2137
|
-
|
|
2138
2124
|
case 'acp-permission-response':
|
|
2139
2125
|
try {
|
|
2140
2126
|
agentManager.respondToAcpPermission(
|
|
@@ -2717,7 +2703,6 @@ module.exports = {
|
|
|
2717
2703
|
server,
|
|
2718
2704
|
wss,
|
|
2719
2705
|
agentManager,
|
|
2720
|
-
appServerApiBridge,
|
|
2721
2706
|
workspaceFileService,
|
|
2722
2707
|
handleMessage,
|
|
2723
2708
|
resolveCliBinDir,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const os = require('os');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const crypto = require('crypto');
|
|
4
3
|
|
|
5
4
|
function farmingConfigDir(env = process.env) {
|
|
6
5
|
return env.FARMING_CONFIG_DIR || path.join(env.HOME || os.homedir(), '.farming');
|
|
@@ -110,23 +109,8 @@ function farmingNetTrustFile(configDir) {
|
|
|
110
109
|
return path.join(configDir, 'farming-net-trust.json');
|
|
111
110
|
}
|
|
112
111
|
|
|
113
|
-
function codexAppServerRuntimeDir(configDir) {
|
|
114
|
-
return path.join(configDir, 'c');
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function codexAppServerAgentHome(configDir, agentId) {
|
|
118
|
-
const safeAgentId = String(agentId || '').trim();
|
|
119
|
-
if (!/^agent-[A-Za-z0-9_-]+$/.test(safeAgentId)) {
|
|
120
|
-
throw new Error('Invalid Codex App Server agent id');
|
|
121
|
-
}
|
|
122
|
-
const homeId = crypto.createHash('sha256').update(safeAgentId).digest('hex').slice(0, 16);
|
|
123
|
-
return path.join(codexAppServerRuntimeDir(configDir), homeId);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
112
|
module.exports = {
|
|
127
113
|
acpCheckpointsDir,
|
|
128
|
-
codexAppServerAgentHome,
|
|
129
|
-
codexAppServerRuntimeDir,
|
|
130
114
|
farmingNetInstancesFile,
|
|
131
115
|
farmingNetServerLogFile,
|
|
132
116
|
farmingNetServerStateFile,
|
|
@@ -681,6 +681,45 @@ function npmPackageMetadataUrl(registryUrl, packageName) {
|
|
|
681
681
|
return `${registry}/${encodeURIComponent(packageName).replace(/^%40/, '@')}`;
|
|
682
682
|
}
|
|
683
683
|
|
|
684
|
+
function normalizePathForCompare(filePath) {
|
|
685
|
+
try {
|
|
686
|
+
return fs.realpathSync(filePath);
|
|
687
|
+
} catch {
|
|
688
|
+
return path.resolve(filePath);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function npmPackageRoot(npmRoot, packageName) {
|
|
693
|
+
return path.join(npmRoot, ...String(packageName || '').split('/').filter(Boolean));
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function npmPrefixForPackageRoot(packageRoot, packageName) {
|
|
697
|
+
const segments = String(packageName || '').split('/').filter(Boolean);
|
|
698
|
+
if (!path.isAbsolute(packageRoot) || segments.length === 0) return '';
|
|
699
|
+
let npmRoot = packageRoot;
|
|
700
|
+
for (let index = 0; index < segments.length; index += 1) npmRoot = path.dirname(npmRoot);
|
|
701
|
+
return path.dirname(path.dirname(npmRoot));
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
function readNpmGlobalRoot(npmCommand, npmPrefix, execFile = childProcess.execFile) {
|
|
705
|
+
const args = ['root', '--global'];
|
|
706
|
+
if (npmPrefix) args.push('--prefix', npmPrefix);
|
|
707
|
+
return new Promise((resolve, reject) => {
|
|
708
|
+
execFile(npmCommand, args, (error, stdout) => {
|
|
709
|
+
if (error) {
|
|
710
|
+
reject(error);
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
const root = String(stdout || '').split(/\r?\n/).map(value => value.trim()).find(Boolean);
|
|
714
|
+
if (!root) {
|
|
715
|
+
reject(new Error('npm root --global returned no path'));
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
resolve(root);
|
|
719
|
+
});
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
|
|
684
723
|
function npmVersionsFromMetadata(metadata, currentVersion) {
|
|
685
724
|
const versions = metadata && metadata.versions && typeof metadata.versions === 'object'
|
|
686
725
|
? Object.keys(metadata.versions)
|
|
@@ -711,6 +750,8 @@ class FarmingUpdateService {
|
|
|
711
750
|
});
|
|
712
751
|
this.npmPackageName = options.npmPackageName || NPM_PACKAGE_NAME;
|
|
713
752
|
this.npmRegistryUrl = options.npmRegistryUrl || process.env.FARMING_NPM_REGISTRY || DEFAULT_NPM_REGISTRY;
|
|
753
|
+
this.npmPackageRoot = options.npmPackageRoot || process.env.FARMING_MANAGED_PACKAGE_ROOT || '';
|
|
754
|
+
this.npmPrefix = options.npmPrefix || process.env.FARMING_NPM_PREFIX || '';
|
|
714
755
|
this.runtime = options.platform || options.arch
|
|
715
756
|
? {
|
|
716
757
|
platform: normalizePlatform(options.platform || process.platform),
|
|
@@ -724,6 +765,8 @@ class FarmingUpdateService {
|
|
|
724
765
|
this.downloadFile = options.downloadFile || downloadFile;
|
|
725
766
|
this.listArchiveEntries = options.listArchiveEntries || listTarArchiveEntries;
|
|
726
767
|
this.execFile = options.execFile || childProcess.execFile;
|
|
768
|
+
this.getNpmGlobalRoot = options.getNpmGlobalRoot
|
|
769
|
+
|| ((npmCommand, npmPrefix) => readNpmGlobalRoot(npmCommand, npmPrefix, this.execFile));
|
|
727
770
|
this.spawn = options.spawn || childProcess.spawn;
|
|
728
771
|
this.latestCache = null;
|
|
729
772
|
this.npmCache = null;
|
|
@@ -782,6 +825,7 @@ class FarmingUpdateService {
|
|
|
782
825
|
const current = this.currentVersion();
|
|
783
826
|
const currentVersion = normalizeVersion(current.releaseVersion || current.packageVersion);
|
|
784
827
|
const metadata = await this.npmMetadata(options);
|
|
828
|
+
const target = await this.npmUpdateTarget();
|
|
785
829
|
const versions = npmVersionsFromMetadata(metadata, currentVersion);
|
|
786
830
|
const latestVersion = normalizeVersion(metadata && metadata['dist-tags'] && metadata['dist-tags'].latest)
|
|
787
831
|
|| versions[0]?.version
|
|
@@ -791,7 +835,8 @@ class FarmingUpdateService {
|
|
|
791
835
|
|| versions.find(version => version.version === latestVersion)
|
|
792
836
|
|| versions[0]
|
|
793
837
|
|| null;
|
|
794
|
-
const
|
|
838
|
+
const blockedReason = target.proven ? '' : target.error;
|
|
839
|
+
const available = Boolean(selected && selected.available && target.proven);
|
|
795
840
|
return {
|
|
796
841
|
method: 'npm',
|
|
797
842
|
current,
|
|
@@ -802,24 +847,63 @@ class FarmingUpdateService {
|
|
|
802
847
|
publishedAt: '',
|
|
803
848
|
assetName: latestVersion,
|
|
804
849
|
assetSize: 0,
|
|
805
|
-
blockedReason
|
|
850
|
+
blockedReason,
|
|
806
851
|
source: npmPackageMetadataUrl(this.npmRegistryUrl, this.npmPackageName),
|
|
807
852
|
},
|
|
808
853
|
selected: {
|
|
809
854
|
version: selected?.version || '',
|
|
810
855
|
assetName: selected?.assetName || '',
|
|
811
856
|
assetSize: selected?.assetSize || 0,
|
|
812
|
-
blockedReason: selected?.blockedReason ||
|
|
857
|
+
blockedReason: selected?.blockedReason || blockedReason,
|
|
813
858
|
},
|
|
814
859
|
versions,
|
|
815
860
|
runtime: this.runtime,
|
|
861
|
+
target,
|
|
816
862
|
available,
|
|
817
|
-
installable: Boolean(selected),
|
|
863
|
+
installable: Boolean(selected && target.proven),
|
|
818
864
|
checkedAt: new Date(this.now()).toISOString(),
|
|
819
865
|
state: this.currentInstallState(),
|
|
820
866
|
};
|
|
821
867
|
}
|
|
822
868
|
|
|
869
|
+
async npmUpdateTarget() {
|
|
870
|
+
const runningPackageRoot = String(this.npmPackageRoot || '').trim();
|
|
871
|
+
if (!path.isAbsolute(runningPackageRoot)) {
|
|
872
|
+
return {
|
|
873
|
+
proven: false,
|
|
874
|
+
error: 'npm update target could not be proven: the running package has no managed package-root provenance',
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
const npmCommand = process.env.FARMING_NPM_COMMAND || 'npm';
|
|
878
|
+
const npmPrefix = this.npmPrefix || npmPrefixForPackageRoot(runningPackageRoot, this.npmPackageName);
|
|
879
|
+
if (!npmPrefix) {
|
|
880
|
+
return {
|
|
881
|
+
proven: false,
|
|
882
|
+
error: 'npm update target could not be proven: the running package has no npm prefix',
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
try {
|
|
886
|
+
const root = await this.getNpmGlobalRoot(npmCommand, npmPrefix);
|
|
887
|
+
const targetPackageRoot = npmPackageRoot(root, this.npmPackageName);
|
|
888
|
+
if (normalizePathForCompare(runningPackageRoot) !== normalizePathForCompare(targetPackageRoot)) {
|
|
889
|
+
return {
|
|
890
|
+
proven: false,
|
|
891
|
+
error: `npm update would target a different installation: running ${runningPackageRoot}; npm ${targetPackageRoot}`,
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
return {
|
|
895
|
+
proven: true,
|
|
896
|
+
npmPrefix,
|
|
897
|
+
packageRoot: targetPackageRoot,
|
|
898
|
+
};
|
|
899
|
+
} catch (error) {
|
|
900
|
+
return {
|
|
901
|
+
proven: false,
|
|
902
|
+
error: `npm update target could not be inspected: ${error.message || String(error)}`,
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
823
907
|
unsupportedStatus() {
|
|
824
908
|
const current = this.currentVersion();
|
|
825
909
|
const reason = installMethodBlockedReason(this.installMethod);
|
|
@@ -1081,9 +1165,11 @@ class FarmingUpdateService {
|
|
|
1081
1165
|
stateFile: this.updateStateFile,
|
|
1082
1166
|
logPath: this.updateLogFile,
|
|
1083
1167
|
cliPath: path.join(this.rootDir, 'bin', 'farming'),
|
|
1168
|
+
packageRoot: status.target.packageRoot,
|
|
1084
1169
|
nodePath,
|
|
1085
1170
|
npmCommand: process.env.FARMING_NPM_COMMAND || 'npm',
|
|
1086
|
-
npmPrefix:
|
|
1171
|
+
npmPrefix: status.target.npmPrefix,
|
|
1172
|
+
npmFallbackRegistryUrl: this.npmRegistryUrl,
|
|
1087
1173
|
serverPid: process.pid,
|
|
1088
1174
|
configDir: this.configDir,
|
|
1089
1175
|
port: process.env.FARMING_PORT || process.env.PORT || '6694',
|
|
@@ -1181,7 +1267,10 @@ module.exports = {
|
|
|
1181
1267
|
installMethodAllowsBundleUpdate,
|
|
1182
1268
|
normalizeVersion,
|
|
1183
1269
|
npmPackageMetadataUrl,
|
|
1270
|
+
npmPrefixForPackageRoot,
|
|
1271
|
+
npmPackageRoot,
|
|
1184
1272
|
npmVersionsFromMetadata,
|
|
1273
|
+
readNpmGlobalRoot,
|
|
1185
1274
|
releaseInstallDir,
|
|
1186
1275
|
manifestAssetSafety,
|
|
1187
1276
|
normalizeSha256,
|