@axhub/genie 0.2.7 → 0.2.9
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/LICENSE +21 -675
- package/dist/api-docs.html +2 -2
- package/dist/assets/App-GBcTeeUS.js +460 -0
- package/dist/assets/App-qxJ8_QYu.css +32 -0
- package/dist/assets/ReviewApp-C9K--AQE.js +1 -0
- package/dist/assets/{_basePickBy-C19AekOu.js → _basePickBy-DR_8uFCo.js} +1 -1
- package/dist/assets/{_baseUniq-JsnevLw_.js → _baseUniq-D0njlQ_7.js} +1 -1
- package/dist/assets/{arc-BLpcuBlf.js → arc-CKlr_Rec.js} +1 -1
- package/dist/assets/architectureDiagram-2XIMDMQ5-BmO_uLUH.js +36 -0
- package/dist/assets/{blockDiagram-WCTKOSBZ-DQBLwsUS.js → blockDiagram-WCTKOSBZ-DhAeO-56.js} +3 -3
- package/dist/assets/c4Diagram-IC4MRINW-C67kFoXx.js +10 -0
- package/dist/assets/channel-V3MBjKys.js +1 -0
- package/dist/assets/{chunk-4BX2VUAB-De63kbgc.js → chunk-4BX2VUAB-mLLagvJi.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-DtTDDdM9.js → chunk-55IACEB6-Lx-hOjlM.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-DHuwd8tw.js → chunk-FMBD7UC4-Bt-XmVUV.js} +1 -1
- package/dist/assets/{chunk-JSJVCQXG-BgytFtmO.js → chunk-JSJVCQXG-Cya6gaDV.js} +1 -1
- package/dist/assets/{chunk-KX2RTZJC-nZdp86aN.js → chunk-KX2RTZJC-Bd7Ig6tF.js} +1 -1
- package/dist/assets/chunk-NQ4KR5QH-5UAE0Vg-.js +220 -0
- package/dist/assets/{chunk-QZHKN3VN-DvUQ3mnO.js → chunk-QZHKN3VN-BAxZ8m7w.js} +1 -1
- package/dist/assets/chunk-WL4C6EOR-DjDPvUUP.js +189 -0
- package/dist/assets/classDiagram-VBA2DB6C-C790yYiY.js +1 -0
- package/dist/assets/classDiagram-v2-RAHNMMFH-C790yYiY.js +1 -0
- package/dist/assets/clone-BbMGfZwt.js +1 -0
- package/dist/assets/cose-bilkent-S5V4N54A-D-60XrkJ.js +1 -0
- package/dist/assets/cytoscape.esm-2ZfV8NB5.js +331 -0
- package/dist/assets/{dagre-KLK3FWXG-CHYIvW47.js → dagre-KLK3FWXG-bqu3ZS4K.js} +1 -1
- package/dist/assets/diagram-E7M64L7V-BueeqoYm.js +24 -0
- package/dist/assets/{diagram-IFDJBPK2-Dzsiln_C.js → diagram-IFDJBPK2-D4fDv2E7.js} +1 -1
- package/dist/assets/{diagram-P4PSJMXO-DKnGbUpE.js → diagram-P4PSJMXO-WqipY3fN.js} +1 -1
- package/dist/assets/erDiagram-INFDFZHY-D0oVnO-x.js +70 -0
- package/dist/assets/{flowDiagram-PKNHOUZH-BAZ2-jKp.js → flowDiagram-PKNHOUZH-DzbGyxrr.js} +4 -4
- package/dist/assets/ganttDiagram-A5KZAMGK-BwhbbgCP.js +292 -0
- package/dist/assets/{gitGraphDiagram-K3NZZRJ6-BflpyjGy.js → gitGraphDiagram-K3NZZRJ6-DZgAh_KM.js} +1 -1
- package/dist/assets/{graph-suelaXFh.js → graph-DzKos-N0.js} +1 -1
- package/dist/assets/highlighted-body-TPN3WLV5-CKDMgz3X.js +1 -0
- package/dist/assets/index-DiQlHzGj.js +2 -0
- package/dist/assets/index-Drat2nB9.css +1 -0
- package/dist/assets/{infoDiagram-LFFYTUFH-pfD1FA3p.js → infoDiagram-LFFYTUFH-BFicZbTf.js} +1 -1
- package/dist/assets/ishikawaDiagram-PHBUUO56-CtihxDxl.js +70 -0
- package/dist/assets/journeyDiagram-4ABVD52K-Du00J8_d.js +139 -0
- package/dist/assets/{kanban-definition-K7BYSVSG-FWinmur1.js → kanban-definition-K7BYSVSG-BJi9S0iQ.js} +5 -5
- package/dist/assets/{layout-vcz43XvZ.js → layout-B80Sityu.js} +1 -1
- package/dist/assets/{linear-le4gc0vx.js → linear-sRQLOf5H.js} +1 -1
- package/dist/assets/mermaid-O7DHMXV3-CBuVs4eJ.js +1038 -0
- package/dist/assets/mindmap-definition-YRQLILUH-C5IL_xi-.js +68 -0
- package/dist/assets/{pieDiagram-SKSYHLDU-C7PKDh3b.js → pieDiagram-SKSYHLDU-CeTwlJ8z.js} +2 -2
- package/dist/assets/quadrantDiagram-337W2JSQ-COfUcLWt.js +7 -0
- package/dist/assets/requirementDiagram-Z7DCOOCP-DSb-CJ5B.js +73 -0
- package/dist/assets/{sankeyDiagram-WA2Y5GQK-4gulcOP4.js → sankeyDiagram-WA2Y5GQK-8jtuVb45.js} +3 -3
- package/dist/assets/sequenceDiagram-2WXFIKYE-C2VpkMwA.js +145 -0
- package/dist/assets/{stateDiagram-RAJIS63D-CB4Vl7qM.js → stateDiagram-RAJIS63D-fmwMqxxc.js} +1 -1
- package/dist/assets/stateDiagram-v2-FVOUBMTO-9GGXVWrR.js +1 -0
- package/dist/assets/timeline-definition-YZTLITO2-Dx1hP5lg.js +61 -0
- package/dist/assets/{treemap-KZPCXAKY-DZSEE6Hz.js → treemap-KZPCXAKY-CkLOdYCZ.js} +58 -58
- package/dist/assets/vendor-codemirror-BxPY6emf.js +39 -0
- package/dist/assets/vendor-react-xmA_f8ig.js +59 -0
- package/dist/assets/vendor-xterm-DfaPXD3y.js +66 -0
- package/dist/assets/{vennDiagram-LZ73GAT5-8E_G06fI.js → vennDiagram-LZ73GAT5-D6KWcnln.js} +4 -4
- package/dist/assets/xychartDiagram-JWTSCODW-6fh6qmzN.js +7 -0
- package/dist/index.html +5 -5
- package/package.json +36 -35
- package/server/acp-runtime/client.js +91 -17
- package/server/acp-runtime/index.js +5 -16
- package/server/acp-runtime/session-store.js +4 -4
- package/server/channels/runtime/AgentRuntimeAdapter.js +1 -10
- package/server/claude-sdk.js +1 -3
- package/server/cli.js +159 -2
- package/server/external-agent/service.js +24 -6
- package/server/external-agent/ws.js +63 -3
- package/server/gemini-cli.js +1 -3
- package/server/index.js +120 -19
- package/server/openai-codex.js +1 -3
- package/server/opencode-cli.js +1 -3
- package/server/projects.js +654 -236
- package/server/routes/cc-connect.js +1131 -0
- package/server/routes/cli-auth.js +1 -73
- package/server/routes/commands.js +4 -9
- package/server/routes/projects.js +45 -24
- package/server/routes/session-core.js +149 -86
- package/server/session-core/eventStore.js +45 -18
- package/server/session-core/providerAdapters.js +50 -13
- package/server/session-core/providerDiscovery.js +8 -3
- package/server/session-core/runtimeState.js +8 -0
- package/server/utils/ccConnectManager.js +390 -0
- package/server/utils/ccConnectState.js +575 -0
- package/server/utils/resolveCommandPath.js +71 -0
- package/server/utils/workspaceRoots.js +154 -0
- package/shared/conversationEvents.js +78 -14
- package/dist/assets/App-BWSqiXAT.js +0 -220
- package/dist/assets/App-DrlLKa8f.css +0 -1
- package/dist/assets/ReviewApp-nz3mbArg.js +0 -1
- package/dist/assets/architectureDiagram-2XIMDMQ5-CarjBOOv.js +0 -36
- package/dist/assets/c4Diagram-IC4MRINW-CGobwBIj.js +0 -10
- package/dist/assets/channel-DkFNxV_H.js +0 -1
- package/dist/assets/chunk-NQ4KR5QH-CMH6EDP2.js +0 -220
- package/dist/assets/chunk-WL4C6EOR-Dn7db_6t.js +0 -189
- package/dist/assets/classDiagram-VBA2DB6C-DtwCEe8S.js +0 -1
- package/dist/assets/classDiagram-v2-RAHNMMFH-DtwCEe8S.js +0 -1
- package/dist/assets/clone-C0lCEIEO.js +0 -1
- package/dist/assets/cose-bilkent-S5V4N54A-DD_nzqsz.js +0 -1
- package/dist/assets/cytoscape.esm-5J0xJHOV.js +0 -321
- package/dist/assets/diagram-E7M64L7V-TVdvHtGc.js +0 -24
- package/dist/assets/erDiagram-INFDFZHY-5Kw0bByo.js +0 -70
- package/dist/assets/ganttDiagram-A5KZAMGK-CsADFkcq.js +0 -292
- package/dist/assets/highlighted-body-OFNGDK62-CZrBMazC.js +0 -1
- package/dist/assets/index-B01NxbUv.css +0 -1
- package/dist/assets/index-DW5pGgQ_.js +0 -2
- package/dist/assets/ishikawaDiagram-PHBUUO56-ndm9snwO.js +0 -70
- package/dist/assets/journeyDiagram-4ABVD52K-HgF2t7z5.js +0 -139
- package/dist/assets/mermaid-GHXKKRXX-CK8m3lad.js +0 -870
- package/dist/assets/mindmap-definition-YRQLILUH-CNq9SKj4.js +0 -68
- package/dist/assets/quadrantDiagram-337W2JSQ-B7FnztNO.js +0 -7
- package/dist/assets/requirementDiagram-Z7DCOOCP-Bl_BM2Th.js +0 -73
- package/dist/assets/sequenceDiagram-2WXFIKYE-VEuJDwyJ.js +0 -145
- package/dist/assets/stateDiagram-v2-FVOUBMTO-C85ucl39.js +0 -1
- package/dist/assets/timeline-definition-YZTLITO2-BPGKhi7f.js +0 -61
- package/dist/assets/vendor-codemirror-CyOKkaQZ.js +0 -31
- package/dist/assets/vendor-react-CP4yFTs7.js +0 -8
- package/dist/assets/vendor-xterm-DfcmCpbH.js +0 -66
- package/dist/assets/xychartDiagram-JWTSCODW-CbBk50-O.js +0 -7
- package/server/_legacy-providers/README.md +0 -30
- package/server/_legacy-providers/claude-sdk.js +0 -956
- package/server/_legacy-providers/gemini-cli.js +0 -368
- package/server/_legacy-providers/openai-codex.js +0 -705
- package/server/_legacy-providers/opencode-cli.js +0 -674
- package/server/acp-runtime/client.test.js +0 -688
- package/server/acp-runtime/session-store.test.js +0 -89
- package/server/cli.test.js +0 -76
- package/server/external-agent/service.test.js +0 -53
- package/server/external-agent/ws.test.js +0 -289
- package/shared/conversationEvents.test.js +0 -403
|
@@ -2,7 +2,6 @@ import fs from 'fs/promises';
|
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import { spawn } from 'child_process';
|
|
6
5
|
import { Readable, Writable } from 'stream';
|
|
7
6
|
|
|
8
7
|
import {
|
|
@@ -13,9 +12,12 @@ import {
|
|
|
13
12
|
|
|
14
13
|
import {
|
|
15
14
|
CONVERSATION_EVENT_KINDS,
|
|
16
|
-
createConversationEvent
|
|
15
|
+
createConversationEvent,
|
|
16
|
+
stripAssistantProtocolTags
|
|
17
17
|
} from '../../shared/conversationEvents.js';
|
|
18
18
|
import { parseDataUrl } from '../utils/agentImages.js';
|
|
19
|
+
import { spawnCommand } from '../utils/spawnCommand.js';
|
|
20
|
+
import { resolveCommandPath } from '../utils/resolveCommandPath.js';
|
|
19
21
|
import { resolveAgentCommand } from './registry.js';
|
|
20
22
|
|
|
21
23
|
const DEFAULT_TERMINAL_OUTPUT_LIMIT = 256 * 1024;
|
|
@@ -672,7 +674,7 @@ async function resolveGeminiCommand(commandLine) {
|
|
|
672
674
|
try {
|
|
673
675
|
const versionOutput = await new Promise((resolve, reject) => {
|
|
674
676
|
let stdout = '';
|
|
675
|
-
const childProcess =
|
|
677
|
+
const childProcess = spawnCommand(parsed.command, ['--version'], {
|
|
676
678
|
stdio: ['ignore', 'pipe', 'ignore']
|
|
677
679
|
});
|
|
678
680
|
|
|
@@ -703,17 +705,41 @@ async function resolveGeminiCommand(commandLine) {
|
|
|
703
705
|
}
|
|
704
706
|
}
|
|
705
707
|
|
|
706
|
-
async function
|
|
708
|
+
async function resolveNpxFallbackCommand(commandLine, agentKey) {
|
|
709
|
+
const parsed = splitCommandLine(commandLine);
|
|
710
|
+
if (parsed.command !== 'npx') {
|
|
711
|
+
return commandLine;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const npxCheck = await resolveCommandPath('npx');
|
|
715
|
+
if (npxCheck.found) {
|
|
716
|
+
return commandLine;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
const npmCheck = await resolveCommandPath('npm');
|
|
720
|
+
if (npmCheck.found) {
|
|
721
|
+
return ['npm', 'exec', '--yes', '--', ...parsed.args].join(' ');
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
throw new Error(
|
|
725
|
+
`Unable to launch ${agentKey} ACP adapter because neither npx nor npm is available in PATH.`
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
export async function resolveLaunchCommand(agentKey, overrides = {}) {
|
|
707
730
|
const commandLine = resolveAgentCommand(agentKey, overrides);
|
|
708
731
|
if (!commandLine) {
|
|
709
732
|
throw new Error(`Unsupported ACP agent: ${agentKey}`);
|
|
710
733
|
}
|
|
711
734
|
|
|
712
|
-
|
|
713
|
-
|
|
735
|
+
const normalizedAgentKey = String(agentKey || '').trim().toLowerCase();
|
|
736
|
+
const resolvedCommandLine = await resolveNpxFallbackCommand(commandLine, normalizedAgentKey || 'unknown');
|
|
737
|
+
|
|
738
|
+
if (normalizedAgentKey === 'gemini') {
|
|
739
|
+
return resolveGeminiCommand(resolvedCommandLine);
|
|
714
740
|
}
|
|
715
741
|
|
|
716
|
-
return
|
|
742
|
+
return resolvedCommandLine;
|
|
717
743
|
}
|
|
718
744
|
|
|
719
745
|
function buildPromptBlocks(promptText, attachments = {}) {
|
|
@@ -786,7 +812,7 @@ class LocalTerminalProcess {
|
|
|
786
812
|
}, {})
|
|
787
813
|
: {};
|
|
788
814
|
|
|
789
|
-
this.child =
|
|
815
|
+
this.child = spawnCommand(this.command, this.args, {
|
|
790
816
|
cwd: this.cwd,
|
|
791
817
|
env: sanitizeProcessEnv(process.env, envEntries),
|
|
792
818
|
stdio: ['ignore', 'pipe', 'pipe']
|
|
@@ -881,6 +907,7 @@ export class AcpClient {
|
|
|
881
907
|
this.isPromptInFlight = false;
|
|
882
908
|
this.pendingPromptDiagnostic = null;
|
|
883
909
|
this.hasReportedPromptFatalError = false;
|
|
910
|
+
this.agentDiagnosticBuffer = '';
|
|
884
911
|
this.streamState = {
|
|
885
912
|
turnId: null,
|
|
886
913
|
assistantSegmentIndex: 0,
|
|
@@ -899,6 +926,7 @@ export class AcpClient {
|
|
|
899
926
|
this.writer.send({
|
|
900
927
|
provider: this.agentKey,
|
|
901
928
|
sessionId: this.sessionId,
|
|
929
|
+
projectPath: this.projectPath,
|
|
902
930
|
runtime: 'acp',
|
|
903
931
|
timestamp: nowIso(),
|
|
904
932
|
...payload
|
|
@@ -1001,7 +1029,19 @@ export class AcpClient {
|
|
|
1001
1029
|
}
|
|
1002
1030
|
|
|
1003
1031
|
handleAgentDiagnostic(text) {
|
|
1004
|
-
const
|
|
1032
|
+
const diagnosticText = String(text || '').trim();
|
|
1033
|
+
if (!diagnosticText) {
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
const nextBuffer = this.agentDiagnosticBuffer
|
|
1038
|
+
? `${this.agentDiagnosticBuffer}\n${diagnosticText}`
|
|
1039
|
+
: diagnosticText;
|
|
1040
|
+
this.agentDiagnosticBuffer = nextBuffer.length > 8192
|
|
1041
|
+
? nextBuffer.slice(-8192)
|
|
1042
|
+
: nextBuffer;
|
|
1043
|
+
|
|
1044
|
+
const fatalError = detectFatalAgentDiagnostic(this.agentKey, this.agentDiagnosticBuffer);
|
|
1005
1045
|
if (!fatalError || !this.isPromptInFlight) {
|
|
1006
1046
|
return;
|
|
1007
1047
|
}
|
|
@@ -1210,6 +1250,11 @@ export class AcpClient {
|
|
|
1210
1250
|
|
|
1211
1251
|
if (update.sessionUpdate === 'agent_message_chunk') {
|
|
1212
1252
|
if (update.content?.type === 'text' && typeof update.content.text === 'string') {
|
|
1253
|
+
const cleanText = stripAssistantProtocolTags(update.content.text);
|
|
1254
|
+
if (!cleanText) {
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1213
1258
|
const messageId = this.streamState.assistantMessageId
|
|
1214
1259
|
|| this.createAssistantMessageId('assistant_text');
|
|
1215
1260
|
|
|
@@ -1230,7 +1275,7 @@ export class AcpClient {
|
|
|
1230
1275
|
CONVERSATION_EVENT_KINDS.ASSISTANT_TEXT_DELTA,
|
|
1231
1276
|
{
|
|
1232
1277
|
messageId,
|
|
1233
|
-
text:
|
|
1278
|
+
text: cleanText
|
|
1234
1279
|
},
|
|
1235
1280
|
{
|
|
1236
1281
|
timestamp,
|
|
@@ -1442,7 +1487,7 @@ export class AcpClient {
|
|
|
1442
1487
|
const spawnEnvironment = await prepareSpawnEnvironment(this.agentKey);
|
|
1443
1488
|
this.spawnCleanup = spawnEnvironment.cleanup;
|
|
1444
1489
|
|
|
1445
|
-
this.childProcess =
|
|
1490
|
+
this.childProcess = spawnCommand(command, args, {
|
|
1446
1491
|
cwd: this.projectPath,
|
|
1447
1492
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1448
1493
|
windowsHide: true,
|
|
@@ -1603,16 +1648,44 @@ export class AcpClient {
|
|
|
1603
1648
|
}
|
|
1604
1649
|
|
|
1605
1650
|
async setModel(modelId) {
|
|
1606
|
-
if (!modelId) {
|
|
1651
|
+
if (!modelId || !this.sessionId || !this.connection) {
|
|
1607
1652
|
return;
|
|
1608
1653
|
}
|
|
1609
1654
|
|
|
1655
|
+
let lastError = null;
|
|
1656
|
+
|
|
1610
1657
|
try {
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1658
|
+
if (typeof this.connection.setSessionConfigOption === 'function') {
|
|
1659
|
+
try {
|
|
1660
|
+
await this.connection.setSessionConfigOption({
|
|
1661
|
+
sessionId: this.sessionId,
|
|
1662
|
+
configId: 'model',
|
|
1663
|
+
value: modelId
|
|
1664
|
+
});
|
|
1665
|
+
return;
|
|
1666
|
+
} catch (error) {
|
|
1667
|
+
lastError = error;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
if (typeof this.connection.unstable_setSessionModel === 'function') {
|
|
1672
|
+
try {
|
|
1673
|
+
await this.connection.unstable_setSessionModel({
|
|
1674
|
+
sessionId: this.sessionId,
|
|
1675
|
+
modelId
|
|
1676
|
+
});
|
|
1677
|
+
return;
|
|
1678
|
+
} catch (error) {
|
|
1679
|
+
lastError = error;
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
} catch (error) {
|
|
1683
|
+
lastError = error;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
if (lastError) {
|
|
1687
|
+
console.warn(`[ACP:${this.agentKey}] Failed to set model "${modelId}": ${lastError.message}`);
|
|
1688
|
+
}
|
|
1616
1689
|
}
|
|
1617
1690
|
|
|
1618
1691
|
async setMode(modeId) {
|
|
@@ -1631,6 +1704,7 @@ export class AcpClient {
|
|
|
1631
1704
|
async sendPrompt(promptText, attachments = {}) {
|
|
1632
1705
|
this.resetTurnState();
|
|
1633
1706
|
this.hasReportedPromptFatalError = false;
|
|
1707
|
+
this.agentDiagnosticBuffer = '';
|
|
1634
1708
|
const promptPayload = buildPromptBlocks(promptText, attachments);
|
|
1635
1709
|
const clientRequestId = typeof attachments?.clientRequestId === 'string' && attachments.clientRequestId.trim()
|
|
1636
1710
|
? attachments.clientRequestId.trim()
|
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
import { resolveWorkingDirectory } from '../utils/defaultWorkingDirectory.js';
|
|
2
|
-
import {
|
|
3
|
-
CLAUDE_MODELS,
|
|
4
|
-
CODEX_MODELS,
|
|
5
|
-
GEMINI_MODELS,
|
|
6
|
-
OPENCODE_MODELS
|
|
7
|
-
} from '../../shared/modelConstants.js';
|
|
8
2
|
import { AcpClient } from './client.js';
|
|
9
3
|
import {
|
|
10
4
|
findAcpSessionRecord,
|
|
@@ -54,16 +48,11 @@ function registerActiveClient(provider, sessionId, client) {
|
|
|
54
48
|
return entry;
|
|
55
49
|
}
|
|
56
50
|
|
|
57
|
-
function resolveDefaultModel(agentKey, requestedModel) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (agentKey === 'claude') return CLAUDE_MODELS.DEFAULT;
|
|
63
|
-
if (agentKey === 'codex') return CODEX_MODELS.DEFAULT;
|
|
64
|
-
if (agentKey === 'gemini') return GEMINI_MODELS.DEFAULT;
|
|
65
|
-
if (agentKey === 'opencode') return OPENCODE_MODELS.DEFAULT;
|
|
66
|
-
return null;
|
|
51
|
+
export function resolveDefaultModel(agentKey, requestedModel) {
|
|
52
|
+
const normalizedRequestedModel = typeof requestedModel === 'string'
|
|
53
|
+
? requestedModel.trim()
|
|
54
|
+
: '';
|
|
55
|
+
return normalizedRequestedModel || null;
|
|
67
56
|
}
|
|
68
57
|
|
|
69
58
|
function unregisterActiveClient(provider, sessionId, client = null) {
|
|
@@ -7,9 +7,6 @@ function parsePositiveInteger(value, fallback) {
|
|
|
7
7
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const ACP_SESSION_ROOT = process.env.AXHUB_GENIE_ACP_SESSION_ROOT
|
|
11
|
-
? path.resolve(process.env.AXHUB_GENIE_ACP_SESSION_ROOT)
|
|
12
|
-
: path.join(os.homedir(), '.axhub-genie', 'acp-sessions');
|
|
13
10
|
const DEFAULT_SESSION_GC_MAX_AGE_DAYS = parsePositiveInteger(process.env.ACP_SESSION_GC_MAX_AGE_DAYS, 30);
|
|
14
11
|
|
|
15
12
|
function normalizeProvider(value) {
|
|
@@ -22,7 +19,10 @@ function normalizeSessionId(value) {
|
|
|
22
19
|
}
|
|
23
20
|
|
|
24
21
|
function getProviderDir(provider) {
|
|
25
|
-
|
|
22
|
+
const sessionRoot = process.env.AXHUB_GENIE_ACP_SESSION_ROOT
|
|
23
|
+
? path.resolve(process.env.AXHUB_GENIE_ACP_SESSION_ROOT)
|
|
24
|
+
: path.join(os.homedir(), '.axhub-genie', 'acp-sessions');
|
|
25
|
+
return path.join(sessionRoot, normalizeProvider(provider));
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function getSessionFilePath(provider, sessionId) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { CODEX_MODELS, GEMINI_MODELS, OPENCODE_MODELS } from '../../../shared/modelConstants.js';
|
|
2
1
|
import { executeAgentPrompt } from '../../acp-runtime/index.js';
|
|
3
2
|
|
|
4
3
|
function normalizeBackend(backend) {
|
|
@@ -9,13 +8,6 @@ function normalizeBackend(backend) {
|
|
|
9
8
|
return 'codex';
|
|
10
9
|
}
|
|
11
10
|
|
|
12
|
-
function getDefaultModel(backend) {
|
|
13
|
-
if (backend === 'codex') return CODEX_MODELS.DEFAULT;
|
|
14
|
-
if (backend === 'gemini') return GEMINI_MODELS.DEFAULT;
|
|
15
|
-
if (backend === 'opencode') return OPENCODE_MODELS.DEFAULT;
|
|
16
|
-
return undefined;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
11
|
function createWriter(callbacks) {
|
|
20
12
|
const state = {
|
|
21
13
|
sessionId: null,
|
|
@@ -96,7 +88,6 @@ export async function runBackendSession({
|
|
|
96
88
|
onError,
|
|
97
89
|
}) {
|
|
98
90
|
const resolvedBackend = normalizeBackend(backend);
|
|
99
|
-
const resolvedModel = model || getDefaultModel(resolvedBackend);
|
|
100
91
|
|
|
101
92
|
const writer = createWriter({
|
|
102
93
|
onSessionId,
|
|
@@ -108,7 +99,7 @@ export async function runBackendSession({
|
|
|
108
99
|
projectPath,
|
|
109
100
|
cwd: projectPath,
|
|
110
101
|
sessionId: sessionId || undefined,
|
|
111
|
-
model:
|
|
102
|
+
model: model || undefined,
|
|
112
103
|
permissionMode: 'bypassPermissions',
|
|
113
104
|
resume: !!sessionId,
|
|
114
105
|
skipPermissions: true,
|
package/server/claude-sdk.js
CHANGED
|
@@ -5,15 +5,13 @@ import {
|
|
|
5
5
|
isAgentSessionActive,
|
|
6
6
|
resolveAgentPermission
|
|
7
7
|
} from './acp-runtime/index.js';
|
|
8
|
-
import { CLAUDE_MODELS } from '../shared/modelConstants.js';
|
|
9
8
|
|
|
10
9
|
export async function queryClaudeSDK(command, options = {}, writer) {
|
|
11
10
|
return executeAgentPrompt({
|
|
12
11
|
agentKey: 'claude',
|
|
13
12
|
command,
|
|
14
13
|
options: {
|
|
15
|
-
...options
|
|
16
|
-
model: options.model || CLAUDE_MODELS.DEFAULT
|
|
14
|
+
...options
|
|
17
15
|
},
|
|
18
16
|
writer
|
|
19
17
|
});
|
package/server/cli.js
CHANGED
|
@@ -24,6 +24,10 @@ import {
|
|
|
24
24
|
DEFAULT_WORKING_DIRECTORY_ENV,
|
|
25
25
|
getConfiguredDefaultProjectPath,
|
|
26
26
|
} from './utils/defaultWorkingDirectory.js';
|
|
27
|
+
import {
|
|
28
|
+
getCcConnectConnectionSummary,
|
|
29
|
+
updateCcConnectPlatformBinding,
|
|
30
|
+
} from './utils/ccConnectManager.js';
|
|
27
31
|
|
|
28
32
|
const __filename = fileURLToPath(import.meta.url);
|
|
29
33
|
const __dirname = dirname(__filename);
|
|
@@ -374,6 +378,27 @@ function buildEditorErrorResponse({ requestId, channel = null, targetClientId =
|
|
|
374
378
|
};
|
|
375
379
|
}
|
|
376
380
|
|
|
381
|
+
function buildCcConnectSuccessResponse({ command, platform = null, data = {} }) {
|
|
382
|
+
return {
|
|
383
|
+
ok: true,
|
|
384
|
+
command,
|
|
385
|
+
platform,
|
|
386
|
+
data,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function buildCcConnectErrorResponse({ command, platform = null, code, message }) {
|
|
391
|
+
return {
|
|
392
|
+
ok: false,
|
|
393
|
+
command,
|
|
394
|
+
platform,
|
|
395
|
+
error: {
|
|
396
|
+
code,
|
|
397
|
+
message,
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
377
402
|
function printJson(payload) {
|
|
378
403
|
console.log(JSON.stringify(payload, null, 2));
|
|
379
404
|
}
|
|
@@ -453,6 +478,27 @@ async function sendEditorWebSocketRequest({ apiBaseUrl, apiKey, message, timeout
|
|
|
453
478
|
});
|
|
454
479
|
}
|
|
455
480
|
|
|
481
|
+
const RETRYABLE_ERROR_CODES = new Set(['CONNECTION_ERROR', 'CONNECTION_CLOSED', 'REQUEST_TIMEOUT']);
|
|
482
|
+
const CLI_RETRY_DELAY_MS = 1000;
|
|
483
|
+
const CLI_MAX_RETRIES = 1;
|
|
484
|
+
|
|
485
|
+
async function sendEditorWebSocketRequestWithRetry(options) {
|
|
486
|
+
let lastError = null;
|
|
487
|
+
for (let attempt = 0; attempt <= CLI_MAX_RETRIES; attempt++) {
|
|
488
|
+
try {
|
|
489
|
+
return await sendEditorWebSocketRequest(options);
|
|
490
|
+
} catch (error) {
|
|
491
|
+
lastError = error;
|
|
492
|
+
if (attempt < CLI_MAX_RETRIES && RETRYABLE_ERROR_CODES.has(error?.code)) {
|
|
493
|
+
await new Promise((resolve) => setTimeout(resolve, CLI_RETRY_DELAY_MS));
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
throw error;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
throw lastError;
|
|
500
|
+
}
|
|
501
|
+
|
|
456
502
|
function resolveOutputDirPath(outputDir) {
|
|
457
503
|
return path.resolve(outputDir || process.cwd());
|
|
458
504
|
}
|
|
@@ -603,7 +649,7 @@ async function runEditorCommand(positionals, options) {
|
|
|
603
649
|
const timeoutMs = parsePositiveInteger(options.timeoutMs || DEFAULT_EDITOR_TIMEOUT_MS, '--timeout-ms') || DEFAULT_EDITOR_TIMEOUT_MS;
|
|
604
650
|
|
|
605
651
|
try {
|
|
606
|
-
const response = await
|
|
652
|
+
const response = await sendEditorWebSocketRequestWithRetry({
|
|
607
653
|
apiBaseUrl,
|
|
608
654
|
apiKey: options.apiKey,
|
|
609
655
|
message: editorRequest.message,
|
|
@@ -627,6 +673,96 @@ async function runEditorCommand(positionals, options) {
|
|
|
627
673
|
}
|
|
628
674
|
}
|
|
629
675
|
|
|
676
|
+
function buildCcConnectCommand(positionals, options) {
|
|
677
|
+
const commandPath = positionals.join(' ');
|
|
678
|
+
const requestedPlatform = typeof options.platform === 'string' ? options.platform.trim() : '';
|
|
679
|
+
|
|
680
|
+
if (commandPath === 'cc-connect' || commandPath === 'cc-connect status') {
|
|
681
|
+
return {
|
|
682
|
+
command: 'cc-connect status',
|
|
683
|
+
action: 'status',
|
|
684
|
+
platform: requestedPlatform || null,
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (commandPath === 'cc-connect set') {
|
|
689
|
+
const platform = requireOption(options, 'platform', '--platform is required');
|
|
690
|
+
const provider = typeof options.provider === 'string' && options.provider.trim()
|
|
691
|
+
? options.provider.trim()
|
|
692
|
+
: null;
|
|
693
|
+
const projectPath = typeof options.projectPath === 'string' && options.projectPath.trim()
|
|
694
|
+
? path.resolve(options.projectPath)
|
|
695
|
+
: null;
|
|
696
|
+
|
|
697
|
+
if (!provider && !projectPath) {
|
|
698
|
+
throw new Error('At least one of --provider or --project-path is required.');
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
return {
|
|
702
|
+
command: 'cc-connect set',
|
|
703
|
+
action: 'set',
|
|
704
|
+
platform,
|
|
705
|
+
provider,
|
|
706
|
+
projectPath,
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
throw new Error(`Unknown cc-connect command: ${commandPath}`);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
async function runCcConnectCommand(positionals, options) {
|
|
714
|
+
const command = buildCcConnectCommand(positionals, options);
|
|
715
|
+
|
|
716
|
+
try {
|
|
717
|
+
if (command.action === 'status') {
|
|
718
|
+
const summary = await getCcConnectConnectionSummary(command.platform);
|
|
719
|
+
const data = command.platform
|
|
720
|
+
? {
|
|
721
|
+
ccConnect: summary.ccConnect,
|
|
722
|
+
providers: summary.providers,
|
|
723
|
+
platform: summary.platform,
|
|
724
|
+
}
|
|
725
|
+
: {
|
|
726
|
+
ccConnect: summary.ccConnect,
|
|
727
|
+
providers: summary.providers,
|
|
728
|
+
platforms: summary.platforms,
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
printJson(buildCcConnectSuccessResponse({
|
|
732
|
+
command: command.command,
|
|
733
|
+
platform: command.platform,
|
|
734
|
+
data,
|
|
735
|
+
}));
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
if (command.action === 'set') {
|
|
740
|
+
const result = await updateCcConnectPlatformBinding({
|
|
741
|
+
platformId: command.platform,
|
|
742
|
+
provider: command.provider === null ? undefined : command.provider,
|
|
743
|
+
projectPath: command.projectPath === null ? undefined : command.projectPath,
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
printJson(buildCcConnectSuccessResponse({
|
|
747
|
+
command: command.command,
|
|
748
|
+
platform: result.platform,
|
|
749
|
+
data: result,
|
|
750
|
+
}));
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
throw new Error(`Unsupported cc-connect action: ${command.action}`);
|
|
755
|
+
} catch (error) {
|
|
756
|
+
printJson(buildCcConnectErrorResponse({
|
|
757
|
+
command: command.command,
|
|
758
|
+
platform: command.platform || null,
|
|
759
|
+
code: error.code || 'CC_CONNECT_COMMAND_FAILED',
|
|
760
|
+
message: error.message,
|
|
761
|
+
}));
|
|
762
|
+
process.exit(1);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
630
766
|
// Show status command
|
|
631
767
|
function showStatus(options = {}) {
|
|
632
768
|
const runtimeStatus = getRuntimeStatus();
|
|
@@ -754,6 +890,7 @@ Commands:
|
|
|
754
890
|
start Start the Axhub Genie server (default)
|
|
755
891
|
stop Stop the running Axhub Genie server
|
|
756
892
|
status Show configuration and data locations
|
|
893
|
+
cc-connect Inspect or update platform connection bindings
|
|
757
894
|
editor Query or control a connected web editor frontend
|
|
758
895
|
update Update to the latest version
|
|
759
896
|
help Show this help information
|
|
@@ -769,12 +906,15 @@ Options:
|
|
|
769
906
|
--json Output JSON (status or editor commands)
|
|
770
907
|
--api-base <url> Override API base URL for editor commands
|
|
771
908
|
--api-key <key> API key for /api/agent/ws editor commands
|
|
909
|
+
--platform <id> Target platform for cc-connect commands
|
|
910
|
+
--provider <id> Provider for cc-connect updates or editor task references
|
|
772
911
|
--channel <name> Integration channel for editor commands
|
|
773
912
|
--target-client-id <id> Target frontend client ID for editor commands
|
|
774
913
|
--client-id <id> Optional client filter for editor clients list
|
|
914
|
+
--project-path <path> Project path for cc-connect platform binding updates
|
|
775
915
|
--element-key <key> Target element key for editor node commands
|
|
776
916
|
--status <values> Comma-separated status filters for editor nodes list
|
|
777
|
-
--state <editing|idle>
|
|
917
|
+
--state <editing|idle|completed|error> Target editing state for editor editing set
|
|
778
918
|
--limit <n> Maximum number of nodes returned by editor nodes list
|
|
779
919
|
--output-dir <path> Download directory for screenshot/image export commands
|
|
780
920
|
--timeout-ms <ms> Timeout for editor WebSocket requests (default: ${DEFAULT_EDITOR_TIMEOUT_MS})
|
|
@@ -790,6 +930,9 @@ Examples:
|
|
|
790
930
|
$ axhub-genie stop # Stop running server
|
|
791
931
|
$ axhub-genie status # Show configuration
|
|
792
932
|
$ axhub-genie status --json # Get machine-readable status
|
|
933
|
+
$ axhub-genie cc-connect status
|
|
934
|
+
$ axhub-genie cc-connect set --platform weixin --provider codex
|
|
935
|
+
$ axhub-genie cc-connect set --platform feishu --project-path /path/to/repo
|
|
793
936
|
$ axhub-genie editor clients list --channel project-a
|
|
794
937
|
$ axhub-genie editor snapshot --channel project-a --target-client-id figma-123
|
|
795
938
|
$ axhub-genie editor nodes list --channel project-a --target-client-id figma-123 --status pending-dispatch,dirty
|
|
@@ -940,10 +1083,18 @@ function parseArgs(args) {
|
|
|
940
1083
|
parsed.options.apiKey = args[++i];
|
|
941
1084
|
} else if (arg.startsWith('--api-key=')) {
|
|
942
1085
|
parsed.options.apiKey = arg.split('=')[1];
|
|
1086
|
+
} else if (arg === '--platform') {
|
|
1087
|
+
parsed.options.platform = args[++i];
|
|
1088
|
+
} else if (arg.startsWith('--platform=')) {
|
|
1089
|
+
parsed.options.platform = arg.split('=')[1];
|
|
943
1090
|
} else if (arg === '--channel') {
|
|
944
1091
|
parsed.options.channel = args[++i];
|
|
945
1092
|
} else if (arg.startsWith('--channel=')) {
|
|
946
1093
|
parsed.options.channel = arg.split('=')[1];
|
|
1094
|
+
} else if (arg === '--project-path') {
|
|
1095
|
+
parsed.options.projectPath = args[++i];
|
|
1096
|
+
} else if (arg.startsWith('--project-path=')) {
|
|
1097
|
+
parsed.options.projectPath = arg.split('=')[1];
|
|
947
1098
|
} else if (arg === '--target-client-id') {
|
|
948
1099
|
parsed.options.targetClientId = args[++i];
|
|
949
1100
|
} else if (arg.startsWith('--target-client-id=')) {
|
|
@@ -1041,6 +1192,9 @@ async function main() {
|
|
|
1041
1192
|
case 'editor':
|
|
1042
1193
|
await runEditorCommand(positionals, options);
|
|
1043
1194
|
break;
|
|
1195
|
+
case 'cc-connect':
|
|
1196
|
+
await runCcConnectCommand(positionals, options);
|
|
1197
|
+
break;
|
|
1044
1198
|
case 'status':
|
|
1045
1199
|
case 'info':
|
|
1046
1200
|
showStatus(options);
|
|
@@ -1078,6 +1232,9 @@ if (isDirectExecution) {
|
|
|
1078
1232
|
}
|
|
1079
1233
|
|
|
1080
1234
|
export {
|
|
1235
|
+
buildCcConnectCommand,
|
|
1236
|
+
buildCcConnectErrorResponse,
|
|
1237
|
+
buildCcConnectSuccessResponse,
|
|
1081
1238
|
buildEditorRequest,
|
|
1082
1239
|
buildEditorSuccessResponse,
|
|
1083
1240
|
buildEditorErrorResponse,
|
|
@@ -62,15 +62,21 @@ async function ensureProviderInstalled(provider) {
|
|
|
62
62
|
throw createRequestError(messageParts.join(' '), 400);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
export function buildSessionNavigation(
|
|
65
|
+
export function buildSessionNavigation({
|
|
66
|
+
provider,
|
|
67
|
+
sessionId
|
|
68
|
+
} = {}) {
|
|
69
|
+
const normalizedProvider = typeof provider === 'string' && provider.trim() ? provider.trim().toLowerCase() : null;
|
|
66
70
|
const normalizedSessionId = typeof sessionId === 'string' && sessionId.trim() ? sessionId.trim() : null;
|
|
67
|
-
const sessionPath =
|
|
71
|
+
const sessionPath = normalizedProvider && normalizedSessionId
|
|
72
|
+
? `/session/${normalizedProvider}/${encodeURIComponent(normalizedSessionId)}`
|
|
73
|
+
: null;
|
|
68
74
|
const frontendPort = process.env.VITE_PORT || '5173';
|
|
69
75
|
const configuredFrontendUrl = typeof process.env.FRONTEND_URL === 'string'
|
|
70
76
|
? process.env.FRONTEND_URL.trim().replace(/\/+$/, '')
|
|
71
77
|
: '';
|
|
72
78
|
const frontendBaseUrl = configuredFrontendUrl || `http://localhost:${frontendPort}`;
|
|
73
|
-
const sessionUrl =
|
|
79
|
+
const sessionUrl = sessionPath ? `${frontendBaseUrl}${sessionPath}` : null;
|
|
74
80
|
|
|
75
81
|
return {
|
|
76
82
|
sessionPath,
|
|
@@ -471,7 +477,11 @@ export async function runExternalAgentRequest({
|
|
|
471
477
|
openOnly: true,
|
|
472
478
|
runtime: 'acp',
|
|
473
479
|
sessionId: normalized.normalizedSessionId,
|
|
474
|
-
...buildSessionNavigation(
|
|
480
|
+
...buildSessionNavigation({
|
|
481
|
+
provider: normalized.provider,
|
|
482
|
+
sessionId: normalized.normalizedSessionId,
|
|
483
|
+
projectPath: normalized.projectPath
|
|
484
|
+
}),
|
|
475
485
|
isResumed: true,
|
|
476
486
|
message: 'Session link generated. No model call triggered.'
|
|
477
487
|
};
|
|
@@ -534,7 +544,11 @@ export async function runExternalAgentRequest({
|
|
|
534
544
|
throw new AgentSessionAbortedError();
|
|
535
545
|
}
|
|
536
546
|
|
|
537
|
-
const navigation = buildSessionNavigation(
|
|
547
|
+
const navigation = buildSessionNavigation({
|
|
548
|
+
provider: normalized.provider,
|
|
549
|
+
sessionId: callbackSessionId,
|
|
550
|
+
projectPath: finalProjectPath
|
|
551
|
+
});
|
|
538
552
|
const response = {
|
|
539
553
|
success: true,
|
|
540
554
|
sessionId: callbackSessionId,
|
|
@@ -580,7 +594,11 @@ export async function runExternalAgentRequest({
|
|
|
580
594
|
} catch (error) {
|
|
581
595
|
callbackSessionId = writer.getSessionId() || callbackCaptureWriter.getSessionId() || normalized.normalizedSessionId;
|
|
582
596
|
callbackResult = {
|
|
583
|
-
...buildSessionNavigation(
|
|
597
|
+
...buildSessionNavigation({
|
|
598
|
+
provider: normalized.provider,
|
|
599
|
+
sessionId: callbackSessionId,
|
|
600
|
+
projectPath: finalProjectPath
|
|
601
|
+
}),
|
|
584
602
|
messages: callbackCaptureWriter.getAssistantMessages(),
|
|
585
603
|
tokens: callbackCaptureWriter.getTotalTokens()
|
|
586
604
|
};
|