chainlesschain 0.162.152 → 0.162.153
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-CVLVJS-Q.js → AIOps-CBilhs1R.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CJ2_GJsI.js → ActionButton-Cf-RnC5Y.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CZsmlTF8.js → Analytics-S8tkGhw0.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DREvMZ62.js → AppLayout-CNXI3Bw5.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-B4NR42w_.js → Audit-DF2zVFZ0.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CJFmf3In.js → Backup-CMEiwQZL.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Bh8_iUZY.js → BaseInput-rwLw4K70.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DEwKjIxV.js → Chat-C478H8u9.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BOqHkxK_.js → ChatBubbleRenderer-DNQsKN61.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DYWCqYI9.js → Checkbox-D-47X635.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BlXrfZAJ.js → Codegen-Cb9Ihed5.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DLPM22eX.js → Col-CQsdzczt.js} +1 -1
- package/src/assets/web-panel/assets/{Community-PFyzqijs.js → Community-DiqzeAy-.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-7DIfY5Wp.js → Compact-Bq-APyyF.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DF4CinPU.js → Compliance-Dnb1YxPr.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-B1J80Vcj.js → Cowork-CZljerdQ.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B7sx2OXX.js → Cron-gAdbZOq7.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-omLkxmu-.js → Crosschain-DMPGXttD.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B_7r7b5F.js → DID-C7dBDAv8.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cp7k3GZg.js → Dashboard-ByR4VcF8.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BCKO89Y8.js → Dropdown-Bc4tbiQN.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CNgTSsFZ.js → EmailListRenderer-BhUN2pDw.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DobM83JP.js → FamilyGuardDashboard-DpJuANCD.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-XVAYQIeu.js → Federation-BEm4TvcE.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DV5ka1KQ.js → FormItemContext-JnkPkhiC.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Dg5q-KpC.js → GenericCardRenderer-BfCzFUIC.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Dsn3Xhxf.js → Git-1c0MWpmD.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D06S4Qow.js → Governance-C_j3EBpv.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-nAvwxUXy.js → Inference-Cb7XRgtY.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CtqRP_rF.js → KnowledgeGraph-DoHPvHyK.js} +1 -1
- package/src/assets/web-panel/assets/Logs-CYriKpy-.js +2 -0
- package/src/assets/web-panel/assets/{Marketplace-CaeY23Kj.js → Marketplace-BT56-GD0.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-C2HHnwnE.js → McpTools-B6XX_wnZ.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CWBrdKlR.js → Memory-DRgNuaQc.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CBLQ8uCY.js → MobileBridge-B0qgvBN2.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-CRRfswf7.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-BXur-euo.js → Mtc-DnSFj9jw.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CpQSlOQC.js → MtcAudit-c0tuz1sm.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-DlFwdEOA.js → Multisig-CVLBGioX.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DSh7fevc.js → NLProgramming-CFaqmNbx.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Bv4NOVxg.js → Notes-BM_mNwU_.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CzHNnIfa.js → NotificationSettings-Sa1k3ReS.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-D7pHfKK4.js → OrderTableRenderer-lWzmtqBh.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-COzV01ed.js → Organization-C2blcq-P.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CYRZJb2_.js → Overflow-B3PwOJnK.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DFm49FE0.js → P2P-DaB9T6tb.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Ctr-6k5B.js → PdhVaultBrowser-BpEBZ72n.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-DXVrhFyv.js → Permissions-BTkWInyH.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BO5utpLK.js → PersonalDataHub-LHEwNmyL.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-C9irYCg7.js → Pipeline-DvWIxqH-.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-r13hrvoF.js → Privacy-BDbpBagU.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-PRKNPZZC.js → ProjectInit-DLeMDWWv.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-QvxM1ZDO.js → ProjectSettings-BK3NsxIz.js} +2 -2
- package/src/assets/web-panel/assets/Projects-BPWPg9zA.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DxbrccZ7.js → Providers-D2EvmPAd.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BMHVRxBX.js → QrScannerModal-DAcu2fNg.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Co3_ndAH.js → QuickAsk-B7U850Yt.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Cv3UWR6s.js → Recommend-bxNXLzOR.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-CSDsO2zA.js → RemoteSession-BsCjAfSJ.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-Bdj59vzM.js → Reputation-DZ9LPu-R.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CejfUjmo.js → Row-cIYkCB3Y.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-C83yKkvU.js → RssFeed-BxTNTtTp.js} +2 -2
- package/src/assets/web-panel/assets/{Search-Ck4l_VI3.js → Search-DSar6GhE.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DGIIEx6K.js → Security-oCbIGysL.js} +4 -4
- package/src/assets/web-panel/assets/{Services-Cj2aNAy3.js → Services-D8yojrNv.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Dlyy8akb.js → Skeleton-vTA6P1eL.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-C4aDa9Zh.js → Skills-BXLf_KgZ.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-tHd_Bauo.js → Sla-Cpwxzz__.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DI7R0Qgd.js → SpeechSettings-DcPN9kCb.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-OOxiPdsE.js → SyncSettings-DY0U5Vuj.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Nro_Ltg5.js → Tasks-DKu3-sZJ.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Bm7eSMWH.js → Templates-MD3nfWGm.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-B8F8eFvD.js → Tenant-DKVnyGXM.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-2oWhR7QF.js → Terminal-DQMIZfWf.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-GLnecmpd.js → TimelineRenderer-CugmNZTs.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CtpFyati.js → Tokens-Cjvlttu6.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DGkXZzbN.js → Trigger-CzNOEcoI.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-ClYZMkXN.js → Trust-D5jg9iPA.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C1AuEW5-.js → UkeySign-59bMlvxY.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DHa9ekSK.js → VideoEditing-DmCzSBqn.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CyQv8ZAN.js → Wallet-DoFe8V6W.js} +3 -3
- package/src/assets/web-panel/assets/{WebAuthn-DPxEEb5Y.js → WebAuthn-9POLER-w.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-C-fCM8Si.js → WorkflowEditor-cFQH0Og6.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BMu1Pk8B.js → chat-D3fR2NkZ.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DYPOXyWQ.js → colors-DiLEwE_P.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C5r_plPk.js → compact-item-CGfFDdic.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-9fWrWmuJ.js → createContext-BbIbOPL2.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-B6FRgsmP.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CjZM2-qE.js → hasIn-DqyWp63_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWwI0Jjd.js → index-BCoDp6o_.js} +1 -1
- package/src/assets/web-panel/assets/{index-Co9kBFxY.js → index-BKeRBUtO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjTB4wPn.js → index-BKxvHCqz.js} +1 -1
- package/src/assets/web-panel/assets/{index-B56CI20h.js → index-BiLP6SNu.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNxR1CHs.js → index-BtcjYHgn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CcDGi9U1.js → index-BtwvOuvO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJJx0kbR.js → index-ByE5tKjP.js} +1 -1
- package/src/assets/web-panel/assets/{index-phHPSXlV.js → index-C1S30j-Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsHmE__1.js → index-C2lZXIEA.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLCoKst9.js → index-CH8gSMSA.js} +1 -1
- package/src/assets/web-panel/assets/{index-jO4lIpFE.js → index-CHpI6g_S.js} +1 -1
- package/src/assets/web-panel/assets/{index-0DVMoDzF.js → index-CIleIMTT.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bti4lpw5.js → index-CToOzfR2.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6zyUpD6.js → index-CZQshOyI.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0rFX-xN.js → index-ComvO4hy.js} +1 -1
- package/src/assets/web-panel/assets/index-Cq411qtc.js +1 -0
- package/src/assets/web-panel/assets/{index-BPucc_ES.js → index-CweXQM71.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTnaRErh.js → index-CySlHabI.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_bTdeou.js → index-D16FSRMW.js} +1 -1
- package/src/assets/web-panel/assets/index-D1oX0DK3.js +1 -0
- package/src/assets/web-panel/assets/{index-Du-w2i6G.js → index-D3vQv3Kq.js} +1 -1
- package/src/assets/web-panel/assets/{index-I3Qdrfcf.js → index-DH6qaU1a.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd9_KCPs.js → index-DPxmTldu.js} +1 -1
- package/src/assets/web-panel/assets/{index-Mipa7XgU.js → index-DQH--Uw5.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBVCXmJV.js → index-Db9UJVjj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDaA4A0b.js → index-DdLwxj-F.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyUtBxnC.js → index-DdjXemK-.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByVDaARk.js → index-DzuGkFvy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVFtY8Y4.js → index-FFlp8Jx9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJk9cPrs.js → index-Km36XQ3z.js} +1 -1
- package/src/assets/web-panel/assets/{index-BW-x3mUK.js → index-auI9fxYH.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1iUe3Ba.js → index-fCfaVIr7.js} +1 -1
- package/src/assets/web-panel/assets/{index-HJdfPSMz.js → index-hVGbmc7y.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYoS2cwK.js → index-kL8f4MRS.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3E7xVl1.js → index-ns6bNnGo.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bglw_kmu.js → index-qHvMk0U3.js} +1 -1
- package/src/assets/web-panel/assets/{index-CvUR6l7C.js → index-rTrejDjk.js} +1 -1
- package/src/assets/web-panel/assets/{index-oerotzoq.js → index-tLaW5UzZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGqrVLWe.js → index-xm1KHUEQ.js} +3 -3
- package/src/assets/web-panel/assets/{initDefaultProps-B7tpABc_.js → initDefaultProps-pg_7pnd6.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DmvaRoVv.js → motion-B5GoJSZL.js} +1 -1
- package/src/assets/web-panel/assets/{move-DF4X29Wf.js → move-BaJoe2FW.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-C0cbg4PO.js → mtc-parser-CiQGbqtr.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DZzcYy0l.js → omit-BFNEsKvU.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DaZWfzuH.js → pickAttrs-YbSoANHm.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CBxOEyvn.js → placementArrow-C40MJPIH.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CGl8NIlO.js → responsiveObserve-LaVz2zF6.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Bv330MSZ.js → slide-BkSoAGxF.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DJVy5oEM.js → statusUtils-C4jWjohA.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BiY1H5ST.js → styleChecker-BGqeIh-m.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-D1sN2OlQ.js → useFlexGapSupport-JsR5NMrM.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DxxHawzW.js → useFs-DOiP38RR.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-C1HblLrD.js → usePersonalDataHub-C-nC0ymt.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Dex0jy4T.js → vnode-BalilHOU.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Bk1MScAD.js → zoom-DjUELqks.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/team.js +34 -0
- package/src/data/changelog.json +7 -2
- package/src/harness/mcp-client.js +115 -1
- package/src/lib/agent-team/team-runner.js +20 -0
- package/src/lib/config-manager.js +14 -1
- package/src/lib/sub-agent-context.js +28 -7
- package/src/lib/telemetry/span-recorder.js +13 -1
- package/src/repl/agent-repl.js +52 -13
- package/src/repl/permission-prompt.js +58 -0
- package/src/runtime/agent-core.js +236 -1
- package/src/runtime/coding-agent-contract-shared.cjs +5 -0
- package/src/assets/web-panel/assets/Logs-J5aGAyfY.js +0 -2
- package/src/assets/web-panel/assets/MobileProjects-Q_Cy_W4_.js +0 -1
- package/src/assets/web-panel/assets/Projects-DfgmsN3j.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DmRz5Pet.js +0 -1
- package/src/assets/web-panel/assets/index-CrsL7YBW.js +0 -1
- package/src/assets/web-panel/assets/index-zW69WSDA.js +0 -1
|
@@ -336,13 +336,19 @@ export class SubAgentContext {
|
|
|
336
336
|
|
|
337
337
|
// Check abort signal
|
|
338
338
|
if (this._signal?.aborted) {
|
|
339
|
-
this.forceComplete("cancelled"
|
|
339
|
+
this.forceComplete("cancelled", {
|
|
340
|
+
partialContent: lastContent,
|
|
341
|
+
artifacts,
|
|
342
|
+
});
|
|
340
343
|
break;
|
|
341
344
|
}
|
|
342
345
|
|
|
343
346
|
// Enforce token budget
|
|
344
347
|
if (this.tokenBudget && this._tokenCount >= this.tokenBudget) {
|
|
345
|
-
this.forceComplete("token-budget-exceeded"
|
|
348
|
+
this.forceComplete("token-budget-exceeded", {
|
|
349
|
+
partialContent: lastContent,
|
|
350
|
+
artifacts,
|
|
351
|
+
});
|
|
346
352
|
break;
|
|
347
353
|
}
|
|
348
354
|
|
|
@@ -355,9 +361,17 @@ export class SubAgentContext {
|
|
|
355
361
|
} catch (err) {
|
|
356
362
|
this.status = "failed";
|
|
357
363
|
this.completedAt = new Date().toISOString();
|
|
364
|
+
// Return partial work to the parent instead of discarding it: the
|
|
365
|
+
// summary is the only channel the parent model sees, so a mid-run API
|
|
366
|
+
// error (rate limit, network drop) must not erase what was already
|
|
367
|
+
// produced. Artifacts collected before the failure are kept as-is.
|
|
368
|
+
const partial =
|
|
369
|
+
lastContent && lastContent.length > 0
|
|
370
|
+
? `\n\nPartial output before failure:\n${this.summarize(lastContent)}`
|
|
371
|
+
: "";
|
|
358
372
|
this.result = {
|
|
359
|
-
summary: `Sub-agent failed: ${err.message}`,
|
|
360
|
-
artifacts
|
|
373
|
+
summary: `Sub-agent failed: ${err.message}${partial}`,
|
|
374
|
+
artifacts,
|
|
361
375
|
tokenCount: this._tokenCount,
|
|
362
376
|
toolsUsed: [...new Set(this._toolsUsed)],
|
|
363
377
|
iterationCount: this._iterationCount,
|
|
@@ -447,15 +461,22 @@ export class SubAgentContext {
|
|
|
447
461
|
/**
|
|
448
462
|
* Force-complete this sub-agent (e.g. on timeout or parent cancellation).
|
|
449
463
|
* @param {string} [reason] - Reason for force-completion
|
|
464
|
+
* @param {{partialContent?: string, artifacts?: Array}} [partial] - Work
|
|
465
|
+
* produced before the cutoff; returned to the parent instead of being
|
|
466
|
+
* discarded (a truncated run should still hand over what it has).
|
|
450
467
|
*/
|
|
451
|
-
forceComplete(reason = "forced") {
|
|
468
|
+
forceComplete(reason = "forced", partial = {}) {
|
|
452
469
|
if (this.status === "active") {
|
|
453
470
|
this.status = "completed";
|
|
454
471
|
this.completedAt = new Date().toISOString();
|
|
455
472
|
if (!this.result) {
|
|
473
|
+
const partialText =
|
|
474
|
+
partial.partialContent && partial.partialContent.length > 0
|
|
475
|
+
? `\n\nPartial output before cutoff:\n${this.summarize(partial.partialContent)}`
|
|
476
|
+
: "";
|
|
456
477
|
this.result = {
|
|
457
|
-
summary: `(Sub-agent force-completed: ${reason})`,
|
|
458
|
-
artifacts: [],
|
|
478
|
+
summary: `(Sub-agent force-completed: ${reason})${partialText}`,
|
|
479
|
+
artifacts: Array.isArray(partial.artifacts) ? partial.artifacts : [],
|
|
459
480
|
tokenCount: this._tokenCount,
|
|
460
481
|
toolsUsed: [...new Set(this._toolsUsed)],
|
|
461
482
|
iterationCount: this._iterationCount,
|
|
@@ -41,15 +41,27 @@ export class TelemetryRecorder {
|
|
|
41
41
|
constructor({
|
|
42
42
|
now = () => Date.now(),
|
|
43
43
|
serviceName = "chainlesschain-cli",
|
|
44
|
+
defaultAttributes = {},
|
|
44
45
|
} = {}) {
|
|
45
46
|
this._now = typeof now === "function" ? now : () => now;
|
|
46
47
|
this.serviceName = serviceName;
|
|
47
48
|
this.traceId = newTraceId(); // one trace per recorder (valid non-zero id)
|
|
49
|
+
// Stamped onto EVERY span (per-span attributes win on key collision).
|
|
50
|
+
// Used for run-level correlation: workflow.run_id / workflow.name let a
|
|
51
|
+
// collector group all model/tool/task spans of one run (Claude-Code
|
|
52
|
+
// 2.1.202 workflow-tracing attributes).
|
|
53
|
+
this.defaultAttributes = { ...defaultAttributes };
|
|
48
54
|
this._spans = []; // completed spans
|
|
49
55
|
this._counters = new Map(); // name → { total, byAttr }
|
|
50
56
|
this._failures = new Map(); // category → count
|
|
51
57
|
}
|
|
52
58
|
|
|
59
|
+
/** Set (or overwrite) an attribute stamped onto every span from now on. */
|
|
60
|
+
setDefaultAttribute(key, value) {
|
|
61
|
+
this.defaultAttributes[key] = value;
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
53
65
|
/**
|
|
54
66
|
* Start a span. Returns a handle; call `.end()` (optionally with a status /
|
|
55
67
|
* extra attributes) to record it. Nesting is expressed via `parentId`.
|
|
@@ -57,7 +69,7 @@ export class TelemetryRecorder {
|
|
|
57
69
|
startSpan(name, attributes = {}, { parentId = null } = {}) {
|
|
58
70
|
const id = spanId();
|
|
59
71
|
const start = this._now();
|
|
60
|
-
const attrs = { ...attributes };
|
|
72
|
+
const attrs = { ...this.defaultAttributes, ...attributes };
|
|
61
73
|
const events = [];
|
|
62
74
|
const self = this;
|
|
63
75
|
let ended = false;
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -105,7 +105,11 @@ import { parseThinkCommand, parseEffortCommand } from "./think-command.js";
|
|
|
105
105
|
import { parseBtwCommand, buildAsideBlock, applyAside } from "./btw-command.js";
|
|
106
106
|
import { shouldStreamLive } from "./stream-decision.js";
|
|
107
107
|
import { emptyTurnNotice } from "./empty-turn-notice.js";
|
|
108
|
-
import {
|
|
108
|
+
import {
|
|
109
|
+
buildPermissionPrompt,
|
|
110
|
+
resolveAskIdleTimeoutMs,
|
|
111
|
+
questionWithIdleTimeout,
|
|
112
|
+
} from "./permission-prompt.js";
|
|
109
113
|
import {
|
|
110
114
|
parsePermissionTier,
|
|
111
115
|
describeTier,
|
|
@@ -425,11 +429,17 @@ export async function startAgentRepl(options = {}) {
|
|
|
425
429
|
// CC_AUTO_PIN env ("1"/"0") > config `context.autoPin` (true/false/object) >
|
|
426
430
|
// default on. See resolveAutoPinOption.
|
|
427
431
|
let _autoPinCfgValue;
|
|
432
|
+
// Idle timeout for interactive permission prompts (0 = wait forever).
|
|
433
|
+
// CC_PERMISSION_ASK_TIMEOUT_MS env > config permissions.askTimeoutMs > off.
|
|
434
|
+
let _askIdleTimeoutMs = resolveAskIdleTimeoutMs();
|
|
428
435
|
try {
|
|
429
436
|
const { loadConfig } = await import("../lib/config-manager.js");
|
|
430
437
|
const _cfg = loadConfig();
|
|
431
438
|
_visionModel = _cfg?.llm?.visionModel || undefined;
|
|
432
439
|
_autoPinCfgValue = _cfg?.context?.autoPin;
|
|
440
|
+
_askIdleTimeoutMs = resolveAskIdleTimeoutMs({
|
|
441
|
+
config: _cfg?.permissions?.askTimeoutMs,
|
|
442
|
+
});
|
|
433
443
|
const raw = _cfg?.llm?.streamStallTimeoutMs;
|
|
434
444
|
const t = Number(raw);
|
|
435
445
|
// Accept 0 (explicit disable) — only ignore absent/invalid values.
|
|
@@ -559,17 +569,24 @@ export async function startAgentRepl(options = {}) {
|
|
|
559
569
|
});
|
|
560
570
|
const q = (p) => new Promise((res) => rlConfirm.question(p, res));
|
|
561
571
|
const cmd = args?.command ? ` ${args.command}` : "";
|
|
562
|
-
const
|
|
563
|
-
|
|
572
|
+
const res = await questionWithIdleTimeout(
|
|
573
|
+
q,
|
|
574
|
+
chalk.yellow(
|
|
575
|
+
`\n[ApprovalGate] ${riskLevel || "medium"} risk command:${cmd}\n` +
|
|
576
|
+
` Proceed? [y]es once / [a]lways allow / [N]o: `,
|
|
577
|
+
),
|
|
578
|
+
_askIdleTimeoutMs,
|
|
579
|
+
);
|
|
580
|
+
rlConfirm.close();
|
|
581
|
+
if (res.timedOut) {
|
|
582
|
+
process.stdout.write(
|
|
564
583
|
chalk.yellow(
|
|
565
|
-
`\n
|
|
566
|
-
` Proceed? [y]es once / [a]lways allow / [N]o: `,
|
|
584
|
+
`\n ⏱ no response in ${_askIdleTimeoutMs}ms — auto-denied\n`,
|
|
567
585
|
),
|
|
568
|
-
)
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
rlConfirm.close();
|
|
586
|
+
);
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
const ans = res.answer.trim().toLowerCase();
|
|
573
590
|
if (ans === "a" || ans === "always") {
|
|
574
591
|
const saved = await _persistAlwaysAllow(tool || "run_shell", args);
|
|
575
592
|
if (saved) {
|
|
@@ -625,10 +642,21 @@ export async function startAgentRepl(options = {}) {
|
|
|
625
642
|
// (settings/hook ask) or a `reason` (destructive-git / sensitive-file
|
|
626
643
|
// guards) — avoids the literal "null" the old template printed.
|
|
627
644
|
const header = buildPermissionPrompt({ tool, args, rule, reason });
|
|
628
|
-
const
|
|
629
|
-
|
|
630
|
-
.
|
|
645
|
+
const res = await questionWithIdleTimeout(
|
|
646
|
+
q,
|
|
647
|
+
chalk.yellow(`\n${header}\n Proceed? (y/N) `),
|
|
648
|
+
_askIdleTimeoutMs,
|
|
649
|
+
);
|
|
631
650
|
rl.close();
|
|
651
|
+
if (res.timedOut) {
|
|
652
|
+
process.stdout.write(
|
|
653
|
+
chalk.yellow(
|
|
654
|
+
`\n ⏱ no response in ${_askIdleTimeoutMs}ms — auto-denied\n`,
|
|
655
|
+
),
|
|
656
|
+
);
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
const ans = res.answer.trim().toLowerCase();
|
|
632
660
|
return ans === "y" || ans === "yes";
|
|
633
661
|
};
|
|
634
662
|
} catch (_err) {
|
|
@@ -2383,6 +2411,17 @@ export async function startAgentRepl(options = {}) {
|
|
|
2383
2411
|
const expanded = target.replace(/^~(?=$|[\\/])/, os.homedir());
|
|
2384
2412
|
process.chdir(path.resolve(process.cwd(), expanded));
|
|
2385
2413
|
logger.log(chalk.green(`cwd → ${process.cwd()}`));
|
|
2414
|
+
// MCP roots derive from cwd — tell connected servers to re-query
|
|
2415
|
+
// roots/list (Claude-Code 2.1.203 change-notification parity).
|
|
2416
|
+
for (const c of [_adhocMcp?.mcpClient, _bundleMcpClient]) {
|
|
2417
|
+
if (c && typeof c.notifyRootsListChanged === "function") {
|
|
2418
|
+
try {
|
|
2419
|
+
c.notifyRootsListChanged();
|
|
2420
|
+
} catch {
|
|
2421
|
+
/* best-effort */
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2386
2425
|
} catch (err) {
|
|
2387
2426
|
logger.error(`/cd failed: ${err.message}`);
|
|
2388
2427
|
}
|
|
@@ -24,3 +24,61 @@ export function buildPermissionPrompt({ tool, args, rule, reason } = {}) {
|
|
|
24
24
|
if (reason) return `[Permission] ${reason}`;
|
|
25
25
|
return `[Permission] confirm ${tool}:${detail}`;
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the idle timeout (ms) for interactive permission prompts.
|
|
30
|
+
*
|
|
31
|
+
* An unanswered prompt blocks the whole agent turn forever (e.g. the user
|
|
32
|
+
* walked away mid-run). With a timeout configured, the prompt auto-denies
|
|
33
|
+
* after `ms` of silence — deny is the only safe unattended answer.
|
|
34
|
+
*
|
|
35
|
+
* Precedence: CC_PERMISSION_ASK_TIMEOUT_MS env > config
|
|
36
|
+
* `permissions.askTimeoutMs` > default 0 (disabled — waits forever, the
|
|
37
|
+
* historical behavior). Non-finite / non-positive values disable it.
|
|
38
|
+
*
|
|
39
|
+
* @param {{env?: string, config?: unknown}} [opts] - injectable for tests
|
|
40
|
+
* @returns {number} timeout in ms, 0 = disabled
|
|
41
|
+
*/
|
|
42
|
+
export function resolveAskIdleTimeoutMs({ env, config } = {}) {
|
|
43
|
+
const envRaw =
|
|
44
|
+
env !== undefined ? env : process.env.CC_PERMISSION_ASK_TIMEOUT_MS;
|
|
45
|
+
const candidate =
|
|
46
|
+
envRaw !== undefined && envRaw !== null && envRaw !== ""
|
|
47
|
+
? Number(envRaw)
|
|
48
|
+
: typeof config === "number" || typeof config === "string"
|
|
49
|
+
? Number(config)
|
|
50
|
+
: NaN; // booleans/objects are not a timeout — disabled
|
|
51
|
+
return Number.isFinite(candidate) && candidate > 0 ? candidate : 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Race an interactive question against an idle timeout.
|
|
56
|
+
*
|
|
57
|
+
* `ask` is the readline-question-as-promise (never rejects). On timeout the
|
|
58
|
+
* caller must still close its readline interface; the stranded question
|
|
59
|
+
* callback becomes a no-op once the interface is closed.
|
|
60
|
+
*
|
|
61
|
+
* @param {(prompt: string) => Promise<string>} ask
|
|
62
|
+
* @param {string} prompt
|
|
63
|
+
* @param {number} timeoutMs - 0/negative = no timeout (plain await)
|
|
64
|
+
* @returns {Promise<{answer: string|null, timedOut: boolean}>}
|
|
65
|
+
*/
|
|
66
|
+
export async function questionWithIdleTimeout(ask, prompt, timeoutMs) {
|
|
67
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
68
|
+
return { answer: await ask(prompt), timedOut: false };
|
|
69
|
+
}
|
|
70
|
+
let timer = null;
|
|
71
|
+
try {
|
|
72
|
+
return await Promise.race([
|
|
73
|
+
ask(prompt).then((answer) => ({ answer, timedOut: false })),
|
|
74
|
+
new Promise((res) => {
|
|
75
|
+
timer = setTimeout(
|
|
76
|
+
() => res({ answer: null, timedOut: true }),
|
|
77
|
+
timeoutMs,
|
|
78
|
+
);
|
|
79
|
+
}),
|
|
80
|
+
]);
|
|
81
|
+
} finally {
|
|
82
|
+
if (timer) clearTimeout(timer);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -1443,6 +1443,8 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1443
1443
|
subAgentBudget: context.subAgentBudget || null,
|
|
1444
1444
|
interactiveApproval: context.interactiveApproval || false,
|
|
1445
1445
|
settingsHooks: context.settingsHooks || null,
|
|
1446
|
+
signal: context.signal || null,
|
|
1447
|
+
backgroundSubAgents: context.backgroundSubAgents || null,
|
|
1446
1448
|
});
|
|
1447
1449
|
} catch (err) {
|
|
1448
1450
|
if (hookDb) {
|
|
@@ -1541,7 +1543,10 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1541
1543
|
name === "spawn_sub_agent" &&
|
|
1542
1544
|
context.settingsHooks &&
|
|
1543
1545
|
toolResult &&
|
|
1544
|
-
typeof toolResult === "object"
|
|
1546
|
+
typeof toolResult === "object" &&
|
|
1547
|
+
// Background spawns return a "running" handle here — their SubagentStop
|
|
1548
|
+
// fires later, when the RESULT is drained into the conversation.
|
|
1549
|
+
!(toolResult.background === true && toolResult.status === "running")
|
|
1545
1550
|
) {
|
|
1546
1551
|
try {
|
|
1547
1552
|
const outcome = runObserveHooks(
|
|
@@ -2056,6 +2061,8 @@ async function executeToolInner(
|
|
|
2056
2061
|
subAgentBudget = null,
|
|
2057
2062
|
interactiveApproval = false,
|
|
2058
2063
|
settingsHooks = null,
|
|
2064
|
+
signal = null,
|
|
2065
|
+
backgroundSubAgents = null,
|
|
2059
2066
|
},
|
|
2060
2067
|
) {
|
|
2061
2068
|
const localToolDescriptor =
|
|
@@ -2777,6 +2784,8 @@ async function executeToolInner(
|
|
|
2777
2784
|
subAgentDepth,
|
|
2778
2785
|
subAgentBudget,
|
|
2779
2786
|
settingsHooks,
|
|
2787
|
+
signal,
|
|
2788
|
+
backgroundSubAgents,
|
|
2780
2789
|
}),
|
|
2781
2790
|
);
|
|
2782
2791
|
}
|
|
@@ -3703,6 +3712,46 @@ export function safeStringifyToolResult(value) {
|
|
|
3703
3712
|
* @param {object} ctx - { skillLoader, cwd, parentMessages, interaction, sessionId }
|
|
3704
3713
|
* @returns {Promise<object>}
|
|
3705
3714
|
*/
|
|
3715
|
+
/**
|
|
3716
|
+
* Remove and return every SETTLED background sub-agent entry from the run's
|
|
3717
|
+
* map. Called by agentLoop before each LLM call (deliver fresh results) and
|
|
3718
|
+
* after the end-of-run wait (deliver stragglers).
|
|
3719
|
+
*/
|
|
3720
|
+
function _takeSettledBackgroundSubAgents(map) {
|
|
3721
|
+
const done = [];
|
|
3722
|
+
for (const [id, entry] of map) {
|
|
3723
|
+
if (entry.settled) {
|
|
3724
|
+
done.push(entry);
|
|
3725
|
+
map.delete(id);
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
return done;
|
|
3729
|
+
}
|
|
3730
|
+
|
|
3731
|
+
/**
|
|
3732
|
+
* Render a settled background sub-agent's outcome as the user-role message
|
|
3733
|
+
* injected into the parent conversation (the only channel that reaches the
|
|
3734
|
+
* model between turns — there is no open tool_call to attach a result to).
|
|
3735
|
+
*/
|
|
3736
|
+
function _backgroundSubAgentResultText(entry) {
|
|
3737
|
+
const o = entry.outcome || {};
|
|
3738
|
+
const status = o.error ? "FAILED" : "completed";
|
|
3739
|
+
const summary =
|
|
3740
|
+
(o.result && o.result.summary) || o.error || "(no output from sub-agent)";
|
|
3741
|
+
const tools =
|
|
3742
|
+
o.result && Array.isArray(o.result.toolsUsed) && o.result.toolsUsed.length
|
|
3743
|
+
? `\nTools used: ${o.result.toolsUsed.join(", ")}`
|
|
3744
|
+
: "";
|
|
3745
|
+
const feedback = entry.hookFeedback
|
|
3746
|
+
? `\nHook feedback: ${entry.hookFeedback}`
|
|
3747
|
+
: "";
|
|
3748
|
+
return (
|
|
3749
|
+
`[Background sub-agent "${entry.role}" (${entry.id}) ${status}]\n` +
|
|
3750
|
+
`Task: ${entry.task}\n` +
|
|
3751
|
+
`Result:\n${summary}${tools}${feedback}`
|
|
3752
|
+
);
|
|
3753
|
+
}
|
|
3754
|
+
|
|
3706
3755
|
async function _executeSpawnSubAgent(args, ctx) {
|
|
3707
3756
|
// Nesting cap: refuse before any context/registry work.
|
|
3708
3757
|
const currentDepth = ctx.subAgentDepth || 0;
|
|
@@ -3897,6 +3946,88 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
3897
3946
|
}
|
|
3898
3947
|
}
|
|
3899
3948
|
|
|
3949
|
+
// ── Background mode (Claude-Code 2.1.198 parity) ────────────────────────
|
|
3950
|
+
// Return a running handle immediately; the parent loop keeps working and
|
|
3951
|
+
// drains the result into the conversation when it settles (agentLoop also
|
|
3952
|
+
// refuses to finish while any background sub-agent is still running). Only
|
|
3953
|
+
// available when the calling loop provided the per-run map — a bare
|
|
3954
|
+
// executeTool() without it falls through to the blocking path.
|
|
3955
|
+
if (args.background === true && ctx.backgroundSubAgents instanceof Map) {
|
|
3956
|
+
// Cancel with the parent: forward the loop's abort signal so killing the
|
|
3957
|
+
// run doesn't orphan a detached child mid-LLM-call.
|
|
3958
|
+
subCtx._signal = subCtx._signal || ctx.signal || null;
|
|
3959
|
+
if (registry) {
|
|
3960
|
+
try {
|
|
3961
|
+
registry.register(subCtx);
|
|
3962
|
+
} catch (_err) {
|
|
3963
|
+
// Registry not available — non-critical
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
emit("sub-agent.started", {
|
|
3967
|
+
task: subCtx.task,
|
|
3968
|
+
background: true,
|
|
3969
|
+
allowedTools: allowedTools || null,
|
|
3970
|
+
maxIterations: subCtx.maxIterations,
|
|
3971
|
+
createdAt: subCtx.createdAt,
|
|
3972
|
+
});
|
|
3973
|
+
const entry = {
|
|
3974
|
+
id: subCtx.id,
|
|
3975
|
+
role: subCtx.role,
|
|
3976
|
+
task: subCtx.task,
|
|
3977
|
+
settled: false,
|
|
3978
|
+
outcome: null,
|
|
3979
|
+
hookFeedback: null,
|
|
3980
|
+
promise: null,
|
|
3981
|
+
};
|
|
3982
|
+
// Settle-capture wrapper: the stored promise NEVER rejects, so an
|
|
3983
|
+
// unconsumed handle can't surface as an unhandled rejection.
|
|
3984
|
+
entry.promise = subCtx
|
|
3985
|
+
.run(task)
|
|
3986
|
+
.then(
|
|
3987
|
+
(result) => ({ result, error: null }),
|
|
3988
|
+
(err) => {
|
|
3989
|
+
subCtx.forceComplete(err.message);
|
|
3990
|
+
return { result: subCtx.result, error: err.message };
|
|
3991
|
+
},
|
|
3992
|
+
)
|
|
3993
|
+
.then((outcome) => {
|
|
3994
|
+
entry.settled = true;
|
|
3995
|
+
entry.outcome = outcome;
|
|
3996
|
+
if (registry) {
|
|
3997
|
+
try {
|
|
3998
|
+
registry.complete(subCtx.id, outcome.result);
|
|
3999
|
+
} catch (_err) {
|
|
4000
|
+
// Non-critical
|
|
4001
|
+
}
|
|
4002
|
+
}
|
|
4003
|
+
emit(outcome.error ? "sub-agent.failed" : "sub-agent.completed", {
|
|
4004
|
+
status: subCtx.status,
|
|
4005
|
+
background: true,
|
|
4006
|
+
...(outcome.error
|
|
4007
|
+
? { error: outcome.error }
|
|
4008
|
+
: {
|
|
4009
|
+
summary: outcome.result?.summary,
|
|
4010
|
+
toolsUsed: outcome.result?.toolsUsed,
|
|
4011
|
+
iterationCount: outcome.result?.iterationCount,
|
|
4012
|
+
tokenCount: outcome.result?.tokenCount,
|
|
4013
|
+
artifactCount: outcome.result?.artifacts?.length || 0,
|
|
4014
|
+
}),
|
|
4015
|
+
completedAt: subCtx.completedAt,
|
|
4016
|
+
});
|
|
4017
|
+
return outcome;
|
|
4018
|
+
});
|
|
4019
|
+
ctx.backgroundSubAgents.set(subCtx.id, entry);
|
|
4020
|
+
return {
|
|
4021
|
+
success: true,
|
|
4022
|
+
background: true,
|
|
4023
|
+
status: "running",
|
|
4024
|
+
subAgentId: subCtx.id,
|
|
4025
|
+
role: subCtx.role,
|
|
4026
|
+
parentSessionId,
|
|
4027
|
+
note: "Sub-agent is running in the background. Its result will be delivered to you automatically in a later turn — continue with other work; the run will not finish before the result arrives.",
|
|
4028
|
+
};
|
|
4029
|
+
}
|
|
4030
|
+
|
|
3900
4031
|
try {
|
|
3901
4032
|
// Notify registry if available
|
|
3902
4033
|
if (registry) {
|
|
@@ -5385,7 +5516,17 @@ export async function* agentLoop(messages, options) {
|
|
|
5385
5516
|
spawned: 0,
|
|
5386
5517
|
max: MAX_SUB_AGENTS_PER_RUN,
|
|
5387
5518
|
},
|
|
5519
|
+
// Abort signal — forwarded to background sub-agents so cancelling the
|
|
5520
|
+
// parent run also cancels children still running detached.
|
|
5521
|
+
signal,
|
|
5522
|
+
// Background sub-agents spawned THIS loop (spawn_sub_agent background:true).
|
|
5523
|
+
// id → { id, role, task, promise, settled, outcome }. Results are drained
|
|
5524
|
+
// into `messages` before each LLM call; the loop refuses to finish while
|
|
5525
|
+
// any are still running (it waits, injects, and gives the model one more
|
|
5526
|
+
// turn) so a background result can never be silently lost.
|
|
5527
|
+
backgroundSubAgents: new Map(),
|
|
5388
5528
|
};
|
|
5529
|
+
const backgroundSubAgents = toolContext.backgroundSubAgents;
|
|
5389
5530
|
|
|
5390
5531
|
throwIfAborted(signal);
|
|
5391
5532
|
|
|
@@ -5490,6 +5631,18 @@ export async function* agentLoop(messages, options) {
|
|
|
5490
5631
|
const runId =
|
|
5491
5632
|
options.runId ||
|
|
5492
5633
|
`run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
5634
|
+
// Workflow-tracing attributes (Claude-Code 2.1.202): stamp the run id (and
|
|
5635
|
+
// an optional caller-provided workflow name) onto EVERY span this run emits,
|
|
5636
|
+
// so a collector can group one run's model/tool spans into one workflow.
|
|
5637
|
+
if (recorder && typeof recorder.setDefaultAttribute === "function") {
|
|
5638
|
+
recorder.setDefaultAttribute("workflow.run_id", runId);
|
|
5639
|
+
if (options.workflowName) {
|
|
5640
|
+
recorder.setDefaultAttribute(
|
|
5641
|
+
"workflow.name",
|
|
5642
|
+
String(options.workflowName),
|
|
5643
|
+
);
|
|
5644
|
+
}
|
|
5645
|
+
}
|
|
5493
5646
|
yield {
|
|
5494
5647
|
type: "run-started",
|
|
5495
5648
|
runId,
|
|
@@ -5657,6 +5810,52 @@ export async function* agentLoop(messages, options) {
|
|
|
5657
5810
|
}
|
|
5658
5811
|
}
|
|
5659
5812
|
|
|
5813
|
+
// Deliver background sub-agent results that settled since the last turn:
|
|
5814
|
+
// inject them as user-role context so THIS LLM call sees them. (There is
|
|
5815
|
+
// no open tool_call to attach a late result to — the spawn call already
|
|
5816
|
+
// returned its "running" handle.)
|
|
5817
|
+
if (backgroundSubAgents.size > 0) {
|
|
5818
|
+
for (const entry of _takeSettledBackgroundSubAgents(
|
|
5819
|
+
backgroundSubAgents,
|
|
5820
|
+
)) {
|
|
5821
|
+
// SubagentStop fires at RESULT time for background spawns (the
|
|
5822
|
+
// spawn-time handle skips it); a block reason rides along as feedback.
|
|
5823
|
+
if (options.settingsHooks) {
|
|
5824
|
+
try {
|
|
5825
|
+
const outcome = runObserveHooks(
|
|
5826
|
+
options.settingsHooks,
|
|
5827
|
+
"SubagentStop",
|
|
5828
|
+
{
|
|
5829
|
+
stop_hook_active: false,
|
|
5830
|
+
session_id: options.sessionId || null,
|
|
5831
|
+
subagent_response: JSON.stringify(
|
|
5832
|
+
entry.outcome?.result || { error: entry.outcome?.error },
|
|
5833
|
+
).substring(0, 2000),
|
|
5834
|
+
},
|
|
5835
|
+
{ cwd: toolContext.cwd },
|
|
5836
|
+
);
|
|
5837
|
+
if (outcome.decision === "block" && outcome.reason) {
|
|
5838
|
+
entry.hookFeedback = outcome.reason;
|
|
5839
|
+
}
|
|
5840
|
+
} catch (_err) {
|
|
5841
|
+
// SubagentStop hooks are best-effort
|
|
5842
|
+
}
|
|
5843
|
+
}
|
|
5844
|
+
messages.push({
|
|
5845
|
+
role: "user",
|
|
5846
|
+
content: _backgroundSubAgentResultText(entry),
|
|
5847
|
+
});
|
|
5848
|
+
yield {
|
|
5849
|
+
type: "background-sub-agent-result",
|
|
5850
|
+
runId,
|
|
5851
|
+
subAgentId: entry.id,
|
|
5852
|
+
role: entry.role,
|
|
5853
|
+
error: entry.outcome?.error || null,
|
|
5854
|
+
summary: entry.outcome?.result?.summary || null,
|
|
5855
|
+
};
|
|
5856
|
+
}
|
|
5857
|
+
}
|
|
5858
|
+
|
|
5660
5859
|
// Turn-scoped context injection (open-agents prepareCall parity).
|
|
5661
5860
|
// prepareCall runs fresh each iteration and returns an ephemeral
|
|
5662
5861
|
// system-message supplement that is NOT persisted to messages history.
|
|
@@ -5736,6 +5935,42 @@ export async function* agentLoop(messages, options) {
|
|
|
5736
5935
|
const toolCalls = msg.tool_calls;
|
|
5737
5936
|
|
|
5738
5937
|
if (!toolCalls || toolCalls.length === 0) {
|
|
5938
|
+
// A final answer while background sub-agents are still outstanding is
|
|
5939
|
+
// premature — their results must not be silently lost. Wait for ALL of
|
|
5940
|
+
// them, inject the results, and give the model one more turn to fold
|
|
5941
|
+
// them into its real final answer. The iteration budget is the backstop
|
|
5942
|
+
// if it keeps spawning more.
|
|
5943
|
+
if (backgroundSubAgents.size > 0) {
|
|
5944
|
+
yield {
|
|
5945
|
+
type: "waiting-background-sub-agents",
|
|
5946
|
+
runId,
|
|
5947
|
+
count: backgroundSubAgents.size,
|
|
5948
|
+
};
|
|
5949
|
+
await Promise.all(
|
|
5950
|
+
[...backgroundSubAgents.values()].map((e) => e.promise),
|
|
5951
|
+
);
|
|
5952
|
+
throwIfAborted(signal);
|
|
5953
|
+
messages.push({ role: "assistant", content: msg.content || "" });
|
|
5954
|
+
for (const entry of _takeSettledBackgroundSubAgents(
|
|
5955
|
+
backgroundSubAgents,
|
|
5956
|
+
)) {
|
|
5957
|
+
messages.push({
|
|
5958
|
+
role: "user",
|
|
5959
|
+
content:
|
|
5960
|
+
_backgroundSubAgentResultText(entry) +
|
|
5961
|
+
"\n\nAll background sub-agents have finished. Incorporate their results and give your final answer.",
|
|
5962
|
+
});
|
|
5963
|
+
yield {
|
|
5964
|
+
type: "background-sub-agent-result",
|
|
5965
|
+
runId,
|
|
5966
|
+
subAgentId: entry.id,
|
|
5967
|
+
role: entry.role,
|
|
5968
|
+
error: entry.outcome?.error || null,
|
|
5969
|
+
summary: entry.outcome?.result?.summary || null,
|
|
5970
|
+
};
|
|
5971
|
+
}
|
|
5972
|
+
continue;
|
|
5973
|
+
}
|
|
5739
5974
|
// Surface the final answer's extended-thinking reasoning (Anthropic, when
|
|
5740
5975
|
// --think is on) so non-streaming consumers (the REPL) can show it. The
|
|
5741
5976
|
// streaming path forwards reasoning live via onThinking instead.
|
|
@@ -588,6 +588,11 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
588
588
|
description:
|
|
589
589
|
"Optional declarative profile (from sub-agent-profiles). When set, seeds systemPrompt / tool allowlist / iteration cap. Explicit `tools` overrides the profile allowlist.",
|
|
590
590
|
},
|
|
591
|
+
background: {
|
|
592
|
+
type: "boolean",
|
|
593
|
+
description:
|
|
594
|
+
"Run the sub-agent in the BACKGROUND: the call returns immediately with a running handle and you continue working; the sub-agent's result is delivered to you automatically in a later turn (the run waits for stragglers before finishing). Use for independent subtasks you don't need before your next step.",
|
|
595
|
+
},
|
|
591
596
|
},
|
|
592
597
|
required: ["task"],
|
|
593
598
|
},
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{I as s,J as g,U as d,c as n,K as _,V as k,S as W,R as S,F as K,Z as Q,w as M,n as C,o as R,b as T,r,P as p,Q as O,_ as U}from"./vendor-BMxUs6UX.js";import{_ as q,u as N}from"./index-CGqrVLWe.js";import{R as E}from"./icons-BsDmGpcT.js";const j={__name:"Logs",setup(V,{expose:a}){a();const x=N(),e=r("status"),y=r(!1),v=r(""),c=r(""),i=r(""),f=r(!0),o=r(null),h={status:"status",doctor:"doctor","skill-sources":"skill sources","llm-providers":"llm providers"},m=T(()=>c.value.split(`
|
|
2
|
-
`)),b=T(()=>{if(!i.value)return m.value;const t=i.value.toLowerCase();return m.value.filter(u=>u.toLowerCase().includes(t))});function L(t){return t.includes("✖")||t.includes("error")||t.includes("Error")||t.includes("failed")?"line-error":t.includes("✔")||t.includes("✓")||t.includes("success")||t.includes("running")?"line-success":t.includes("warn")||t.includes("Warn")||t.includes("○")?"line-warn":t.startsWith(" ")||t.startsWith(" ")?"line-indent":""}function l(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function w(t){if(!i.value)return t;const u=i.value.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return t.replace(new RegExp(`(${u})`,"gi"),"<mark>$1</mark>")}async function B(){y.value=!0,v.value="",c.value="";const t=h[e.value]||"status";try{const{output:u}=await x.execute(t,3e4);c.value=u,f.value&&(await C(),o.value&&(o.value.scrollTop=o.value.scrollHeight))}catch(u){v.value=`执行失败: ${u.message}`,c.value=v.value}finally{y.value=!1}}M(b,async()=>{f.value&&(await C(),o.value&&(o.value.scrollTop=o.value.scrollHeight))}),R(B);const H={ws:x,activeTab:e,loading:y,error:v,rawOutput:c,searchQuery:i,autoScroll:f,logContainer:o,TAB_COMMANDS:h,allLines:m,filteredLines:b,lineClass:L,escapeHtml:l,highlightSearch:w,loadLog:B,ref:r,computed:T,watch:M,nextTick:C,onMounted:R,get ReloadOutlined(){return E},get useWsStore(){return N}};return Object.defineProperty(H,"__isScriptSetup",{enumerable:!1,value:!0}),H}},z={style:{display:"flex","align-items":"center","justify-content":"space-between","margin-bottom":"24px"}},A={style:{display:"flex",gap:"10px",margin:"12px 0"}},D={ref:"logContainer",class:"log-box"},F={key:0,style:{"text-align":"center",padding:"40px",color:"var(--text-muted)"}},I={key:1,style:{"text-align":"center",padding:"40px",color:"var(--text-muted)"}},P={key:2},J=["innerHTML"];function Z(V,a,x,e,y,v){const c=s("a-checkbox"),i=s("a-button"),f=s("a-space"),o=s("a-tab-pane"),h=s("a-tabs"),m=s("a-input-search"),b=s("a-tag"),L=s("a-spin");return p(),g("div",null,[d("div",z,[a[5]||(a[5]=d("div",null,[d("h2",{class:"page-title"},"日志查看"),d("p",{class:"page-sub"},"系统运行日志与诊断输出")],-1)),n(f,null,{default:_(()=>[n(c,{checked:e.autoScroll,"onUpdate:checked":a[0]||(a[0]=l=>e.autoScroll=l)},{default:_(()=>[...a[3]||(a[3]=[O("自动滚动",-1)])]),_:1},8,["checked"]),n(i,{type:"primary",ghost:"",loading:e.loading,onClick:e.loadLog},{icon:_(()=>[n(e.ReloadOutlined)]),default:_(()=>[a[4]||(a[4]=O(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),k(" Tab Selector "),n(h,{activeKey:e.activeTab,"onUpdate:activeKey":a[1]||(a[1]=l=>e.activeTab=l),onChange:e.loadLog,style:{"margin-bottom":"0"}},{default:_(()=>[n(o,{key:"status",tab:"系统状态"}),n(o,{key:"doctor",tab:"环境诊断"}),n(o,{key:"skill-sources",tab:"技能来源"}),n(o,{key:"llm-providers",tab:"LLM 提供商"})]),_:1},8,["activeKey"]),k(" Search Bar "),d("div",A,[n(m,{value:e.searchQuery,"onUpdate:value":a[2]||(a[2]=l=>e.searchQuery=l),placeholder:"搜索日志内容...","allow-clear":"",style:{flex:"1"}},null,8,["value"]),e.filteredLines.length!==e.allLines.length?(p(),W(b,{key:0,color:"blue"},{default:_(()=>[O(S(e.filteredLines.length)+" / "+S(e.allLines.length)+" 行 ",1)]),_:1})):k("v-if",!0)]),k(" Log Output "),d("div",D,[e.loading?(p(),g("div",F,[n(L,{size:"large"}),a[6]||(a[6]=d("div",{style:{"margin-top":"10px"}},"加载中...",-1))])):e.filteredLines.length?(p(),g("div",P,[(p(!0),g(K,null,Q(e.filteredLines,(l,w)=>(p(),g("div",{key:w,class:U(["log-line",e.lineClass(l)]),innerHTML:e.highlightSearch(e.escapeHtml(l))},null,10,J))),128))])):(p(),g("div",I,S(e.error||"暂无日志内容,点击刷新加载"),1))],512)])}const $=q(j,[["render",Z],["__scopeId","data-v-8c2906e0"],["__file","/tmp/cc-web-panel-7Oqy5c/repo/packages/web-panel/src/views/Logs.vue"]]);export{$ as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as c,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-BMxUs6UX.js";import{_ as v,b as m}from"./index-CGqrVLWe.js";import{a7 as y,M}from"./icons-BsDmGpcT.js";const B={__name:"MobileProjects",setup(p,{expose:i}){i();const n=u(),{t:e}=m();function a(){n.push("/projects")}function _(){n.push("/mobile-bridge")}const s={router:n,t:e,goToProjects:a,goToMobileBridge:_,get useRouter(){return u},get useI18n(){return m},get MobileOutlined(){return M},get FolderOutlined(){return y}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}},O={class:"mobile-projects-placeholder"},x={class:"title"},k={class:"subtitle"},w={class:"explainer"};function T(p,i,n,e,a,_){const s=c("a-alert"),d=c("a-button"),f=c("a-space"),P=c("a-empty"),j=c("a-card");return h(),g("div",O,[l(j,null,{default:r(()=>[l(P,{description:!1},{image:r(()=>[l(e.MobileOutlined,{style:{fontSize:"64px",color:"#bfbfbf"}})]),default:r(()=>[o("h2",x,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-7Oqy5c/repo/packages/web-panel/src/views/MobileProjects.vue"]]);export{N as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as i,J as I,U,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-BMxUs6UX.js";import{_ as we,b as re,u as ie,d}from"./index-CGqrVLWe.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-BsDmGpcT.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),h=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"}],M=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,h.value=[];try{const f=await w("project.listFiles",{projectId:o.id,limit:200},`project list-files ${o.id} --json`,8e3);h.value=Array.isArray(f?.files)?f.files:[]}catch{h.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:""}),A=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:""},A.value=!0}async function N(){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);h.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 N(),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}'`),A.value=!1,await N(),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 N(),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 N()):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:h,filesLoading:k,createOpen:E,creating:L,newProject:F,columns:z,countByStatus:M,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:A,creatingFolder:m,newFolder:R,editFileOpen:n,editingFile:c,editFileContent:q,savingFile:Y,openCreateFile:ue,openCreateFolder:ce,refreshFiles:N,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"}},Ae={class:"page-title"},Ie={class:"page-sub"},Ue={class:"filter-bar",style:{"margin-bottom":"12px",display:"flex",gap:"12px","align-items":"center"}},he={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"),h=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"),M=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"),A=i("a-modal"),m=i("a-select-option"),R=i("a-select");return p(),I("div",null,[U("div",ze,[U("div",null,[U("h2",Ae,s(e.t("projects.title")),1),U("p",Ie,[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(h,{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 "),U("div",Ue,[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(),I("code",he,s(c.id.slice(0,8))+"…",1)):n.key==="name"?(p(),I(ne,{key:1},[U("strong",null,s(c.name),1),c.description?(p(),I("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(),I(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(M,{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(()=>[U("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(),I("code",Re,s(e.detail.root_path),1)):(p(),I("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(),I("span",Ee,s(n.file_size)+" B",1)):_("v-if",!0),t(M,{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(()=>[U("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(A,{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(A,{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(A,{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(A,{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-7Oqy5c/repo/packages/web-panel/src/views/Projects.vue"]]);export{We as default};
|