chainlesschain 0.162.32 → 0.162.34
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/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-Cg_uWAVl.js → AIOps-BYfi9NYS.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DSFtQ1c2.js → ActionButton-BiS_tAN7.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BMxpkw8y.js → Analytics-jiWl_p-B.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-tgVxlmsx.js → AppLayout-m4sIzDot.js} +3 -3
- package/src/assets/web-panel/assets/{Audit-DwzGllcp.js → Audit-CPla3Erm.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BG28Y2MV.js → Backup-BGeQzTaB.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-TXthbazl.js → BaseInput-DTf7Z1iU.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-D096SxaD.js → Chat-DPTlQlD-.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BgRXce4e.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-Czttw1JS.js → Checkbox-DY-XuQMu.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DZtMgv4q.js → Codegen-B6oxPiZI.js} +1 -1
- package/src/assets/web-panel/assets/{Col-D3DnfExY.js → Col-Dqxb4wSE.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Bj5AdwqY.js → Community-DCIX514p.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BQ8Zszub.js → Compact-BGtCzDoJ.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DXacb34n.js → Compliance-zcOYd55o.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BgMUBTkw.js → Cowork-DVTtdIdM.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-fqBWOqlN.js → Cron-CPUaR69k.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-E4oa1MWy.js → Crosschain-DnjUS6QH.js} +1 -1
- package/src/assets/web-panel/assets/{DID-pwgfYZaV.js → DID-Dnz8VDmx.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-n8mdLFIR.js → Dashboard-CtWf27j7.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown--6DYqxk7.js → Dropdown-B4GC1ZV4.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CkjQluz3.js → EmailListRenderer-wjij3kzr.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-u-QTQ-OC.js → FamilyGuardDashboard-rS-2W4u5.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D219M5Qc.js → Federation-90p5Tnoz.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BBU_aopC.js → FormItemContext-Cnrw7gzq.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-pTMCIHcM.js → GenericCardRenderer-C85NsWa3.js} +1 -1
- package/src/assets/web-panel/assets/{Git-ClcCARWt.js → Git-BFAVM9F8.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CvUi3I93.js → Governance-DBoRonpq.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DT-a4pVg.js → Inference-DHRyD66j.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DHMs2LY8.js → KnowledgeGraph-CTvUKecD.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-D2s4eV1N.js → Logs-CB0dv_Ts.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-YC5-fx-6.js → Marketplace-CN7Hm5Uw.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-7JHTEC4T.js → McpTools-q5H25_8L.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BudotVLD.js → Memory-BCV3pZ1d.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CAiRyLVU.js → MobileBridge-C04Mngt4.js} +2 -2
- package/src/assets/web-panel/assets/MobileProjects-CUxONYre.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-d0iY0CeK.js → Mtc-ByAMz2DN.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-aI2cG1UP.js → MtcAudit-B7V7byJq.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-4bF70khG.js → Multisig-DtKmcVQV.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CwLib1S7.js → NLProgramming-CaMbT5SC.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Wt7AuFRU.js → Notes-DRjbSTCU.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-D081vV_7.js → NotificationSettings-B9YbJID5.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DCPei1L9.js → OrderTableRenderer-BcI_-vGS.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BNEsUNdP.js → Organization-oTask4BE.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-B_1iUXDD.js → Overflow-Bab06ey7.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Dbc-kNwJ.js → P2P--wlBeU0N.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-D8Xh289k.js → PdhVaultBrowser-D4t77Pwc.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-C77mM6-n.js → Permissions-B3sf6CJ3.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Dj0J3r_K.js → PersonalDataHub-BXOojk63.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-B6F0WQ2C.js → Pipeline-DReqtBFN.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-eDKOkyyq.js → Privacy-cT1GwKLx.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DAWwhr5_.js → ProjectInit-BhTAzVhH.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DwdK8k6I.js → ProjectSettings-CK-D8Fyj.js} +2 -2
- package/src/assets/web-panel/assets/Projects-CbHiwen6.js +1 -0
- package/src/assets/web-panel/assets/{Providers--DcYxQfN.js → Providers-B-ftiXa8.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DU268niT.js → QuickAsk-CT5XPwTF.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-ChnflhV1.js → Recommend-CohhlBZ_.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DSsY3bQG.js → Reputation-CrgbixFz.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Zb-EjmgQ.js → Row-ClExmBn3.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CGLiixZB.js → RssFeed-VV0qizCJ.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Dhr_po-U.js → Search-CqJapSiL.js} +1 -1
- package/src/assets/web-panel/assets/{Security-GMYNhGsR.js → Security-DY66Zie6.js} +2 -2
- package/src/assets/web-panel/assets/{Services-DiOpnVY0.js → Services-RQwxat7-.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DG3ez6ME.js → Skeleton-0v37UTU_.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DZGptytP.js → Skills-B4Vm4DxN.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CtGpE3xA.js → Sla-CggphTlo.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DQFw6Cf9.js → SpeechSettings-BAOU08C7.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-C8X78RpX.js → SyncSettings-DmtC4J1w.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-CExqxzL6.js +1 -0
- package/src/assets/web-panel/assets/{Templates-SF9_ZWsV.js → Templates-C1QK0YoU.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BbIQSVZz.js → Tenant-CieOfmqp.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DKr5zDwu.js → Terminal-DWdhrxRq.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BtLaNaWr.js → TimelineRenderer-CjFVUUDU.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CfYbk2NG.js → Tokens-Bwbk3id9.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BLX_XDP0.js → Trigger-uJle_yj4.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BWxUv9PR.js → Trust-BcOuxAA5.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DRwTyQD4.js → UkeySign-DUu7Ufg6.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BsC4VOSo.js → VideoEditing-Ck8JtQ2n.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CSsO1NJU.js → Wallet-B3jw43on.js} +2 -2
- package/src/assets/web-panel/assets/{WebAuthn-z1MxiFzS.js → WebAuthn-Baf9K0y7.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-B1vV7uuJ.js → WorkflowEditor-CTEDl_83.js} +1 -1
- package/src/assets/web-panel/assets/{chat-C0NJRaL2.js → chat-CKV51quV.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CHRiteWF.js → colors-BO_RP_yz.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-2XmBBKPD.js → compact-item-BZsxw_ZG.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DkedHC38.js → createContext-CAbvtzVL.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DQYatsRR.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Bpn9Xrlw.js → hasIn-QmHT8zDz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyJpmSHZ.js → index-5hlO2-JQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAFLFMXQ.js → index-8BMLlHCv.js} +1 -1
- package/src/assets/web-panel/assets/{index-De5vOO9V.js → index-9IqJODII.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtU4qZRF.js → index-B2aiE8jk.js} +1 -1
- package/src/assets/web-panel/assets/{index-NuBsCRaR.js → index-B3fwyCjJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYUd69vM.js → index-B5zhcul9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdR7RfRP.js → index-B9Z83FTS.js} +1 -1
- package/src/assets/web-panel/assets/{index-De49R7TX.js → index-BCsZiq4i.js} +1 -1
- package/src/assets/web-panel/assets/{index-BveL_4n3.js → index-BEJa1FiF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYmwEaIk.js → index-BL7gQAuB.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMbF-Euw.js → index-BNvTNZ1V.js} +1 -1
- package/src/assets/web-panel/assets/{index-i4W_EAuh.js → index-BPZHeug4.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN068mCR.js → index-BRNYA0BV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJOoo72F.js → index-BnPBG3Tr.js} +1 -1
- package/src/assets/web-panel/assets/index-Bv_y1Ud7.js +1 -0
- package/src/assets/web-panel/assets/{index-DUBsq_1G.js → index-C3K1eHDd.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfY9U3X5.js → index-C6AA-xB2.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dk7P-q3n.js → index-C6i3reUS.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cljnfuxu.js → index-CEh2Ry_A.js} +1 -1
- package/src/assets/web-panel/assets/{index-cfSUlOfY.js → index-CSaI8R_7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DM9JrnYi.js → index-CVoYeZ5Q.js} +1 -1
- package/src/assets/web-panel/assets/index-CZZnSJEX.js +1 -0
- package/src/assets/web-panel/assets/{index-alGjpoM1.js → index-CqiKnXtL.js} +1 -1
- package/src/assets/web-panel/assets/{index-Sk3-3tKa.js → index-CsBx0u5G.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZ1gOoiG.js → index-D8CHQnPl.js} +1 -1
- package/src/assets/web-panel/assets/{index-uHGxyZtQ.js → index-DBCYOypV.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9mNfpxi.js → index-DC1CFfQU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCg6ZY4t.js → index-DKnngF_f.js} +1 -1
- package/src/assets/web-panel/assets/{index-BItcSqan.js → index-DKquNxL2.js} +3 -3
- package/src/assets/web-panel/assets/{index-D7U411hK.js → index-DRK0oAV5.js} +1 -1
- package/src/assets/web-panel/assets/{index-CToQxpWz.js → index-DeC7lehI.js} +1 -1
- package/src/assets/web-panel/assets/{index-DryKGM_t.js → index-DjrDGJP2.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5NGWgHp.js → index-Dln_vjSY.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOsIgPge.js → index-Dob6B6qS.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAeHmElB.js → index-GPY0LjCu.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDy_RDjs.js → index-Ha2_56mf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWgWrrWs.js → index-fnDgExTu.js} +1 -1
- package/src/assets/web-panel/assets/{index-CxvA72CP.js → index-jd2r-T4p.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE5Qm9UI.js → index-qPafbZmr.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DlDE-QgI.js → initDefaultProps-Bc2GWeWe.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CodUbIRF.js → motion-BI-Rxw6o.js} +1 -1
- package/src/assets/web-panel/assets/{move-DaLwsHeR.js → move-DRPdwDQB.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DdVg-3rL.js → omit-B4XTl3jW.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-KLR1EVCo.js → pickAttrs-Do5d86Wr.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-ChV7HvNw.js → placementArrow-B8VGZ0ZF.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BB_A8dBt.js → responsiveObserve-Cf0kI_vN.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Bc1tQnIK.js → slide-Cb0psjSL.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CgrveSb0.js → statusUtils-Bjuo5Oal.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-vXAYhhjz.js → styleChecker-BLMhoHJ5.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-BCIMPfq9.js → useFlexGapSupport-BdCwAfNU.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DMZGdr6G.js → useFs-9Jhaz5gG.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-118tWI_Z.js → usePersonalDataHub-xYFyXKwD.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Z7O2Y7JP.js → vnode-CVhepE6Z.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BXym6zmD.js → zoom-IbbtJ4Zr.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +39 -0
- package/src/commands/command.js +187 -0
- package/src/commands/context.js +189 -0
- package/src/index.js +4 -0
- package/src/lib/goal-assess.js +228 -0
- package/src/lib/goal-store.js +33 -0
- package/src/lib/slash-commands.js +197 -0
- package/src/repl/agent-repl.js +42 -1
- package/src/runtime/agent-core.js +275 -0
- package/src/runtime/headless-runner.js +151 -0
- package/src/runtime/headless-stream.js +86 -0
- package/src/runtime/mcp-config.js +239 -0
- package/src/runtime/policies/agent-policy.js +1 -0
- package/src/assets/web-panel/assets/ChatBubbleRenderer-PIx0Eu9I.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-CrJJOCFw.js +0 -1
- package/src/assets/web-panel/assets/Projects-Cb3p5QAP.js +0 -1
- package/src/assets/web-panel/assets/Tasks-DtVkhWCV.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DmNpkOdC.js +0 -1
- package/src/assets/web-panel/assets/index-7nAysteg.js +0 -1
- package/src/assets/web-panel/assets/index-BKWSQilQ.js +0 -1
|
@@ -26,12 +26,18 @@ import {
|
|
|
26
26
|
agentLoop as coreAgentLoop,
|
|
27
27
|
formatToolArgs,
|
|
28
28
|
} from "./agent-core.js";
|
|
29
|
+
import {
|
|
30
|
+
loadMcpConfig,
|
|
31
|
+
resolvePermissionPromptTool,
|
|
32
|
+
makePermissionPromptConfirmer,
|
|
33
|
+
} from "./mcp-config.js";
|
|
29
34
|
import { IterationBudget } from "../lib/iteration-budget.js";
|
|
30
35
|
import {
|
|
31
36
|
startSession as jsonlStartSession,
|
|
32
37
|
appendUserMessage as jsonlAppendUserMessage,
|
|
33
38
|
appendAssistantMessage as jsonlAppendAssistantMessage,
|
|
34
39
|
appendTokenUsage as jsonlAppendTokenUsage,
|
|
40
|
+
appendCompactEvent as jsonlAppendCompactEvent,
|
|
35
41
|
rebuildMessages as jsonlRebuildMessages,
|
|
36
42
|
sessionExists as jsonlSessionExists,
|
|
37
43
|
getLastSessionId as jsonlGetLastSessionId,
|
|
@@ -245,6 +251,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
245
251
|
appendAssistantMessage:
|
|
246
252
|
deps.appendAssistantMessage || jsonlAppendAssistantMessage,
|
|
247
253
|
appendTokenUsage: deps.appendTokenUsage || jsonlAppendTokenUsage,
|
|
254
|
+
appendCompactEvent: deps.appendCompactEvent || jsonlAppendCompactEvent,
|
|
248
255
|
getLastSessionId: deps.getLastSessionId || jsonlGetLastSessionId,
|
|
249
256
|
};
|
|
250
257
|
const isStream = outputFormat === "stream-json";
|
|
@@ -367,6 +374,51 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
367
374
|
}
|
|
368
375
|
}
|
|
369
376
|
|
|
377
|
+
// --mcp-config: connect ad-hoc MCP servers for this run and expose their
|
|
378
|
+
// tools to the LLM (Claude-Code parity). Connection is best-effort — a server
|
|
379
|
+
// that fails to connect is logged to stderr and contributes no tools; a
|
|
380
|
+
// missing/empty config file fails fast (the user explicitly asked for MCP).
|
|
381
|
+
let mcp = null;
|
|
382
|
+
if (options.mcpConfig) {
|
|
383
|
+
const doLoadMcp = deps.loadMcpConfig || loadMcpConfig;
|
|
384
|
+
try {
|
|
385
|
+
mcp = await doLoadMcp(options.mcpConfig, { writeErr });
|
|
386
|
+
if (isText) {
|
|
387
|
+
for (const c of mcp.connected) {
|
|
388
|
+
writeErr(` mcp: ${c.server} (${c.tools} tools)\n`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
} catch (err) {
|
|
392
|
+
writeErr(`Error: ${err.message}\n`);
|
|
393
|
+
return { exitCode: 1, result: err.message, isError: true };
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// --permission-prompt-tool: route every CONFIRM-tier approval to an MCP tool
|
|
398
|
+
// (loaded via --mcp-config) instead of headless fail-closed. Overrides the
|
|
399
|
+
// permission-mode confirmer on the gate for this session.
|
|
400
|
+
if (options.permissionPromptTool) {
|
|
401
|
+
let ppt;
|
|
402
|
+
try {
|
|
403
|
+
ppt = resolvePermissionPromptTool(mcp, options.permissionPromptTool);
|
|
404
|
+
} catch (err) {
|
|
405
|
+
writeErr(`Error: ${err.message}\n`);
|
|
406
|
+
if (mcp?.mcpClient) await mcp.mcpClient.disconnectAll().catch(() => {});
|
|
407
|
+
return { exitCode: 1, result: err.message, isError: true };
|
|
408
|
+
}
|
|
409
|
+
if (approvalGate && typeof approvalGate.setConfirmer === "function") {
|
|
410
|
+
approvalGate.setConfirmer(
|
|
411
|
+
makePermissionPromptConfirmer({
|
|
412
|
+
mcpClient: mcp.mcpClient,
|
|
413
|
+
server: ppt.server,
|
|
414
|
+
tool: ppt.tool,
|
|
415
|
+
writeErr,
|
|
416
|
+
isText,
|
|
417
|
+
}),
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
370
422
|
const loopOptions = {
|
|
371
423
|
model,
|
|
372
424
|
provider,
|
|
@@ -382,11 +434,48 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
382
434
|
enabledToolNames,
|
|
383
435
|
disabledTools,
|
|
384
436
|
iterationBudget: budget,
|
|
437
|
+
// --mcp-config wiring: tool defs for the LLM + dispatch map + live client.
|
|
438
|
+
mcpClient: mcp?.mcpClient || null,
|
|
439
|
+
extraToolDefinitions: mcp?.extraToolDefinitions || undefined,
|
|
440
|
+
externalToolExecutors: mcp?.externalToolExecutors || undefined,
|
|
441
|
+
externalToolDescriptors: mcp?.externalToolDescriptors || undefined,
|
|
385
442
|
// chatFn passthrough lets tests drive the loop deterministically.
|
|
386
443
|
chatFn: deps.chatFn || options.chatFn || undefined,
|
|
387
444
|
signal: options.signal || undefined,
|
|
388
445
|
};
|
|
389
446
|
|
|
447
|
+
// Goal binding (cc goal, Phase 1). `--goal <id>` binds explicitly; `--goal`
|
|
448
|
+
// with no value (options.goal === true) auto-resolves from active/session.
|
|
449
|
+
// When omitted, headless stays goal-free (no behavior change). Best-effort:
|
|
450
|
+
// a failure here must never fail the run.
|
|
451
|
+
let boundGoalId = null;
|
|
452
|
+
if (options.goal !== undefined && options.goal !== false) {
|
|
453
|
+
try {
|
|
454
|
+
const explicitId = typeof options.goal === "string" ? options.goal : null;
|
|
455
|
+
const { resolveActiveGoal, linkSession } =
|
|
456
|
+
await import("../lib/goal-store.js");
|
|
457
|
+
const goal = (deps.resolveActiveGoal || resolveActiveGoal)({
|
|
458
|
+
explicitId,
|
|
459
|
+
sessionId,
|
|
460
|
+
});
|
|
461
|
+
if (goal) {
|
|
462
|
+
const { goalPrepareCall } = await import("../lib/goal-context.js");
|
|
463
|
+
loopOptions.prepareCall = goalPrepareCall(goal);
|
|
464
|
+
boundGoalId = goal.id;
|
|
465
|
+
// Link the session so a later `--continue`/`--resume` keeps this goal.
|
|
466
|
+
if (explicitId && persist !== false) {
|
|
467
|
+
try {
|
|
468
|
+
linkSession(goal.id, sessionId);
|
|
469
|
+
} catch {
|
|
470
|
+
/* linking is optional polish — never fatal */
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
} catch {
|
|
475
|
+
/* goal binding is best-effort — proceed without it */
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
390
479
|
const startedAt = deps.now ? deps.now() : Date.now();
|
|
391
480
|
const toolCalls = [];
|
|
392
481
|
const usage = { input_tokens: 0, output_tokens: 0 };
|
|
@@ -424,6 +513,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
424
513
|
resumed_from: resumeId,
|
|
425
514
|
history_messages: history.length,
|
|
426
515
|
additional_directories: additionalDirectories,
|
|
516
|
+
goal_id: boundGoalId,
|
|
427
517
|
});
|
|
428
518
|
|
|
429
519
|
try {
|
|
@@ -522,6 +612,17 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
522
612
|
writeErr(`Error: ${message}\n`);
|
|
523
613
|
}
|
|
524
614
|
return { exitCode: 1, result: message, isError: true };
|
|
615
|
+
} finally {
|
|
616
|
+
// Tear down ad-hoc MCP servers (--mcp-config) before returning, whether the
|
|
617
|
+
// loop completed or threw. Best-effort: a failed disconnect never masks the
|
|
618
|
+
// run's own outcome.
|
|
619
|
+
if (mcp?.mcpClient) {
|
|
620
|
+
try {
|
|
621
|
+
await mcp.mcpClient.disconnectAll();
|
|
622
|
+
} catch {
|
|
623
|
+
// ignore — disconnect is best-effort
|
|
624
|
+
}
|
|
625
|
+
}
|
|
525
626
|
}
|
|
526
627
|
|
|
527
628
|
// coreAgentLoop emits run-ended reason "budget-exhausted" when the iteration
|
|
@@ -543,6 +644,56 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
543
644
|
}
|
|
544
645
|
}
|
|
545
646
|
|
|
647
|
+
// Run-end goal self-assessment (cc goal Phase 2, opt-in via --goal-assess).
|
|
648
|
+
// Spends one extra completion to judge whether the run advanced the bound
|
|
649
|
+
// goal, then persists progress / key-result / drift updates. Best-effort: it
|
|
650
|
+
// must never change the run's own outcome.
|
|
651
|
+
if (options.goalAssess && boundGoalId && !isError) {
|
|
652
|
+
try {
|
|
653
|
+
const { getGoal } = await import("../lib/goal-store.js");
|
|
654
|
+
const goal = (deps.getGoal || getGoal)(boundGoalId);
|
|
655
|
+
if (goal) {
|
|
656
|
+
const { assessGoalProgress } = await import("../lib/goal-assess.js");
|
|
657
|
+
const doAssess = deps.assessGoalProgress || assessGoalProgress;
|
|
658
|
+
const assessChat =
|
|
659
|
+
deps.assessChat ||
|
|
660
|
+
(async (assessPrompt) => {
|
|
661
|
+
const { chatWithTools } = await import("./agent-core.js");
|
|
662
|
+
const r = await chatWithTools(
|
|
663
|
+
[{ role: "user", content: assessPrompt }],
|
|
664
|
+
{ model, provider, baseUrl, apiKey, enabledToolNames: [] },
|
|
665
|
+
);
|
|
666
|
+
return r?.message?.content || "";
|
|
667
|
+
});
|
|
668
|
+
const { assessment } = await doAssess({
|
|
669
|
+
goal,
|
|
670
|
+
transcript: { prompt: options.prompt, finalText, toolCalls },
|
|
671
|
+
chat: assessChat,
|
|
672
|
+
});
|
|
673
|
+
if (assessment) {
|
|
674
|
+
if (isText) {
|
|
675
|
+
writeErr(
|
|
676
|
+
` ◎ goal ${boundGoalId}: ${assessment.advanced ? "advanced" : "no progress"}` +
|
|
677
|
+
(assessment.progress != null
|
|
678
|
+
? ` (${assessment.progress}%)`
|
|
679
|
+
: "") +
|
|
680
|
+
"\n",
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
emitStream({
|
|
684
|
+
type: "goal_assessment",
|
|
685
|
+
goal_id: boundGoalId,
|
|
686
|
+
advanced: assessment.advanced,
|
|
687
|
+
progress: assessment.progress,
|
|
688
|
+
note: assessment.note,
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
} catch {
|
|
693
|
+
/* assessment is best-effort — never affect the run outcome */
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
546
697
|
if (isStream) {
|
|
547
698
|
emitStream({
|
|
548
699
|
type: "result",
|
|
@@ -20,6 +20,11 @@ import { bootstrap } from "./bootstrap.js";
|
|
|
20
20
|
import { buildSystemPrompt, agentLoop as coreAgentLoop } from "./agent-core.js";
|
|
21
21
|
import { composeSystemPrompt } from "./system-prompt.js";
|
|
22
22
|
import { expandFileRefs } from "./file-ref-expander.js";
|
|
23
|
+
import {
|
|
24
|
+
loadMcpConfig,
|
|
25
|
+
resolvePermissionPromptTool,
|
|
26
|
+
makePermissionPromptConfirmer,
|
|
27
|
+
} from "./mcp-config.js";
|
|
23
28
|
import { IterationBudget } from "../lib/iteration-budget.js";
|
|
24
29
|
import {
|
|
25
30
|
resolvePermissionMode,
|
|
@@ -207,6 +212,72 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
207
212
|
additional_directories: additionalDirectories,
|
|
208
213
|
});
|
|
209
214
|
|
|
215
|
+
// Goal binding (cc goal, Phase 1) — resolved once and injected on every turn.
|
|
216
|
+
// `--goal <id>` binds explicitly; `--goal` with no value auto-resolves.
|
|
217
|
+
let goalPrepareCallFn;
|
|
218
|
+
if (options.goal !== undefined && options.goal !== false) {
|
|
219
|
+
try {
|
|
220
|
+
const explicitId = typeof options.goal === "string" ? options.goal : null;
|
|
221
|
+
const { resolveActiveGoal } = await import("../lib/goal-store.js");
|
|
222
|
+
const goal = (deps.resolveActiveGoal || resolveActiveGoal)({
|
|
223
|
+
explicitId,
|
|
224
|
+
sessionId,
|
|
225
|
+
});
|
|
226
|
+
if (goal) {
|
|
227
|
+
const { goalPrepareCall } = await import("../lib/goal-context.js");
|
|
228
|
+
goalPrepareCallFn = goalPrepareCall(goal);
|
|
229
|
+
}
|
|
230
|
+
} catch {
|
|
231
|
+
/* goal binding is best-effort — proceed without it */
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// --mcp-config: connect ad-hoc MCP servers for the whole stream session and
|
|
236
|
+
// expose their tools to the LLM (Claude-Code parity). Best-effort connect; a
|
|
237
|
+
// missing/empty config fails the session up front.
|
|
238
|
+
let mcp = null;
|
|
239
|
+
if (options.mcpConfig) {
|
|
240
|
+
const doLoadMcp = deps.loadMcpConfig || loadMcpConfig;
|
|
241
|
+
try {
|
|
242
|
+
mcp = await doLoadMcp(options.mcpConfig, { writeErr });
|
|
243
|
+
} catch (err) {
|
|
244
|
+
emit({
|
|
245
|
+
type: "result",
|
|
246
|
+
subtype: "error",
|
|
247
|
+
is_error: true,
|
|
248
|
+
error: err.message,
|
|
249
|
+
});
|
|
250
|
+
return { exitCode: 1, turns: 0 };
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// --permission-prompt-tool: defer CONFIRM-tier approvals to an MCP tool
|
|
255
|
+
// (loaded via --mcp-config) instead of headless fail-closed.
|
|
256
|
+
if (options.permissionPromptTool) {
|
|
257
|
+
let ppt;
|
|
258
|
+
try {
|
|
259
|
+
ppt = resolvePermissionPromptTool(mcp, options.permissionPromptTool);
|
|
260
|
+
} catch (err) {
|
|
261
|
+
emit({
|
|
262
|
+
type: "result",
|
|
263
|
+
subtype: "error",
|
|
264
|
+
is_error: true,
|
|
265
|
+
error: err.message,
|
|
266
|
+
});
|
|
267
|
+
if (mcp?.mcpClient) await mcp.mcpClient.disconnectAll().catch(() => {});
|
|
268
|
+
return { exitCode: 1, turns: 0 };
|
|
269
|
+
}
|
|
270
|
+
if (approvalGate && typeof approvalGate.setConfirmer === "function") {
|
|
271
|
+
approvalGate.setConfirmer(
|
|
272
|
+
makePermissionPromptConfirmer({
|
|
273
|
+
mcpClient: mcp.mcpClient,
|
|
274
|
+
server: ppt.server,
|
|
275
|
+
tool: ppt.tool,
|
|
276
|
+
}),
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
210
281
|
const loopOptionsBase = {
|
|
211
282
|
model,
|
|
212
283
|
provider,
|
|
@@ -219,6 +290,12 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
219
290
|
approvalGate,
|
|
220
291
|
enabledToolNames,
|
|
221
292
|
disabledTools,
|
|
293
|
+
prepareCall: goalPrepareCallFn,
|
|
294
|
+
// --mcp-config wiring (tool defs + dispatch map + live client).
|
|
295
|
+
mcpClient: mcp?.mcpClient || null,
|
|
296
|
+
extraToolDefinitions: mcp?.extraToolDefinitions || undefined,
|
|
297
|
+
externalToolExecutors: mcp?.externalToolExecutors || undefined,
|
|
298
|
+
externalToolDescriptors: mcp?.externalToolDescriptors || undefined,
|
|
222
299
|
chatFn: deps.chatFn || options.chatFn || undefined,
|
|
223
300
|
signal: options.signal || undefined,
|
|
224
301
|
// --include-partial-messages: stream live assistant-text deltas as
|
|
@@ -310,6 +387,15 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
310
387
|
});
|
|
311
388
|
}
|
|
312
389
|
|
|
390
|
+
// Tear down ad-hoc MCP servers (--mcp-config) when stdin closes.
|
|
391
|
+
if (mcp?.mcpClient) {
|
|
392
|
+
try {
|
|
393
|
+
await mcp.mcpClient.disconnectAll();
|
|
394
|
+
} catch {
|
|
395
|
+
// ignore — disconnect is best-effort
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
313
399
|
emit({ type: "system", subtype: "end", session_id: sessionId, turns });
|
|
314
400
|
return { exitCode: sawError ? 1 : 0, turns };
|
|
315
401
|
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ad-hoc MCP config loader for headless agent runs (`cc agent --mcp-config`).
|
|
3
|
+
*
|
|
4
|
+
* Claude-Code parity: load a JSON file describing MCP servers, connect them for
|
|
5
|
+
* the duration of one headless run, and expose each server's tools to the LLM.
|
|
6
|
+
*
|
|
7
|
+
* The agent loop already knows how to *call* an MCP tool — it just needs three
|
|
8
|
+
* things wired into its options (see agent-core.js):
|
|
9
|
+
* - extraToolDefinitions → the LLM sees the tools (OpenAI function shape)
|
|
10
|
+
* - externalToolExecutors → name → {kind:"mcp", serverName, toolName}
|
|
11
|
+
* - mcpClient → executes mcpClient.callTool(server, tool, args)
|
|
12
|
+
*
|
|
13
|
+
* Tools are namespaced `mcp__<server>__<tool>` (Claude-Code convention) so they
|
|
14
|
+
* never collide with built-in agent tools or across servers.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from "fs";
|
|
18
|
+
import { MCPClient } from "../harness/mcp-client.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Normalize a parsed config object into a `{ name: serverConfig }` map.
|
|
22
|
+
* Accepts the Claude-Code shape `{ "mcpServers": { ... } }`, the bundle shape
|
|
23
|
+
* `{ "servers": { ... } }`, or a bare `{ name: cfg }` map.
|
|
24
|
+
*/
|
|
25
|
+
export function parseMcpServers(raw) {
|
|
26
|
+
const block =
|
|
27
|
+
(raw && typeof raw === "object" && (raw.mcpServers || raw.servers)) ||
|
|
28
|
+
raw ||
|
|
29
|
+
{};
|
|
30
|
+
const out = {};
|
|
31
|
+
for (const [name, cfg] of Object.entries(block)) {
|
|
32
|
+
if (!cfg || typeof cfg !== "object") continue;
|
|
33
|
+
out[name] = {
|
|
34
|
+
command: cfg.command,
|
|
35
|
+
args: Array.isArray(cfg.args) ? cfg.args : [],
|
|
36
|
+
env: cfg.env && typeof cfg.env === "object" ? cfg.env : {},
|
|
37
|
+
url: cfg.url,
|
|
38
|
+
transport: cfg.transport,
|
|
39
|
+
headers: cfg.headers && typeof cfg.headers === "object" ? cfg.headers : {},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Namespaced tool name exposed to the LLM. */
|
|
46
|
+
export function mcpToolName(server, tool) {
|
|
47
|
+
return `mcp__${server}__${tool}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Connect the given servers and build the agent-loop wiring. Connection
|
|
52
|
+
* failures are reported (writeErr) but never abort the run — a broken server
|
|
53
|
+
* just contributes no tools.
|
|
54
|
+
*
|
|
55
|
+
* @param {object} servers `{ name: { command|url, args, env, transport, headers } }`
|
|
56
|
+
* @param {object} [deps] { writeErr, createClient }
|
|
57
|
+
* @returns {Promise<{mcpClient, extraToolDefinitions, externalToolExecutors,
|
|
58
|
+
* externalToolDescriptors, connected}>}
|
|
59
|
+
*/
|
|
60
|
+
export async function setupMcpFromConfig(servers, deps = {}) {
|
|
61
|
+
const writeErr = deps.writeErr || (() => {});
|
|
62
|
+
const createClient = deps.createClient || (() => new MCPClient());
|
|
63
|
+
|
|
64
|
+
const mcpClient = createClient();
|
|
65
|
+
const extraToolDefinitions = [];
|
|
66
|
+
const externalToolExecutors = {};
|
|
67
|
+
const externalToolDescriptors = {};
|
|
68
|
+
const connected = [];
|
|
69
|
+
|
|
70
|
+
for (const [name, cfg] of Object.entries(servers)) {
|
|
71
|
+
let result;
|
|
72
|
+
try {
|
|
73
|
+
result = await mcpClient.connect(name, cfg);
|
|
74
|
+
} catch (err) {
|
|
75
|
+
writeErr(` mcp: failed to connect "${name}": ${err.message}\n`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const tools = Array.isArray(result?.tools) ? result.tools : [];
|
|
79
|
+
connected.push({ server: name, tools: tools.length });
|
|
80
|
+
for (const t of tools) {
|
|
81
|
+
if (!t || !t.name) continue;
|
|
82
|
+
const full = mcpToolName(name, t.name);
|
|
83
|
+
extraToolDefinitions.push({
|
|
84
|
+
type: "function",
|
|
85
|
+
function: {
|
|
86
|
+
name: full,
|
|
87
|
+
description: t.description || `MCP tool "${t.name}" on server "${name}"`,
|
|
88
|
+
parameters: t.inputSchema || { type: "object", properties: {} },
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
externalToolExecutors[full] = {
|
|
92
|
+
kind: "mcp",
|
|
93
|
+
serverName: name,
|
|
94
|
+
toolName: t.name,
|
|
95
|
+
};
|
|
96
|
+
externalToolDescriptors[full] = {
|
|
97
|
+
name: full,
|
|
98
|
+
kind: "mcp",
|
|
99
|
+
category: "mcp",
|
|
100
|
+
source: name,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
mcpClient,
|
|
107
|
+
extraToolDefinitions,
|
|
108
|
+
externalToolExecutors,
|
|
109
|
+
externalToolDescriptors,
|
|
110
|
+
connected,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Read + parse a `--mcp-config` file and connect its servers.
|
|
116
|
+
* Throws on an unreadable/empty config (fail fast — the user asked for MCP).
|
|
117
|
+
*
|
|
118
|
+
* @param {string} filePath
|
|
119
|
+
* @param {object} [deps] { writeErr, createClient, readFile }
|
|
120
|
+
*/
|
|
121
|
+
export async function loadMcpConfig(filePath, deps = {}) {
|
|
122
|
+
const readFile = deps.readFile || ((p) => fs.readFileSync(p, "utf-8"));
|
|
123
|
+
let raw;
|
|
124
|
+
try {
|
|
125
|
+
raw = JSON.parse(readFile(filePath));
|
|
126
|
+
} catch (err) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`--mcp-config: cannot read/parse "${filePath}": ${err.message}`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
const servers = parseMcpServers(raw);
|
|
132
|
+
if (Object.keys(servers).length === 0) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`--mcp-config: no servers found in "${filePath}" ` +
|
|
135
|
+
`(expected {"mcpServers": {"name": {"command": "..."}}}).`,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return setupMcpFromConfig(servers, deps);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── --permission-prompt-tool (programmable headless approval) ──────────────
|
|
142
|
+
//
|
|
143
|
+
// Claude-Code parity: instead of headless fail-closed (auto-deny risky tools),
|
|
144
|
+
// route every CONFIRM-tier decision to an MCP tool that returns the verdict.
|
|
145
|
+
// The named tool must come from a server loaded via --mcp-config.
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Resolve a `mcp__<server>__<tool>` permission-prompt-tool name to its server +
|
|
149
|
+
* tool, validating it was actually loaded. Throws (fail fast) otherwise.
|
|
150
|
+
*/
|
|
151
|
+
export function resolvePermissionPromptTool(mcp, toolName) {
|
|
152
|
+
if (!mcp || !mcp.externalToolExecutors) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
`--permission-prompt-tool "${toolName}" requires --mcp-config ` +
|
|
155
|
+
`(the tool must come from a loaded MCP server).`,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
const exec = mcp.externalToolExecutors[toolName];
|
|
159
|
+
if (!exec || exec.kind !== "mcp") {
|
|
160
|
+
const avail = Object.keys(mcp.externalToolExecutors).join(", ") || "(none)";
|
|
161
|
+
throw new Error(
|
|
162
|
+
`--permission-prompt-tool "${toolName}" not found among loaded MCP ` +
|
|
163
|
+
`tools. Available: ${avail}`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
return { server: exec.serverName, tool: exec.toolName };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Interpret an MCP `tools/call` result as an allow/deny verdict. Liberal: reads
|
|
171
|
+
* a JSON `{behavior:"allow"|"deny"}` (Claude-Code shape) from a text content
|
|
172
|
+
* block, or a top-level `behavior`/`decision`/`allow`. Anything not clearly an
|
|
173
|
+
* allow is treated as deny (fail-closed).
|
|
174
|
+
*/
|
|
175
|
+
export function parsePermissionDecision(result) {
|
|
176
|
+
if (!result || result.isError) {
|
|
177
|
+
return { allow: false, reason: "permission tool returned no/err result" };
|
|
178
|
+
}
|
|
179
|
+
let payload = result;
|
|
180
|
+
if (Array.isArray(result.content)) {
|
|
181
|
+
const textBlock = result.content.find(
|
|
182
|
+
(b) => b && b.type === "text" && typeof b.text === "string",
|
|
183
|
+
);
|
|
184
|
+
if (textBlock) {
|
|
185
|
+
try {
|
|
186
|
+
payload = JSON.parse(textBlock.text);
|
|
187
|
+
} catch {
|
|
188
|
+
payload = { behavior: textBlock.text.trim() };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const behavior =
|
|
193
|
+
payload?.behavior ??
|
|
194
|
+
payload?.decision ??
|
|
195
|
+
(payload?.allow === true ? "allow" : undefined);
|
|
196
|
+
const allow = behavior === "allow" || payload?.allow === true;
|
|
197
|
+
return {
|
|
198
|
+
allow,
|
|
199
|
+
reason: payload?.message || payload?.reason || null,
|
|
200
|
+
updatedInput: payload?.updatedInput,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Build an ApprovalGate confirmer that defers each CONFIRM-tier decision to the
|
|
206
|
+
* given MCP tool. Fail-closed: any tool error → deny.
|
|
207
|
+
*
|
|
208
|
+
* @param {object} args { mcpClient, server, tool, writeErr?, isText? }
|
|
209
|
+
* @returns {(ctx:{tool:string,args:object})=>Promise<boolean>}
|
|
210
|
+
*/
|
|
211
|
+
export function makePermissionPromptConfirmer({
|
|
212
|
+
mcpClient,
|
|
213
|
+
server,
|
|
214
|
+
tool,
|
|
215
|
+
writeErr = () => {},
|
|
216
|
+
isText = false,
|
|
217
|
+
}) {
|
|
218
|
+
return async (ctx) => {
|
|
219
|
+
try {
|
|
220
|
+
const result = await mcpClient.callTool(server, tool, {
|
|
221
|
+
tool_name: ctx?.tool,
|
|
222
|
+
input: ctx?.args || {},
|
|
223
|
+
});
|
|
224
|
+
const { allow, reason } = parsePermissionDecision(result);
|
|
225
|
+
if (isText) {
|
|
226
|
+
writeErr(
|
|
227
|
+
` permission(${ctx?.tool}): ${allow ? "allow" : "deny"}` +
|
|
228
|
+
`${reason ? " — " + reason : ""}\n`,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
return allow;
|
|
232
|
+
} catch (err) {
|
|
233
|
+
if (isText) {
|
|
234
|
+
writeErr(` permission(${ctx?.tool}): deny (tool error: ${err.message})\n`);
|
|
235
|
+
}
|
|
236
|
+
return false; // fail-closed
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as v,P as u,J as S,U as s,R as a,S as y,K as C,Q as x,V as w,_ as B,b as n}from"./vendor-BvqAck49.js";import{_ as k}from"./index-BItcSqan.js";import"./icons-DP3uiYxy.js";const M={__name:"ChatBubbleRenderer",props:{event:{type:Object,required:!0}},setup(c,{expose:d}){d();const t=c,r=n(()=>{const e=t.event.content||{};return e.text||e.body||e.message||e.title||JSON.stringify(e).slice(0,200)}),i=n(()=>{const e=t.event.content||{};return e.from||e.sender||e.senderName||t.event.actor||"(unknown)"}),l=n(()=>{const e=(t.event.actor||"").toLowerCase();return e.includes("self")||e==="me"||e.endsWith("_self")}),o=n(()=>{const e=t.event.source.adapter||"";return e.startsWith("messaging-qq")?"magenta":e==="wechat"?"green":"blue"}),m=n(()=>{if(!t.event.occurredAt)return"";try{const e=new Date(t.event.occurredAt),p=e.getFullYear(),f=String(e.getMonth()+1).padStart(2,"0"),g=String(e.getDate()).padStart(2,"0"),b=String(e.getHours()).padStart(2,"0"),h=String(e.getMinutes()).padStart(2,"0");return`${p}-${f}-${g} ${b}:${h}`}catch{return""}}),_={props:t,messageText:r,actorLabel:i,isMine:l,adapterColor:o,formattedTime:m,computed:n};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}},N={class:"bubble"},T={class:"meta"},R={class:"actor"},V={class:"time"},q={class:"body"};function D(c,d,t,r,i,l){const o=v("a-tag");return u(),S("div",{class:B(["chat-row",{mine:r.isMine}])},[s("div",N,[s("div",T,[s("span",R,a(r.actorLabel),1),s("span",V,a(r.formattedTime),1)]),s("div",q,a(r.messageText),1),t.event.source.adapter?(u(),y(o,{key:0,class:"src",color:r.adapterColor},{default:C(()=>[x(a(t.event.source.adapter),1)]),_:1},8,["color"])):w("v-if",!0)])],2)}const A=k(M,[["render",D],["__scopeId","data-v-49238629"],["__file","/tmp/cc-web-panel-v2hnMt/repo/packages/web-panel/src/components/pdh/renderers/ChatBubbleRenderer.vue"]]);export{A as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as n,J as g,c as l,K as r,N as u,P as h,U as o,R as t,Q as b}from"./vendor-BvqAck49.js";import{_ as v,b as m}from"./index-BItcSqan.js";import{a7 as M,M as y}from"./icons-DP3uiYxy.js";const B={__name:"MobileProjects",setup(p,{expose:i}){i();const c=u(),{t:e}=m();function a(){c.push("/projects")}function _(){c.push("/mobile-bridge")}const s={router:c,t:e,goToProjects:a,goToMobileBridge:_,get useRouter(){return u},get useI18n(){return m},get MobileOutlined(){return y},get FolderOutlined(){return M}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}},x={class:"mobile-projects-placeholder"},O={class:"title"},k={class:"subtitle"},w={class:"explainer"};function T(p,i,c,e,a,_){const s=n("a-alert"),d=n("a-button"),f=n("a-space"),P=n("a-empty"),j=n("a-card");return h(),g("div",x,[l(j,null,{default:r(()=>[l(P,{description:!1},{image:r(()=>[l(e.MobileOutlined,{style:{fontSize:"64px",color:"#bfbfbf"}})]),default:r(()=>[o("h2",O,t(e.t("mobileProjects.title")),1),o("p",k,t(e.t("mobileProjects.subtitle")),1),l(s,{message:e.t("mobileProjects.v02Banner"),type:"info","show-icon":"",class:"banner"},null,8,["message"]),o("div",w,[o("h3",null,t(e.t("mobileProjects.currentDirection")),1),o("p",null,t(e.t("mobileProjects.currentDirectionBody")),1),o("ul",null,[o("li",null,t(e.t("mobileProjects.stepPhone")),1),o("li",null,t(e.t("mobileProjects.stepTap")),1),o("li",null,t(e.t("mobileProjects.stepPull")),1)]),o("h3",null,t(e.t("mobileProjects.reverseDirection")),1),o("p",null,t(e.t("mobileProjects.reverseDirectionBody")),1)]),l(f,{class:"actions"},{default:r(()=>[l(d,{type:"primary",onClick:e.goToProjects},{default:r(()=>[l(e.FolderOutlined),b(" "+t(e.t("mobileProjects.viewLocalProjects")),1)]),_:1}),l(d,{onClick:e.goToMobileBridge},{default:r(()=>[l(e.MobileOutlined),b(" "+t(e.t("mobileProjects.checkBridge")),1)]),_:1})]),_:1})]),_:1})]),_:1})])}const N=v(B,[["render",T],["__scopeId","data-v-9262cc45"],["__file","/tmp/cc-web-panel-v2hnMt/repo/packages/web-panel/src/views/MobileProjects.vue"]]);export{N as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as i,J as A,U as I,R as s,Q as r,c as t,K as a,V as _,S as x,o as oe,b as ee,r as u,P as p,F as ne,a2 as ge}from"./vendor-BvqAck49.js";import{_ as we,b as re,u as ie,d}from"./index-BItcSqan.js";import{u as de}from"./useShellMode-CgR0wCYM.js";import{aM as ke,aN as Fe,aO as be,f as je,a4 as Ce,a7 as xe,as as Oe,R as Se}from"./icons-DP3uiYxy.js";const Pe={__name:"Projects",setup(se,{expose:l}){l();const{t:te}=re(),e=ie(),{isEmbedded:W}=de();async function w(o,f,ye,ae=8e3){if(W){const Z=await e.sendRaw({...f,type:o},ae);if(!Z?.ok){const $=Z?.error;throw new Error(typeof $=="string"?$:$?.message||`${o} failed`)}return Z.result}return e.executeJson(ye,ae)}const B=u(!1),y=u([]),O=u(""),S=u(""),P=u(!1),v=u(null),U=u([]),k=u(!1),E=u(!1),L=u(!1),F=u({name:"",description:"",type:"document",rootPath:""}),z=[{title:"ID",key:"id",width:110},{title:"名称",key:"name"},{title:"类型",key:"project_type",width:120},{title:"状态",key:"status",width:100},{title:"同步",key:"sync_status",width:100},{title:"更新",key:"updated_at",width:160},{title:"操作",key:"actions",width:180,fixed:"right"}],N=ee(()=>{const o={active:0,draft:0,completed:0,archived:0};for(const f of y.value)o[f.status]!==void 0&&(o[f.status]+=1);return o}),J=ee(()=>y.value.filter(o=>!(O.value&&o.status!==O.value||S.value&&!o.name.toLowerCase().includes(S.value.toLowerCase()))));function g(o){switch(o){case"active":return"green";case"draft":return"default";case"completed":return"cyan";case"archived":return"gold";default:return"default"}}function K(o){switch(o){case"synced":return"green";case"pending":return"orange";case"conflict":return"red";case"error":return"red";default:return"default"}}function Q(o){return!o&&o!==0?"-":new Date(typeof o=="number"?o:parseInt(o,10)).toLocaleString("zh-CN",{hour12:!1})}async function C(){B.value=!0;try{const o=await w("project.list",{limit:500},"project list --limit 500 --json",1e4);y.value=Array.isArray(o?.projects)?o.projects:Array.isArray(o)?o:[]}catch(o){d.error("加载失败: "+(o.message||o)),y.value=[]}finally{B.value=!1}}function G(o){return{onClick:()=>V(o)}}async function V(o){v.value=o,P.value=!0,k.value=!0,U.value=[];try{const f=await w("project.listFiles",{projectId:o.id,limit:200},`project list-files ${o.id} --json`,8e3);U.value=Array.isArray(f?.files)?f.files:[]}catch{U.value=[]}finally{k.value=!1}}async function H(o){try{(await w("project.delete",{id:o.id},`project delete ${o.id} --json`,8e3))?.ok?(d.success(`已删除项目 '${o.name}'`),P.value=!1,await C()):d.error("删除失败")}catch(f){d.error(f.message||String(f))}}function X(){F.value={name:"",description:"",type:"document",rootPath:""},E.value=!0}async function T(){if(!F.value.name.trim()){d.warning("请输入项目名称");return}L.value=!0;try{const o=await w("project.init",{name:F.value.name.trim(),description:F.value.description||null,projectType:F.value.type,rootPath:F.value.rootPath||null},`project init "${F.value.name.trim()}" --type ${F.value.type} --json`,8e3);o?.id?(d.success(`已创建项目 '${o.name}'`),E.value=!1,await C()):d.error("创建失败")}catch(o){d.error(o.message||String(o))}finally{L.value=!1}}const b=u(!1),D=u(!1),j=u({path:"",content:""}),h=u(!1),m=u(!1),R=u({path:""}),n=u(!1),c=u(null),q=u(""),Y=u(!1);function ue(){j.value={path:"",content:""},b.value=!0}function ce(){R.value={path:""},h.value=!0}async function M(){if(v.value){k.value=!0;try{const o=await w("project.listFiles",{projectId:v.value.id,limit:200},`project list-files ${v.value.id} --json`,8e3);U.value=Array.isArray(o?.files)?o.files:[]}catch(o){d.error("刷新文件失败: "+(o.message||o))}finally{k.value=!1}}}async function fe(){if(!j.value.path.trim()){d.warning("请输入文件路径");return}if(v.value){D.value=!0;try{const o=await w("project.createFile",{projectId:v.value.id,filePath:j.value.path.trim(),content:j.value.content||""},`project create-file ${v.value.id} "${j.value.path.trim()}" --json`,8e3);o?.id?(d.success(`已创建文件 '${o.file_name}'`),b.value=!1,await M(),await C()):d.error("创建文件失败")}catch(o){d.error(o.message||String(o))}finally{D.value=!1}}}async function pe(){if(!R.value.path.trim()){d.warning("请输入文件夹路径");return}if(v.value){m.value=!0;try{const o=await w("project.createFolder",{projectId:v.value.id,folderPath:R.value.path.trim()},`project create-folder ${v.value.id} "${R.value.path.trim()}" --json`,8e3);o?.id?(d.success(`已创建文件夹 '${o.file_name}'`),h.value=!1,await M(),await C()):d.error("创建文件夹失败")}catch(o){d.error(o.message||String(o))}finally{m.value=!1}}}async function ve(o){try{(await w("project.deleteFile",{fileId:o.id},`project delete-file ${o.id} --json`,8e3))?.deleted?(d.success(`已删除 '${o.file_name}'`),await M(),await C()):d.error("删除失败")}catch(f){d.error(f.message||String(f))}}async function me(o){if(o.is_folder){d.info("文件夹无内容可编辑");return}try{const f=await w("project.getFile",{fileId:o.id},`project get-file ${o.id} --json`,8e3);c.value=o,q.value=f?.content||"",n.value=!0}catch(f){d.error("读取文件失败: "+(f.message||f))}}async function _e(){if(c.value){Y.value=!0;try{(await w("project.writeFile",{fileId:c.value.id,content:q.value},`project write-file ${c.value.id} --json`,8e3))?.id?(d.success("已保存"),n.value=!1,await M()):d.error("保存失败")}catch(o){d.error(o.message||String(o))}finally{Y.value=!1}}}oe(()=>{C()});const le={t:te,ws:e,isEmbedded:W,callProjectTopic:w,loading:B,projects:y,statusFilter:O,nameFilter:S,detailOpen:P,detail:v,files:U,filesLoading:k,createOpen:E,creating:L,newProject:F,columns:z,countByStatus:N,filteredProjects:J,statusColor:g,syncColor:K,formatTime:Q,loadAll:C,onRowClick:G,openDetail:V,onDelete:H,onShowCreate:X,onCreate:T,createFileOpen:b,creatingFile:D,newFile:j,createFolderOpen:h,creatingFolder:m,newFolder:R,editFileOpen:n,editingFile:c,editFileContent:q,savingFile:Y,openCreateFile:ue,openCreateFolder:ce,refreshFiles:M,onCreateFile:fe,onCreateFolder:pe,onDeleteFile:ve,openEditFile:me,onSaveFile:_e,ref:u,computed:ee,onMounted:oe,get ReloadOutlined(){return Se},get PlusOutlined(){return Oe},get FolderOutlined(){return xe},get FileTextOutlined(){return Ce},get CheckCircleOutlined(){return je},get CheckSquareOutlined(){return be},get FileAddOutlined(){return Fe},get FolderAddOutlined(){return ke},get message(){return d},get useI18n(){return re},get useWsStore(){return ie},get useShellMode(){return de}};return Object.defineProperty(le,"__isScriptSetup",{enumerable:!1,value:!0}),le}},ze={style:{display:"flex","align-items":"center","justify-content":"space-between","margin-bottom":"24px"}},he={class:"page-title"},Ae={class:"page-sub"},Ie={class:"filter-bar",style:{"margin-bottom":"12px",display:"flex",gap:"12px","align-items":"center"}},Ue={key:0,style:{"font-size":"12px",color:"#888"}},De={key:0,style:{color:"#888","font-size":"12px"}},Re={key:0},Te={key:1,style:{color:"#888"}},Be=["onClick"],Ee={key:0,style:{color:"#888","font-size":"12px"}};function Le(se,l,te,e,W,w){const B=i("router-link"),y=i("a-button"),O=i("a-space"),S=i("a-statistic"),P=i("a-card"),v=i("a-col"),U=i("a-row"),k=i("a-radio-button"),E=i("a-radio-group"),L=i("a-input-search"),F=i("a-alert"),z=i("a-tag"),N=i("a-popconfirm"),J=i("a-table"),g=i("a-descriptions-item"),K=i("a-descriptions"),Q=i("a-divider"),C=i("a-empty"),G=i("a-list-item"),V=i("a-list"),H=i("a-spin"),X=i("a-drawer"),T=i("a-input"),b=i("a-form-item"),D=i("a-textarea"),j=i("a-form"),h=i("a-modal"),m=i("a-select-option"),R=i("a-select");return p(),A("div",null,[I("div",ze,[I("div",null,[I("h2",he,s(e.t("projects.title")),1),I("p",Ae,[l[17]||(l[17]=r("桌面 / CLI / 手机 三端共享同一份项目数据,Phase 3d sync 自动同步 (",-1)),t(B,{to:"/project-init"},{default:a(()=>[...l[16]||(l[16]=[r("项目初始化 / 环境设置",-1)])]),_:1}),l[18]||(l[18]=r(")",-1))])]),t(O,null,{default:a(()=>[t(y,{loading:e.loading,onClick:e.loadAll},{icon:a(()=>[t(e.ReloadOutlined)]),default:a(()=>[l[19]||(l[19]=r(" 刷新 ",-1))]),_:1},8,["loading"]),t(y,{type:"primary",onClick:e.onShowCreate},{icon:a(()=>[t(e.PlusOutlined)]),default:a(()=>[l[20]||(l[20]=r(" 新建项目 ",-1))]),_:1})]),_:1})]),_(" Stats "),t(U,{gutter:[16,16],style:{"margin-bottom":"20px"}},{default:a(()=>[t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"总项目",value:e.projects.length,"value-style":{color:"#1677ff",fontSize:"20px"}},{prefix:a(()=>[t(e.FolderOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"活跃",value:e.countByStatus.active,"value-style":{color:"#52c41a",fontSize:"20px"}},{prefix:a(()=>[t(e.CheckCircleOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"草稿",value:e.countByStatus.draft,"value-style":{color:"#8c8c8c",fontSize:"20px"}},{prefix:a(()=>[t(e.FileTextOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"已完成",value:e.countByStatus.completed,"value-style":{color:"#13c2c2",fontSize:"20px"}},{prefix:a(()=>[t(e.CheckSquareOutlined)]),_:1},8,["value"])]),_:1})]),_:1})]),_:1}),_(" Filter "),I("div",Ie,[t(E,{value:e.statusFilter,"onUpdate:value":l[0]||(l[0]=n=>e.statusFilter=n),size:"small","button-style":"solid"},{default:a(()=>[t(k,{value:""},{default:a(()=>[...l[21]||(l[21]=[r("全部",-1)])]),_:1}),t(k,{value:"active"},{default:a(()=>[...l[22]||(l[22]=[r("活跃",-1)])]),_:1}),t(k,{value:"draft"},{default:a(()=>[...l[23]||(l[23]=[r("草稿",-1)])]),_:1}),t(k,{value:"completed"},{default:a(()=>[...l[24]||(l[24]=[r("已完成",-1)])]),_:1}),t(k,{value:"archived"},{default:a(()=>[...l[25]||(l[25]=[r("已归档",-1)])]),_:1})]),_:1},8,["value"]),t(L,{value:e.nameFilter,"onUpdate:value":l[1]||(l[1]=n=>e.nameFilter=n),placeholder:"按名称过滤",style:{"max-width":"260px"},"allow-clear":""},null,8,["value"])]),!e.projects.length&&!e.loading?(p(),x(F,{key:0,type:"info",message:"还没有项目",description:'运行 `cc project init <name>` 或点击右上角"新建项目"按钮创建。桌面 / CLI / 手机三端共享同一份数据。',"show-icon":"",style:{"margin-bottom":"16px"}})):_("v-if",!0),e.projects.length||e.loading?(p(),x(J,{key:1,columns:e.columns,"data-source":e.filteredProjects,loading:e.loading,pagination:{pageSize:20,showSizeChanger:!0},"row-key":"id","custom-row":e.onRowClick},{bodyCell:a(({column:n,record:c})=>[n.key==="id"?(p(),A("code",Ue,s(c.id.slice(0,8))+"…",1)):n.key==="name"?(p(),A(ne,{key:1},[I("strong",null,s(c.name),1),c.description?(p(),A("div",De,s(c.description),1)):_("v-if",!0)],64)):n.key==="project_type"?(p(),x(z,{key:2},{default:a(()=>[r(s(c.project_type),1)]),_:2},1024)):n.key==="status"?(p(),x(z,{key:3,color:e.statusColor(c.status)},{default:a(()=>[r(s(c.status),1)]),_:2},1032,["color"])):n.key==="sync_status"?(p(),x(z,{key:4,color:e.syncColor(c.sync_status)},{default:a(()=>[r(s(c.sync_status||"unknown"),1)]),_:2},1032,["color"])):n.key==="updated_at"?(p(),A(ne,{key:5},[r(s(e.formatTime(c.updated_at)),1)],64)):n.key==="actions"?(p(),x(O,{key:6,onClick:l[2]||(l[2]=ge(()=>{},["stop"]))},{default:a(()=>[t(y,{size:"small",onClick:q=>e.openDetail(c)},{default:a(()=>[...l[26]||(l[26]=[r("详情",-1)])]),_:1},8,["onClick"]),t(N,{title:`删除项目 '${c.name}' ?`,"ok-text":"删除","ok-type":"danger","cancel-text":"取消",onConfirm:q=>e.onDelete(c)},{default:a(()=>[t(y,{size:"small",danger:""},{default:a(()=>[...l[27]||(l[27]=[r("删除",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)):_("v-if",!0)]),_:1},8,["data-source","loading"])):_("v-if",!0),_(" Detail drawer "),t(X,{open:e.detailOpen,"onUpdate:open":l[3]||(l[3]=n=>e.detailOpen=n),title:e.detail?.name||"项目详情",width:"640",placement:"right"},{default:a(()=>[e.detail?(p(),x(K,{key:0,column:1,bordered:"",size:"small"},{default:a(()=>[t(g,{label:"ID"},{default:a(()=>[I("code",null,s(e.detail.id),1)]),_:1}),t(g,{label:"名称"},{default:a(()=>[r(s(e.detail.name),1)]),_:1}),t(g,{label:"描述"},{default:a(()=>[r(s(e.detail.description||"-"),1)]),_:1}),t(g,{label:"类型"},{default:a(()=>[t(z,null,{default:a(()=>[r(s(e.detail.project_type),1)]),_:1})]),_:1}),t(g,{label:"状态"},{default:a(()=>[t(z,{color:e.statusColor(e.detail.status)},{default:a(()=>[r(s(e.detail.status),1)]),_:1},8,["color"])]),_:1}),t(g,{label:"同步状态"},{default:a(()=>[t(z,{color:e.syncColor(e.detail.sync_status)},{default:a(()=>[r(s(e.detail.sync_status||"unknown"),1)]),_:1},8,["color"])]),_:1}),t(g,{label:"用户"},{default:a(()=>[r(s(e.detail.user_id),1)]),_:1}),t(g,{label:"根路径"},{default:a(()=>[e.detail.root_path?(p(),A("code",Re,s(e.detail.root_path),1)):(p(),A("span",Te,"(无)"))]),_:1}),t(g,{label:"文件数"},{default:a(()=>[r(s(e.detail.file_count||0),1)]),_:1}),t(g,{label:"创建"},{default:a(()=>[r(s(e.formatTime(e.detail.created_at)),1)]),_:1}),t(g,{label:"更新"},{default:a(()=>[r(s(e.formatTime(e.detail.updated_at)),1)]),_:1})]),_:1})):_("v-if",!0),t(Q,null,{default:a(()=>[...l[28]||(l[28]=[r("文件",-1)])]),_:1}),_(" Sub-phase 7.3 (2026-05-17): 文件 CRUD toolbar "),t(O,{style:{"margin-bottom":"12px"}},{default:a(()=>[t(y,{size:"small",type:"primary",disabled:!e.detail,onClick:e.openCreateFile},{default:a(()=>[t(e.FileAddOutlined),l[29]||(l[29]=r(" 新建文件 ",-1))]),_:1},8,["disabled"]),t(y,{size:"small",disabled:!e.detail,onClick:e.openCreateFolder},{default:a(()=>[t(e.FolderAddOutlined),l[30]||(l[30]=r(" 新建文件夹 ",-1))]),_:1},8,["disabled"])]),_:1}),t(H,{spinning:e.filesLoading},{default:a(()=>[!e.files.length&&!e.filesLoading?(p(),x(C,{key:0,description:"无文件 (点上方按钮新建)"})):(p(),x(V,{key:1,size:"small","data-source":e.files},{renderItem:a(({item:n})=>[t(G,null,{extra:a(()=>[t(O,null,{default:a(()=>[n.file_size?(p(),A("span",Ee,s(n.file_size)+" B",1)):_("v-if",!0),t(N,{title:`删除 ${n.is_folder?"文件夹":"文件"} '${n.file_name}' ?`,"ok-text":"删除","ok-type":"danger","cancel-text":"取消",onConfirm:c=>e.onDeleteFile(n)},{default:a(()=>[t(y,{size:"small",danger:""},{default:a(()=>[...l[31]||(l[31]=[r("×",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)]),default:a(()=>[I("span",{style:{cursor:"pointer"},onClick:c=>e.openEditFile(n)},s(n.is_folder?"📁":"📄")+" "+s(n.file_path),9,Be)]),_:2},1024)]),_:1},8,["data-source"]))]),_:1},8,["spinning"])]),_:1},8,["open","title"]),_(" Sub-phase 7.3: Create file modal "),t(h,{open:e.createFileOpen,"onUpdate:open":l[6]||(l[6]=n=>e.createFileOpen=n),title:"新建文件","confirm-loading":e.creatingFile,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreateFile},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"文件路径(项目内)",required:""},{default:a(()=>[t(T,{value:e.newFile.path,"onUpdate:value":l[4]||(l[4]=n=>e.newFile.path=n),placeholder:"例如 README.md 或 src/main.kt"},null,8,["value"])]),_:1}),t(b,{label:"初始内容(可选)"},{default:a(()=>[t(D,{value:e.newFile.content,"onUpdate:value":l[5]||(l[5]=n=>e.newFile.content=n),rows:6,placeholder:"留空创建空文件"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),_(" Sub-phase 7.3: Create folder modal "),t(h,{open:e.createFolderOpen,"onUpdate:open":l[8]||(l[8]=n=>e.createFolderOpen=n),title:"新建文件夹","confirm-loading":e.creatingFolder,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreateFolder},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"文件夹路径(项目内)",required:""},{default:a(()=>[t(T,{value:e.newFolder.path,"onUpdate:value":l[7]||(l[7]=n=>e.newFolder.path=n),placeholder:"例如 src/utils"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),_(" Sub-phase 7.3: Edit file content modal "),t(h,{open:e.editFileOpen,"onUpdate:open":l[10]||(l[10]=n=>e.editFileOpen=n),title:`编辑 ${e.editingFile?.file_name||""}`,"confirm-loading":e.savingFile,"ok-text":"保存","cancel-text":"取消",onOk:e.onSaveFile,width:"720"},{default:a(()=>[t(D,{value:e.editFileContent,"onUpdate:value":l[9]||(l[9]=n=>e.editFileContent=n),rows:18,"auto-size":{minRows:12,maxRows:24},style:{"font-family":"monospace"}},null,8,["value"])]),_:1},8,["open","title","confirm-loading"]),_(" Create modal "),t(h,{open:e.createOpen,"onUpdate:open":l[15]||(l[15]=n=>e.createOpen=n),title:"新建项目","confirm-loading":e.creating,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreate},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"项目名称",required:""},{default:a(()=>[t(T,{value:e.newProject.name,"onUpdate:value":l[11]||(l[11]=n=>e.newProject.name=n),placeholder:"例如:旅行计划-上海"},null,8,["value"])]),_:1}),t(b,{label:"描述"},{default:a(()=>[t(D,{value:e.newProject.description,"onUpdate:value":l[12]||(l[12]=n=>e.newProject.description=n),rows:2},null,8,["value"])]),_:1}),t(b,{label:"类型"},{default:a(()=>[t(R,{value:e.newProject.type,"onUpdate:value":l[13]||(l[13]=n=>e.newProject.type=n)},{default:a(()=>[t(m,{value:"document"},{default:a(()=>[...l[32]||(l[32]=[r("文档 (document)",-1)])]),_:1}),t(m,{value:"data"},{default:a(()=>[...l[33]||(l[33]=[r("数据 (data)",-1)])]),_:1}),t(m,{value:"web"},{default:a(()=>[...l[34]||(l[34]=[r("Web",-1)])]),_:1}),t(m,{value:"app"},{default:a(()=>[...l[35]||(l[35]=[r("应用 (app)",-1)])]),_:1}),t(m,{value:"presentation"},{default:a(()=>[...l[36]||(l[36]=[r("演示文稿",-1)])]),_:1}),t(m,{value:"spreadsheet"},{default:a(()=>[...l[37]||(l[37]=[r("表格",-1)])]),_:1}),t(m,{value:"design"},{default:a(()=>[...l[38]||(l[38]=[r("设计",-1)])]),_:1}),t(m,{value:"code"},{default:a(()=>[...l[39]||(l[39]=[r("代码",-1)])]),_:1}),t(m,{value:"workflow"},{default:a(()=>[...l[40]||(l[40]=[r("工作流",-1)])]),_:1}),t(m,{value:"knowledge"},{default:a(()=>[...l[41]||(l[41]=[r("知识库",-1)])]),_:1})]),_:1},8,["value"])]),_:1}),t(b,{label:"根路径 (可选)"},{default:a(()=>[t(T,{value:e.newProject.rootPath,"onUpdate:value":l[14]||(l[14]=n=>e.newProject.rootPath=n),placeholder:"留空则仅元数据"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"])])}const We=we(Pe,[["render",Le],["__scopeId","data-v-019ac5aa"],["__file","/tmp/cc-web-panel-v2hnMt/repo/packages/web-panel/src/views/Projects.vue"]]);export{We as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{E as B,b as z,r as D,I as p,J as c,U as _,c as n,K as a,S as T,V as w,o as P,x as I,P as i,Q as g,R as r,F as h,Z as F}from"./vendor-BvqAck49.js";import{u as R,_ as O}from"./index-BItcSqan.js";import{R as E}from"./icons-DP3uiYxy.js";const V=B("tasks",()=>{const k=D([]),l=D(!1);let u=null,e=null;const x=z(()=>k.value.filter(t=>t.status==="running")),b=z(()=>k.value.filter(t=>t.status==="pending")),y=z(()=>k.value.filter(t=>t.status==="completed"||t.status==="failed"||t.status==="timeout"));async function f(){const t=R();l.value=!0;try{const s=await t.sendRaw({type:"tasks-list"});s&&Array.isArray(s.tasks)&&(k.value=s.tasks)}catch{}finally{l.value=!1}}async function o(t){const s=R();try{await s.sendRaw({type:"tasks-stop",taskId:t})}catch{}finally{await f()}}const d=D(null);function m(t=5e3){v(),f(),u=setInterval(f,t),C()}function v(){u&&(clearInterval(u),u=null),e&&(e(),e=null)}function C(){const t=R();if(e)return;const s=S=>{S.type==="task:notification"&&S.payload?.task&&(d.value=S.payload.task,f(),setTimeout(()=>{d.value=null},8e3))};e=t.onRuntimeEvent(s)}function N(t){return!t||t<0?"-":t<1e3?`${t}ms`:t<6e4?`${(t/1e3).toFixed(1)}s`:`${(t/6e4).toFixed(1)}m`}function A(t){switch(t){case"running":return"processing";case"pending":return"default";case"completed":return"success";case"failed":return"error";case"timeout":return"warning";default:return"default"}}return{tasks:k,loading:l,running:x,pending:b,completed:y,lastNotification:d,fetchTasks:f,stopTask:o,startPolling:m,stopPolling:v,formatDuration:N,getStatusColor:A}}),U={__name:"Tasks",setup(k,{expose:l}){l();const u=V(),e=[{title:"状态",key:"status",width:90},{title:"描述",key:"description",ellipsis:!0},{title:"类型",dataIndex:"type",width:100},{title:"耗时",key:"duration",width:90},{title:"创建时间",key:"createdAt",width:180},{title:"结果",key:"result",ellipsis:!0},{title:"操作",key:"action",width:80}];function x(o){return o.status==="running"&&o.startedAt?u.formatDuration(Date.now()-o.startedAt):o.completedAt&&o.startedAt?u.formatDuration(o.completedAt-o.startedAt):"-"}function b(o){return o?new Date(o).toLocaleString():"-"}function y(o,d){return o?o.length>d?`${o.slice(0,d)}...`:o:""}P(()=>u.startPolling(5e3)),I(()=>u.stopPolling());const f={store:u,columns:e,getDuration:x,formatTime:b,truncate:y,onMounted:P,onUnmounted:I,get ReloadOutlined(){return E},get useTasksStore(){return V}};return Object.defineProperty(f,"__isScriptSetup",{enumerable:!1,value:!0}),f}},L={class:"page-header"},M={key:0,class:"error-text"},j={key:1},J={class:"task-header"},K={class:"task-desc"},Q={class:"task-id"},W={class:"task-meta"},Z=["title"],q={key:0,class:"error-text"},G={key:1,class:"success-text"},H={key:2,class:"muted-text"};function X(k,l,u,e,x,b){const y=p("a-button"),f=p("a-space"),o=p("a-alert"),d=p("a-statistic"),m=p("a-card"),v=p("a-col"),C=p("a-row"),N=p("a-tag"),A=p("a-table");return i(),c("div",null,[_("div",L,[l[3]||(l[3]=_("div",null,[_("h2",{class:"page-title"},"后台任务"),_("p",{class:"page-sub"},"查看后台任务队列、实时通知和任务执行结果。")],-1)),n(f,null,{default:a(()=>[n(y,{ghost:"",loading:e.store.loading,onClick:l[0]||(l[0]=t=>e.store.fetchTasks())},{icon:a(()=>[n(e.ReloadOutlined)]),default:a(()=>[l[2]||(l[2]=g(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),e.store.lastNotification?(i(),T(o,{key:0,type:e.store.lastNotification.status==="completed"?"success":"error","show-icon":"",closable:"",class:"banner",onClose:l[1]||(l[1]=t=>e.store.lastNotification=null)},{message:a(()=>[g(" 任务"+r(e.store.lastNotification.status==="completed"?"完成":"结束")+": "+r(e.store.lastNotification.description||e.store.lastNotification.id.slice(0,16)),1)]),description:a(()=>[e.store.lastNotification.error?(i(),c("span",M,r(e.store.lastNotification.error),1)):e.store.lastNotification.result?(i(),c("span",j,r(e.truncate(String(e.store.lastNotification.result),120)),1)):w("v-if",!0)]),_:1},8,["type"])):w("v-if",!0),n(C,{gutter:[16,16],class:"stats-row"},{default:a(()=>[n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"全部任务",value:e.store.tasks.length},null,8,["value"])]),_:1})]),_:1}),n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"运行中",value:e.store.running.length},null,8,["value"])]),_:1})]),_:1}),n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"等待中",value:e.store.pending.length},null,8,["value"])]),_:1})]),_:1}),n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"已完成",value:e.store.completed.length},null,8,["value"])]),_:1})]),_:1})]),_:1}),e.store.running.length>0?(i(),T(m,{key:1,title:"运行中的任务",class:"panel-card",size:"small"},{default:a(()=>[(i(!0),c(h,null,F(e.store.running,t=>(i(),c("div",{key:t.id,class:"task-item running"},[_("div",J,[n(N,{color:e.store.getStatusColor(t.status)},{default:a(()=>[g(r(t.status.toUpperCase()),1)]),_:2},1032,["color"]),_("span",K,r(t.description),1),_("span",Q,r(t.id.slice(0,16)),1)]),_("div",W,[_("span",null,"类型: "+r(t.type||"-"),1),_("span",null,"已运行: "+r(e.store.formatDuration(Date.now()-t.startedAt)),1),n(y,{size:"small",danger:"",onClick:s=>e.store.stopTask(t.id)},{default:a(()=>[...l[4]||(l[4]=[g("停止",-1)])]),_:1},8,["onClick"])])]))),128))]),_:1})):w("v-if",!0),n(m,{class:"panel-card"},{default:a(()=>[n(A,{columns:e.columns,"data-source":e.store.tasks,pagination:{pageSize:15,size:"small"},loading:e.store.loading,"row-key":"id",size:"small"},{bodyCell:a(({column:t,record:s})=>[t.key==="status"?(i(),T(N,{key:0,color:e.store.getStatusColor(s.status)},{default:a(()=>[g(r(s.status),1)]),_:2},1032,["color"])):t.key==="description"?(i(),c("span",{key:1,title:s.command},r(s.description),9,Z)):t.key==="duration"?(i(),c(h,{key:2},[g(r(e.getDuration(s)),1)],64)):t.key==="createdAt"?(i(),c(h,{key:3},[g(r(e.formatTime(s.createdAt)),1)],64)):t.key==="result"?(i(),c(h,{key:4},[s.error?(i(),c("span",q,r(e.truncate(s.error,60)),1)):s.result?(i(),c("span",G,r(e.truncate(String(s.result),60)),1)):(i(),c("span",H,"-"))],64)):t.key==="action"?(i(),c(h,{key:5},[s.status==="running"?(i(),T(y,{key:0,size:"small",danger:"",onClick:S=>e.store.stopTask(s.id)},{default:a(()=>[...l[5]||(l[5]=[g(" 停止 ",-1)])]),_:1},8,["onClick"])):w("v-if",!0)],64)):w("v-if",!0)]),_:1},8,["data-source","loading"])]),_:1})])}const et=O(U,[["render",X],["__scopeId","data-v-da5ff6a2"],["__file","/tmp/cc-web-panel-v2hnMt/repo/packages/web-panel/src/views/Tasks.vue"]]);export{et as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{O as r}from"./index-BItcSqan.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as o}from"./Row-Zb-EjmgQ.js";import{U as t}from"./index-BItcSqan.js";import"./vendor-BvqAck49.js";import"./responsiveObserve-BB_A8dBt.js";import"./useFlexGapSupport-BCIMPfq9.js";import"./styleChecker-vXAYhhjz.js";import"./index-CyJpmSHZ.js";import"./icons-DP3uiYxy.js";const l=t(o);export{l as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{C as o}from"./Col-D3DnfExY.js";import{U as t}from"./index-BItcSqan.js";import"./vendor-BvqAck49.js";import"./index-CyJpmSHZ.js";import"./icons-DP3uiYxy.js";const s=t(o);export{s as default};
|