chainlesschain 0.162.130 → 0.162.131
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-DlBanM-D.js → AIOps-2KUTHQX_.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-yoBaBWJy.js → ActionButton-L7_IhqNu.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BmrOyYD0.js → Analytics-CUixECiG.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-GFuM9A3X.js → AppLayout-Dpe2haDQ.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-XknQ2_0O.js → Audit-CnRXY9qp.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-B1iEUtGw.js → Backup-C0JsfiNs.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Be6KNmhp.js → BaseInput-Cu__ZKoW.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DwsFF4yj.js → Chat-CBFYmY92.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Dw1_CWh4.js → ChatBubbleRenderer-Df45RqwP.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CJMgWRaw.js → Checkbox-Brs6y0pv.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DmUTxgww.js → Codegen-DvIDK2R6.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DKiqcZD4.js → Col-BY1bz9zm.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DwkBuQJ9.js → Community-Du0uBY_j.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-ClnINh4j.js → Compact-CxkCfnD4.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CiT8aABn.js → Compliance-DI4GSvYO.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CSdl80o1.js → Cowork-BaBiaYNG.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-EpM2_dN5.js → Cron-By787-AO.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-D0k0wjwX.js → Crosschain-D06BizgW.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CC4U6GEI.js → DID-CaE65NYK.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CxHIpA4F.js → Dashboard-BEk1ucNb.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-z6Y524uk.js → Dropdown-Depeqs8h.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Bs_NxIAQ.js → EmailListRenderer-BA1AKXFR.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BdMikomZ.js → FamilyGuardDashboard-BZFbC7Cx.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BaBybFmU.js → Federation-8yPwScKv.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-bOifggcW.js → FormItemContext-BVy_AKdW.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BEhi1SaZ.js → GenericCardRenderer-D7kFe3QM.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BoISA30j.js → Git-BI_taCzW.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D8XZcZmr.js → Governance-DIOg1O6M.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DF0zfQ35.js → Inference-CSL-isQ_.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Bx28A0s9.js → KnowledgeGraph-iCn8Fvmf.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CxP6elqM.js → Logs-YMjpW89s.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-BhyVR9xn.js → Marketplace--fNmNRri.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-TYU8DcM5.js → McpTools-DGaQOFxN.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-UDwDvKuv.js → Memory-DNjUfk5O.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DEa4DTPm.js → MobileBridge-Ce2Pn2oK.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BU-T_VO4.js → MobileProjects-DaNhq1_x.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-hYAzBWQi.js → Mtc-Htf1b8xE.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-0417bzil.js → MtcAudit-2IIu0OB3.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-C8mNrESc.js → Multisig-BMAUzfxj.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Cq73NSD-.js → NLProgramming-DsPldroh.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CuyXdYfG.js → Notes-COLd7vCP.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-4dP5jtLG.js → NotificationSettings-CNzZtI_o.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BlFX_WW9.js → OrderTableRenderer-6NPy-YHQ.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DM8-EgzR.js → Organization-DSNHsR4a.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-B9pMMIE8.js → Overflow-BcAYe_TB.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CNxt3m8G.js → P2P-B9XhsIKr.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BbppiJQa.js → PdhVaultBrowser-BR0GWf23.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CkbU4k5w.js → Permissions-Css2FapO.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CTP1cWxo.js → PersonalDataHub-DjRdBk_h.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-DOXykOA8.js → Pipeline-Cv6hncIf.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BWrp8ZRY.js → Privacy-vDC68AoW.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B6OQPTTl.js → ProjectInit-mkoQhgMU.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CYu0yAVQ.js → ProjectSettings-Byl3RnMM.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Dcu-tF8M.js → Projects-CILs2XYD.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-mR6PwgKV.js → Providers-BCrc0doI.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-EWtGuBnr.js → QuickAsk-Dt4oMuVS.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-YKMSZwfC.js → Recommend-BERAt_xe.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-yK5aobGy.js → Reputation-BKMmJ1ht.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D1s181ke.js → Row-DtGT9VXo.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DVoFZ5kC.js → RssFeed-CU_HDGRB.js} +2 -2
- package/src/assets/web-panel/assets/{Search-CN4DO-B5.js → Search-Df58g7IV.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DU7zt02X.js → Security-Cf9gGz78.js} +4 -4
- package/src/assets/web-panel/assets/{Services-ithSFJ8m.js → Services-epoiecXf.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-AdnDEpv-.js → Skeleton-C9675HRM.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DbzSM7vB.js → Skills-DnGvHN3A.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DX54_u0l.js → Sla-DRwsKeYG.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CRHZuDqy.js → SpeechSettings-DqBcNvXF.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DbFnDg_K.js → SyncSettings-CR50CALR.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Dhsmw2CQ.js → Tasks-ncUrJWWO.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DeBl9D2A.js → Templates-CWjIynfa.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CF-RiJ0g.js → Tenant-CpIyHDJJ.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-_66-j6JZ.js → Terminal-BVUShXlx.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-9RbokKX3.js → TimelineRenderer-C0ovMDh_.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Bv1_BfYT.js → Tokens-BJJfEvw7.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CCYW_wGy.js → Trigger-nDr3aXXM.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-C8NW132a.js → Trust-DBfuYxaI.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C4VPSFe9.js → UkeySign-DTUTMPJd.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-1zzclNfS.js → VideoEditing-CQqkMpBR.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DafZQtOh.js → Wallet-84mblhC7.js} +3 -3
- package/src/assets/web-panel/assets/{WebAuthn-we7YNPUy.js → WebAuthn-xH8iwuYw.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-C0ufqV_h.js → WorkflowEditor-BAdP685p.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D-OyV5Td.js → chat-BG05UmOG.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DfY_daVD.js → colors-B--izi6g.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BZGEQaH7.js → compact-item-mhINqcNr.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Ha9KgHfb.js → createContext-BxF4heyS.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-B-PQddh3.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DGcsqYDb.js → hasIn-k6zp6JXy.js} +1 -1
- package/src/assets/web-panel/assets/{index--WXQ2y49.js → index-ALaGUTBj.js} +1 -1
- package/src/assets/web-panel/assets/index-B8dJqRve.js +1 -0
- package/src/assets/web-panel/assets/{index-CaQ_9au2.js → index-BQTN9owK.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6Lk_-uR.js → index-Bm4EqCGD.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdYrVSXl.js → index-BmqTrBA9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCWbpajj.js → index-BptC59Nw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhX3LQ5F.js → index-BpxmdKly.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5t-g1rX.js → index-Bz_W2HMQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dw0NH-KM.js → index-C3T_jBxU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCMhrAQQ.js → index-C7E33Rtr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DihK8yMW.js → index-C8YjdEoE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNHsZmjx.js → index-C9uMHXAU.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8304Ulf.js → index-CDgK11Jy.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYnWmaCw.js → index-CQ4ARcWQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CcaG1Gci.js → index-CZY1CcMi.js} +1 -1
- package/src/assets/web-panel/assets/{index-DiHUtyKj.js → index-C_PP2xgo.js} +1 -1
- package/src/assets/web-panel/assets/{index-ybjPuUmk.js → index-CaOJtN9_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNRFSxql.js → index-Cf1HBQJD.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvJxHGRq.js → index-ClLYJ9Lr.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4PD8V1s.js → index-D22mMJcM.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZU8HRgG.js → index-D4it444p.js} +3 -3
- package/src/assets/web-panel/assets/{index-CZ18sJL-.js → index-D50R_x2q.js} +1 -1
- package/src/assets/web-panel/assets/index-DA_QbRy1.js +1 -0
- package/src/assets/web-panel/assets/{index-Da-1E5Dk.js → index-DBeRyDo3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cn6dP-P7.js → index-DIfHlmg5.js} +1 -1
- package/src/assets/web-panel/assets/{index-LODjH1N_.js → index-DJ7voWn9.js} +1 -1
- package/src/assets/web-panel/assets/{index-42LImEfZ.js → index-DYDTWu56.js} +1 -1
- package/src/assets/web-panel/assets/{index-gTYJ-BfG.js → index-DZhH_4lu.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsdgGEmW.js → index-DbJ9HYUz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvhP7rmX.js → index-DcIEV2W9.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5Jgl_3A.js → index-DkGO_kL_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLAWGH1Z.js → index-DoIbLP_2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMggRtTA.js → index-Dut5fnts.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiPMeSUC.js → index-Dy6draCr.js} +1 -1
- package/src/assets/web-panel/assets/{index-i7FGX3Og.js → index-Hrtyb8g4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DN6Qj7JH.js → index-NufO1jVs.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvCAWCE_.js → index-YVGxF1lz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCDaH6SF.js → index-ptTT_8Cw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDDEWfQx.js → index-tgxfNjRl.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-B5HHTM2M.js → initDefaultProps-BRO1fie3.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BGMk0sIO.js → motion-B0PeqWDm.js} +1 -1
- package/src/assets/web-panel/assets/{move-5FLoyfX1.js → move-DaFHMz5S.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DJl_jRfZ.js → mtc-parser-CwRq1H46.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Db-_WlEN.js → omit-BoixPnCY.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DsZsLkAT.js → pickAttrs-CtG4UyHs.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-M5UE9Uuc.js → placementArrow-CGzpdN2U.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-c4k_3oW2.js → responsiveObserve-DxtcM-r9.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Bk5r7ti1.js → slide-oAHegf3-.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CKIS5RY_.js → statusUtils-Ddl5dLe-.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BYIaM5uH.js → styleChecker-4gYXGrlZ.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CcjrBzHi.js → useFlexGapSupport-DB-sP5mv.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CkMOMjsE.js → useFs-cROlRg8N.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-Djl3wiRP.js → usePersonalDataHub-COtU3A5K.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-V3dEKndy.js → vnode-Cz2bZGdQ.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DroVkKDe.js → zoom-zhr1SK6Y.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agents.js +15 -28
- package/src/lib/agents.js +57 -0
- package/src/repl/add-dir.js +73 -0
- package/src/repl/agent-repl.js +311 -1
- package/src/repl/agents-status.js +122 -0
- package/src/repl/hooks-status.js +67 -0
- package/src/repl/pr-comments.js +197 -0
- package/src/repl/release-notes.js +29 -0
- package/src/repl/status-summary.js +33 -0
- package/src/repl/todos-status.js +65 -0
- package/src/assets/web-panel/assets/devWarning-CnWCtTRg.js +0 -1
- package/src/assets/web-panel/assets/index-35rCdAfK.js +0 -1
- package/src/assets/web-panel/assets/index-DN16qFHw.js +0 -1
package/src/repl/agent-repl.js
CHANGED
|
@@ -686,7 +686,9 @@ export async function startAgentRepl(options = {}) {
|
|
|
686
686
|
// --system-prompt replaces the built-in prompt; --append-system-prompt
|
|
687
687
|
// extends it (parity with the headless runners). The base is kept so an
|
|
688
688
|
// output-style persona can be swapped in/out at runtime via /output-style.
|
|
689
|
-
const
|
|
689
|
+
// `let` (not const): /add-dir rebuilds this mid-session to re-advertise the
|
|
690
|
+
// updated working roots; output-style swaps also read it live.
|
|
691
|
+
let _replBaseSystem = composeSystemPrompt(
|
|
690
692
|
buildSystemPrompt(process.cwd(), { additionalDirectories }),
|
|
691
693
|
{
|
|
692
694
|
systemPrompt: options.systemPrompt,
|
|
@@ -1035,6 +1037,8 @@ export async function startAgentRepl(options = {}) {
|
|
|
1035
1037
|
// so it follows `/cd` mid-session.
|
|
1036
1038
|
// Keep in sync with the rl.on("line") handlers + /help below.
|
|
1037
1039
|
slashCommands: [
|
|
1040
|
+
"/add-dir",
|
|
1041
|
+
"/agents",
|
|
1038
1042
|
"/auto",
|
|
1039
1043
|
"/cd",
|
|
1040
1044
|
"/clear",
|
|
@@ -1048,7 +1052,9 @@ export async function startAgentRepl(options = {}) {
|
|
|
1048
1052
|
"/exit",
|
|
1049
1053
|
"/export",
|
|
1050
1054
|
"/help",
|
|
1055
|
+
"/hooks",
|
|
1051
1056
|
"/ide",
|
|
1057
|
+
"/init",
|
|
1052
1058
|
"/mcp",
|
|
1053
1059
|
"/memory",
|
|
1054
1060
|
"/microcompact",
|
|
@@ -1056,10 +1062,12 @@ export async function startAgentRepl(options = {}) {
|
|
|
1056
1062
|
"/output-style",
|
|
1057
1063
|
"/permissions",
|
|
1058
1064
|
"/plan",
|
|
1065
|
+
"/pr-comments",
|
|
1059
1066
|
"/profile",
|
|
1060
1067
|
"/provider",
|
|
1061
1068
|
"/quit",
|
|
1062
1069
|
"/reindex",
|
|
1070
|
+
"/release-notes",
|
|
1063
1071
|
"/reload-skills",
|
|
1064
1072
|
"/review",
|
|
1065
1073
|
"/rewind",
|
|
@@ -1067,6 +1075,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
1067
1075
|
"/session",
|
|
1068
1076
|
"/sessions",
|
|
1069
1077
|
"/stats",
|
|
1078
|
+
"/status",
|
|
1070
1079
|
"/statusline",
|
|
1071
1080
|
"/sub-agents",
|
|
1072
1081
|
"/task",
|
|
@@ -1074,6 +1083,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
1074
1083
|
"/terminal-setup",
|
|
1075
1084
|
"/theme",
|
|
1076
1085
|
"/think",
|
|
1086
|
+
"/todos",
|
|
1077
1087
|
"/ultrathink",
|
|
1078
1088
|
"/vim",
|
|
1079
1089
|
],
|
|
@@ -1526,9 +1536,18 @@ export async function startAgentRepl(options = {}) {
|
|
|
1526
1536
|
logger.log(
|
|
1527
1537
|
` ${chalk.cyan("/doctor")} Session health check (provider/key/IDE/MCP/hooks)`,
|
|
1528
1538
|
);
|
|
1539
|
+
logger.log(
|
|
1540
|
+
` ${chalk.cyan("/status")} Environment snapshot (version/model/session/cwd/roots/IDE·MCP·hooks)`,
|
|
1541
|
+
);
|
|
1542
|
+
logger.log(
|
|
1543
|
+
` ${chalk.cyan("/release-notes")} Running version + changelog links + how to upgrade`,
|
|
1544
|
+
);
|
|
1529
1545
|
logger.log(
|
|
1530
1546
|
` ${chalk.cyan("/memory")} Project-memory files loaded (cc.md hierarchy + rules)`,
|
|
1531
1547
|
);
|
|
1548
|
+
logger.log(
|
|
1549
|
+
` ${chalk.cyan("/init")} Inventory this folder into a cc.md project-memory file (/init [--force])`,
|
|
1550
|
+
);
|
|
1532
1551
|
logger.log(
|
|
1533
1552
|
` ${chalk.cyan("/context")} Live context-window usage by role`,
|
|
1534
1553
|
);
|
|
@@ -1550,12 +1569,18 @@ export async function startAgentRepl(options = {}) {
|
|
|
1550
1569
|
logger.log(
|
|
1551
1570
|
` ${chalk.cyan("/cd <dir>")} Change working directory mid-session (completion/memory follow)`,
|
|
1552
1571
|
);
|
|
1572
|
+
logger.log(
|
|
1573
|
+
` ${chalk.cyan("/add-dir")} Add an extra working root (/add-dir <dir>; no arg lists roots)`,
|
|
1574
|
+
);
|
|
1553
1575
|
logger.log(
|
|
1554
1576
|
` ${chalk.cyan("/reload-skills")} Re-scan skill layers without restarting`,
|
|
1555
1577
|
);
|
|
1556
1578
|
logger.log(
|
|
1557
1579
|
` ${chalk.cyan("/review")} Diff-first code review (/review [high] [--security|--simplify] [--fix])`,
|
|
1558
1580
|
);
|
|
1581
|
+
logger.log(
|
|
1582
|
+
` ${chalk.cyan("/pr-comments")} Fetch a GitHub PR's comments and address them (/pr-comments [<n>] [--repo o/r]; needs gh)`,
|
|
1583
|
+
);
|
|
1559
1584
|
logger.log(
|
|
1560
1585
|
` ${chalk.cyan("/compact")} Smart compact (importance-based)`,
|
|
1561
1586
|
);
|
|
@@ -1596,18 +1621,27 @@ export async function startAgentRepl(options = {}) {
|
|
|
1596
1621
|
` ${chalk.cyan("/plan approve")} Approve and execute the plan`,
|
|
1597
1622
|
);
|
|
1598
1623
|
logger.log(` ${chalk.cyan("/plan reject")} Reject the plan`);
|
|
1624
|
+
logger.log(
|
|
1625
|
+
` ${chalk.cyan("/agents")} Manage sub-agent definitions (/agents [show|new] <name>; cc agents)`,
|
|
1626
|
+
);
|
|
1599
1627
|
logger.log(
|
|
1600
1628
|
` ${chalk.cyan("/sub-agents")} Show active/completed sub-agents`,
|
|
1601
1629
|
);
|
|
1602
1630
|
logger.log(
|
|
1603
1631
|
` ${chalk.cyan("/tasks")} Show background shell tasks (kill <id> · kill-all)`,
|
|
1604
1632
|
);
|
|
1633
|
+
logger.log(
|
|
1634
|
+
` ${chalk.cyan("/todos")} Show the session TODO list (what the agent tracks with todo_write)`,
|
|
1635
|
+
);
|
|
1605
1636
|
logger.log(
|
|
1606
1637
|
` ${chalk.cyan("/ide")} IDE bridge status (connected editor, tools, or why not)`,
|
|
1607
1638
|
);
|
|
1608
1639
|
logger.log(
|
|
1609
1640
|
` ${chalk.cyan("/mcp")} MCP server status + tools (/mcp <name> for one server)`,
|
|
1610
1641
|
);
|
|
1642
|
+
logger.log(
|
|
1643
|
+
` ${chalk.cyan("/hooks")} Loaded .claude/settings.json hooks (cc hook for observe-only DB hooks)`,
|
|
1644
|
+
);
|
|
1611
1645
|
logger.log(chalk.bold("\nCapabilities:"));
|
|
1612
1646
|
logger.log(" Read, write, and edit files");
|
|
1613
1647
|
logger.log(" Run shell commands (git, npm, etc.)");
|
|
@@ -1671,6 +1705,192 @@ export async function startAgentRepl(options = {}) {
|
|
|
1671
1705
|
return;
|
|
1672
1706
|
}
|
|
1673
1707
|
|
|
1708
|
+
// `/todos` — the session's TODO list (what the agent tracks with the
|
|
1709
|
+
// todo_write tool). Read-only view; the data lives in todo-manager keyed by
|
|
1710
|
+
// sessionId (same store the tool writes). Claude-Code /todos parity.
|
|
1711
|
+
if (trimmed === "/todos" || trimmed === "/todo") {
|
|
1712
|
+
try {
|
|
1713
|
+
const { getTodos } = await import("../lib/todo-manager.js");
|
|
1714
|
+
const { formatTodos } = await import("./todos-status.js");
|
|
1715
|
+
logger.log("\n" + formatTodos(getTodos(sessionId)) + "\n");
|
|
1716
|
+
} catch (err) {
|
|
1717
|
+
logger.error(chalk.red(`/todos failed: ${err.message}`));
|
|
1718
|
+
}
|
|
1719
|
+
prompt();
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
// `/hooks` — the decision-capable .claude/settings.json `hooks` block loaded
|
|
1724
|
+
// for this session (PreToolUse/PostToolUse/…). Observe-only DB hooks
|
|
1725
|
+
// (`cc hook add`) are managed via the `cc hook` CLI. Claude-Code /hooks parity.
|
|
1726
|
+
if (trimmed === "/hooks" || trimmed.startsWith("/hooks ")) {
|
|
1727
|
+
try {
|
|
1728
|
+
const { formatSettingsHooks } = await import("./hooks-status.js");
|
|
1729
|
+
logger.log("\n" + formatSettingsHooks(_settingsHooks) + "\n");
|
|
1730
|
+
} catch (err) {
|
|
1731
|
+
logger.error(chalk.red(`/hooks failed: ${err.message}`));
|
|
1732
|
+
}
|
|
1733
|
+
prompt();
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
// `/add-dir [dir]` — add an extra working root mid-session (or, with no
|
|
1738
|
+
// arg, list the current roots). The new root is threaded into every
|
|
1739
|
+
// subsequent turn's options.additionalDirectories (so read/search/edit span
|
|
1740
|
+
// it) and re-advertised in the system prompt. Claude-Code /add-dir parity.
|
|
1741
|
+
if (trimmed === "/add-dir" || trimmed.startsWith("/add-dir ")) {
|
|
1742
|
+
const arg = trimmed.slice("/add-dir".length).trim();
|
|
1743
|
+
try {
|
|
1744
|
+
const { resolveAddDir, formatAddDirRoots } =
|
|
1745
|
+
await import("./add-dir.js");
|
|
1746
|
+
if (!arg) {
|
|
1747
|
+
logger.log(
|
|
1748
|
+
"\n" +
|
|
1749
|
+
formatAddDirRoots(process.cwd(), additionalDirectories) +
|
|
1750
|
+
"\n",
|
|
1751
|
+
);
|
|
1752
|
+
} else {
|
|
1753
|
+
const res = resolveAddDir(arg, {
|
|
1754
|
+
cwd: process.cwd(),
|
|
1755
|
+
existing: additionalDirectories,
|
|
1756
|
+
});
|
|
1757
|
+
if (!res.ok) {
|
|
1758
|
+
logger.log(chalk.yellow(`/add-dir: ${res.reason}`));
|
|
1759
|
+
} else if (res.alreadyPresent) {
|
|
1760
|
+
logger.log(chalk.dim(`Already a working root: ${res.dir}`));
|
|
1761
|
+
} else {
|
|
1762
|
+
additionalDirectories.push(res.dir);
|
|
1763
|
+
// Re-advertise the updated roots in the system prompt; keep the
|
|
1764
|
+
// active output-style body layered on top (same as /output-style).
|
|
1765
|
+
_replBaseSystem = composeSystemPrompt(
|
|
1766
|
+
buildSystemPrompt(process.cwd(), { additionalDirectories }),
|
|
1767
|
+
{
|
|
1768
|
+
systemPrompt: options.systemPrompt,
|
|
1769
|
+
appendSystemPrompt: options.appendSystemPrompt,
|
|
1770
|
+
},
|
|
1771
|
+
);
|
|
1772
|
+
messages[0].content = _activeOutputStyle
|
|
1773
|
+
? `${_replBaseSystem}\n\n${_activeOutputStyle.body}`
|
|
1774
|
+
: _replBaseSystem;
|
|
1775
|
+
logger.log(chalk.green(`Added working root: ${res.dir}`));
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
} catch (err) {
|
|
1779
|
+
logger.error(chalk.red(`/add-dir failed: ${err.message}`));
|
|
1780
|
+
}
|
|
1781
|
+
prompt();
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
// `/init [--force]` — inventory the current folder into a cc.md
|
|
1786
|
+
// project-memory file (Claude-Code /init parity). Non-interactive: reuses
|
|
1787
|
+
// the same offline census as `cc init`. Loaded as project context next
|
|
1788
|
+
// session (or inspect with /memory).
|
|
1789
|
+
if (trimmed === "/init" || trimmed.startsWith("/init ")) {
|
|
1790
|
+
const force = /(^|\s)(--force|-f)(\s|$)/.test(trimmed);
|
|
1791
|
+
try {
|
|
1792
|
+
const { inventoryProject, renderMemoryFile } =
|
|
1793
|
+
await import("../lib/project-inventory.js");
|
|
1794
|
+
const initCwd = process.cwd();
|
|
1795
|
+
const target = path.join(initCwd, "cc.md");
|
|
1796
|
+
if (fs.existsSync(target) && !force) {
|
|
1797
|
+
logger.log(
|
|
1798
|
+
chalk.yellow(
|
|
1799
|
+
`cc.md already exists at ${target} — /init --force to overwrite.`,
|
|
1800
|
+
),
|
|
1801
|
+
);
|
|
1802
|
+
} else {
|
|
1803
|
+
const inv = inventoryProject(initCwd);
|
|
1804
|
+
fs.writeFileSync(target, renderMemoryFile(inv), "utf-8");
|
|
1805
|
+
logger.log(chalk.green(`Generated ${target}`));
|
|
1806
|
+
const langs = (inv.languages || [])
|
|
1807
|
+
.slice(0, 5)
|
|
1808
|
+
.map(([l, n]) => `${l} (${n})`)
|
|
1809
|
+
.join(", ");
|
|
1810
|
+
if (langs) logger.log(chalk.dim(` Languages: ${langs}`));
|
|
1811
|
+
if (inv.packageManager)
|
|
1812
|
+
logger.log(chalk.dim(` Package manager: ${inv.packageManager}`));
|
|
1813
|
+
if (inv.scripts && inv.scripts.length)
|
|
1814
|
+
logger.log(
|
|
1815
|
+
chalk.dim(` Scripts documented: ${inv.scripts.length}`),
|
|
1816
|
+
);
|
|
1817
|
+
logger.log(
|
|
1818
|
+
chalk.dim(
|
|
1819
|
+
" Loaded as project context next session (or /memory to inspect).",
|
|
1820
|
+
),
|
|
1821
|
+
);
|
|
1822
|
+
}
|
|
1823
|
+
} catch (err) {
|
|
1824
|
+
logger.error(chalk.red(`/init failed: ${err.message}`));
|
|
1825
|
+
}
|
|
1826
|
+
prompt();
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
// `/agents [list|show <name>|new <name> …]` — manage sub-agent DEFINITIONS
|
|
1831
|
+
// (.chainlesschain/agents/*.md / .claude/agents/*.md). Mirrors `cc agents`;
|
|
1832
|
+
// distinct from /sub-agents (running instances). Claude-Code /agents parity.
|
|
1833
|
+
if (trimmed === "/agents" || trimmed.startsWith("/agents ")) {
|
|
1834
|
+
try {
|
|
1835
|
+
const { parseAgentsCommand, formatAgentsList, formatAgentDetail } =
|
|
1836
|
+
await import("./agents-status.js");
|
|
1837
|
+
const { discoverAgents, getAgent, scaffoldAgent } =
|
|
1838
|
+
await import("../lib/agents.js");
|
|
1839
|
+
const { listSubAgentProfiles } =
|
|
1840
|
+
await import("../lib/sub-agent-profiles.js");
|
|
1841
|
+
const cmd = parseAgentsCommand(trimmed);
|
|
1842
|
+
if (cmd.action === "help") {
|
|
1843
|
+
logger.log(
|
|
1844
|
+
"Usage: /agents [list] · /agents show <name> · /agents new <name> [--tools a,b] [--claude|--personal] [--description <text>]",
|
|
1845
|
+
);
|
|
1846
|
+
} else if (cmd.action === "list") {
|
|
1847
|
+
logger.log(
|
|
1848
|
+
"\n" +
|
|
1849
|
+
formatAgentsList(
|
|
1850
|
+
discoverAgents(process.cwd()),
|
|
1851
|
+
listSubAgentProfiles(),
|
|
1852
|
+
) +
|
|
1853
|
+
"\n",
|
|
1854
|
+
);
|
|
1855
|
+
} else if (cmd.action === "show") {
|
|
1856
|
+
if (!cmd.name) {
|
|
1857
|
+
logger.log(chalk.yellow("Usage: /agents show <name>"));
|
|
1858
|
+
} else {
|
|
1859
|
+
const a = getAgent(cmd.name, process.cwd());
|
|
1860
|
+
if (!a) logger.log(chalk.yellow(`No such agent: ${cmd.name}`));
|
|
1861
|
+
else logger.log("\n" + formatAgentDetail(a) + "\n");
|
|
1862
|
+
}
|
|
1863
|
+
} else if (cmd.action === "new") {
|
|
1864
|
+
if (!cmd.name) {
|
|
1865
|
+
logger.log(
|
|
1866
|
+
chalk.yellow("Usage: /agents new <name> [--description <text>]"),
|
|
1867
|
+
);
|
|
1868
|
+
} else {
|
|
1869
|
+
const res = scaffoldAgent({
|
|
1870
|
+
name: cmd.name,
|
|
1871
|
+
description: cmd.description,
|
|
1872
|
+
tools: cmd.tools,
|
|
1873
|
+
location: cmd.location,
|
|
1874
|
+
});
|
|
1875
|
+
if (!res.ok) {
|
|
1876
|
+
logger.log(chalk.yellow(`/agents new: ${res.reason}`));
|
|
1877
|
+
} else {
|
|
1878
|
+
logger.log(chalk.green(`✓ created ${res.file}`));
|
|
1879
|
+
logger.log(
|
|
1880
|
+
chalk.dim(
|
|
1881
|
+
` edit it, then spawn it from the agent or run: cc agents run ${res.name} "<task>"`,
|
|
1882
|
+
),
|
|
1883
|
+
);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
} catch (err) {
|
|
1888
|
+
logger.error(chalk.red(`/agents failed: ${err.message}`));
|
|
1889
|
+
}
|
|
1890
|
+
prompt();
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1674
1894
|
if (trimmed === "/sub-agents" || trimmed === "/subagents") {
|
|
1675
1895
|
try {
|
|
1676
1896
|
const { SubAgentRegistry } =
|
|
@@ -3057,6 +3277,73 @@ export async function startAgentRepl(options = {}) {
|
|
|
3057
3277
|
return;
|
|
3058
3278
|
}
|
|
3059
3279
|
|
|
3280
|
+
// `/status` — concise environment snapshot (version / model / session / cwd
|
|
3281
|
+
// / roots / IDE·MCP·hooks). Lighter than /doctor. Claude-Code /status parity
|
|
3282
|
+
// (minus account/billing, which cc has no notion of).
|
|
3283
|
+
if (trimmed === "/status" || trimmed.startsWith("/status ")) {
|
|
3284
|
+
try {
|
|
3285
|
+
const { VERSION } = await import("../constants.js");
|
|
3286
|
+
const { readDiskVersion } = await import("../lib/version-skew.js");
|
|
3287
|
+
const { ideToolNames } = await import("./ide-status.js");
|
|
3288
|
+
const { formatStatus } = await import("./status-summary.js");
|
|
3289
|
+
const mcpConnected = _adhocMcp?.connected;
|
|
3290
|
+
const mcpCount = Array.isArray(mcpConnected)
|
|
3291
|
+
? mcpConnected.length
|
|
3292
|
+
: typeof mcpConnected === "number"
|
|
3293
|
+
? mcpConnected
|
|
3294
|
+
: mcpConnected
|
|
3295
|
+
? 1
|
|
3296
|
+
: 0;
|
|
3297
|
+
logger.log(
|
|
3298
|
+
"\n" +
|
|
3299
|
+
formatStatus({
|
|
3300
|
+
version: VERSION,
|
|
3301
|
+
installedVersion: readDiskVersion(),
|
|
3302
|
+
node: process.version,
|
|
3303
|
+
platform: `${process.platform}-${process.arch}`,
|
|
3304
|
+
provider,
|
|
3305
|
+
model: _curModel || model,
|
|
3306
|
+
sessionId,
|
|
3307
|
+
messageCount: messages.length,
|
|
3308
|
+
cwd: process.cwd(),
|
|
3309
|
+
extraRoots: additionalDirectories.length,
|
|
3310
|
+
ideConnected: ideToolNames(_adhocMcp).length > 0,
|
|
3311
|
+
mcpServers: mcpCount,
|
|
3312
|
+
hookEvents: _settingsHooks
|
|
3313
|
+
? Object.keys(_settingsHooks).length
|
|
3314
|
+
: 0,
|
|
3315
|
+
}) +
|
|
3316
|
+
"\n",
|
|
3317
|
+
);
|
|
3318
|
+
} catch (err) {
|
|
3319
|
+
logger.error(chalk.red(`/status failed: ${err.message}`));
|
|
3320
|
+
}
|
|
3321
|
+
prompt();
|
|
3322
|
+
return;
|
|
3323
|
+
}
|
|
3324
|
+
|
|
3325
|
+
// `/release-notes` — running version + a pointer to the full changelog +
|
|
3326
|
+
// how to upgrade. Claude-Code /release-notes parity.
|
|
3327
|
+
if (trimmed === "/release-notes" || trimmed.startsWith("/release-notes ")) {
|
|
3328
|
+
try {
|
|
3329
|
+
const { VERSION } = await import("../constants.js");
|
|
3330
|
+
const { readDiskVersion } = await import("../lib/version-skew.js");
|
|
3331
|
+
const { formatReleaseNotes } = await import("./release-notes.js");
|
|
3332
|
+
logger.log(
|
|
3333
|
+
"\n" +
|
|
3334
|
+
formatReleaseNotes({
|
|
3335
|
+
version: VERSION,
|
|
3336
|
+
installedVersion: readDiskVersion(),
|
|
3337
|
+
}) +
|
|
3338
|
+
"\n",
|
|
3339
|
+
);
|
|
3340
|
+
} catch (err) {
|
|
3341
|
+
logger.error(chalk.red(`/release-notes failed: ${err.message}`));
|
|
3342
|
+
}
|
|
3343
|
+
prompt();
|
|
3344
|
+
return;
|
|
3345
|
+
}
|
|
3346
|
+
|
|
3060
3347
|
// `/export [path]` — dump the live conversation to a Markdown transcript
|
|
3061
3348
|
// (Claude-Code parity). Distinct from `cc export` (knowledge base). Captures
|
|
3062
3349
|
// exactly what's in context now, persisted or not.
|
|
@@ -3275,6 +3562,29 @@ export async function startAgentRepl(options = {}) {
|
|
|
3275
3562
|
return;
|
|
3276
3563
|
}
|
|
3277
3564
|
}
|
|
3565
|
+
|
|
3566
|
+
// `/pr-comments [<n>|<url>] [--repo owner/name]` (Claude-Code parity):
|
|
3567
|
+
// fetch a GitHub PR's reviews + conversation + inline comments via `gh` and
|
|
3568
|
+
// feed them as this turn's input so the agent can address the feedback.
|
|
3569
|
+
if (promptText.startsWith("/pr-comments")) {
|
|
3570
|
+
try {
|
|
3571
|
+
const { expandPrComments } = await import("./pr-comments.js");
|
|
3572
|
+
const res = await expandPrComments(promptText);
|
|
3573
|
+
if (res != null) {
|
|
3574
|
+
promptText = res.text;
|
|
3575
|
+
logger.log(
|
|
3576
|
+
chalk.gray(
|
|
3577
|
+
`[pr] PR #${res.number}: ${res.count} comment(s) fetched`,
|
|
3578
|
+
),
|
|
3579
|
+
);
|
|
3580
|
+
}
|
|
3581
|
+
} catch (err) {
|
|
3582
|
+
logger.info(chalk.yellow(`[pr-comments] ${err.message}`));
|
|
3583
|
+
prompt();
|
|
3584
|
+
return;
|
|
3585
|
+
}
|
|
3586
|
+
}
|
|
3587
|
+
|
|
3278
3588
|
try {
|
|
3279
3589
|
const macro = await resolveSlashMacro(trimmed, { cwd: process.cwd() });
|
|
3280
3590
|
if (macro.matched) {
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/agents` REPL command (Claude-Code parity) — manage user-defined sub-agent
|
|
3
|
+
* DEFINITIONS (`.chainlesschain/agents/*.md` / `.claude/agents/*.md`) from
|
|
4
|
+
* inside an interactive session: list / show / new. Mirrors the `cc agents`
|
|
5
|
+
* CLI; the discovery + scaffold live in lib/agents.js (single source of truth),
|
|
6
|
+
* this module is the pure arg-parse + render layer. Distinct from `/sub-agents`
|
|
7
|
+
* which shows running instances.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
function stripQuotes(s) {
|
|
11
|
+
const t = String(s || "").trim();
|
|
12
|
+
if (
|
|
13
|
+
(t.startsWith('"') && t.endsWith('"')) ||
|
|
14
|
+
(t.startsWith("'") && t.endsWith("'"))
|
|
15
|
+
) {
|
|
16
|
+
return t.slice(1, -1);
|
|
17
|
+
}
|
|
18
|
+
return t;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Parse a `/agents …` line.
|
|
23
|
+
* Forms: `/agents [list]`, `/agents show <name>`, `/agents <name>` (= show),
|
|
24
|
+
* `/agents new <name> [--tools a,b] [--claude|--personal] [--description <text>]`,
|
|
25
|
+
* `/agents help`.
|
|
26
|
+
* @returns {{action:string, name?:string|null, description?:string|null,
|
|
27
|
+
* tools?:string|null, location?:string}}
|
|
28
|
+
*/
|
|
29
|
+
export function parseAgentsCommand(line) {
|
|
30
|
+
let rest = String(line || "")
|
|
31
|
+
.trim()
|
|
32
|
+
.replace(/^\/agents\b/, "")
|
|
33
|
+
.trim();
|
|
34
|
+
|
|
35
|
+
let location = "project";
|
|
36
|
+
if (/(^|\s)--personal(\s|$)/.test(rest)) {
|
|
37
|
+
location = "personal";
|
|
38
|
+
rest = rest.replace(/(^|\s)--personal(\s|$)/, " ");
|
|
39
|
+
}
|
|
40
|
+
if (/(^|\s)--claude(\s|$)/.test(rest)) {
|
|
41
|
+
if (location !== "personal") location = "claude";
|
|
42
|
+
rest = rest.replace(/(^|\s)--claude(\s|$)/, " ");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let tools = null;
|
|
46
|
+
const tm = rest.match(/(^|\s)--tools\s+("[^"]*"|'[^']*'|\S+)/);
|
|
47
|
+
if (tm) {
|
|
48
|
+
tools = stripQuotes(tm[2]);
|
|
49
|
+
rest = rest.replace(tm[0], " ");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// --description takes the rest of the line (may contain spaces).
|
|
53
|
+
let description = null;
|
|
54
|
+
const dm = rest.match(/(^|\s)--description\s+(.*)$/);
|
|
55
|
+
if (dm) {
|
|
56
|
+
description = stripQuotes(dm[2].trim()) || null;
|
|
57
|
+
rest = rest.slice(0, dm.index).trim();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
rest = rest.replace(/\s+/g, " ").trim();
|
|
61
|
+
const tokens = rest.length ? rest.split(" ") : [];
|
|
62
|
+
const first = tokens[0] || "";
|
|
63
|
+
|
|
64
|
+
if (!first || first === "list" || first === "ls") return { action: "list" };
|
|
65
|
+
if (first === "help") return { action: "help" };
|
|
66
|
+
if (first === "show") return { action: "show", name: tokens[1] || null };
|
|
67
|
+
if (first === "new") {
|
|
68
|
+
return {
|
|
69
|
+
action: "new",
|
|
70
|
+
name: tokens[1] || null,
|
|
71
|
+
description,
|
|
72
|
+
tools,
|
|
73
|
+
location,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// A bare token is treated as a name to show.
|
|
77
|
+
return { action: "show", name: first };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Render the list of agent definitions + built-in profiles. */
|
|
81
|
+
export function formatAgentsList(agents, profiles) {
|
|
82
|
+
const list = Array.isArray(agents) ? agents : [];
|
|
83
|
+
const profs = Array.isArray(profiles) ? profiles : [];
|
|
84
|
+
const lines = [
|
|
85
|
+
`Agent definitions (${list.length}) — .chainlesschain/agents · .claude/agents · ~/.claude/agents:`,
|
|
86
|
+
];
|
|
87
|
+
if (list.length === 0) {
|
|
88
|
+
lines.push(" (none — create one with /agents new <name>)");
|
|
89
|
+
} else {
|
|
90
|
+
for (const a of list) {
|
|
91
|
+
const tools = a.tools ? a.tools.join(",") : "(all)";
|
|
92
|
+
lines.push(` ${a.name} [${a.scope}] ${a.description || ""}`.trimEnd());
|
|
93
|
+
lines.push(` tools: ${tools}${a.model ? ` · model: ${a.model}` : ""}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (profs.length) {
|
|
97
|
+
lines.push("", "Built-in profiles (spawn_sub_agent profile:):");
|
|
98
|
+
for (const p of profs) {
|
|
99
|
+
lines.push(` ${p.name} — ${p.shortDescription || ""}`.trimEnd());
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
lines.push(
|
|
103
|
+
"",
|
|
104
|
+
'Manage: /agents show <name> · /agents new <name> · run via `cc agents run <name> "<task>"`',
|
|
105
|
+
);
|
|
106
|
+
return lines.join("\n");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Render one agent definition's metadata + system prompt. */
|
|
110
|
+
export function formatAgentDetail(agent) {
|
|
111
|
+
if (!agent) return null;
|
|
112
|
+
const tools = agent.tools ? agent.tools.join(",") : "(all)";
|
|
113
|
+
const lines = [
|
|
114
|
+
`${agent.name} [${agent.scope}]`,
|
|
115
|
+
agent.description ? ` ${agent.description}` : null,
|
|
116
|
+
` tools: ${tools}${agent.model ? ` · model: ${agent.model}` : ""}`,
|
|
117
|
+
` file: ${agent.file}`,
|
|
118
|
+
"",
|
|
119
|
+
agent.systemPrompt || "(empty system prompt)",
|
|
120
|
+
].filter((l) => l != null);
|
|
121
|
+
return lines.join("\n");
|
|
122
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure renderer for the `/hooks` REPL command — a user-facing view of the
|
|
3
|
+
* decision-capable `.claude/settings.json` `hooks` block loaded for this
|
|
4
|
+
* session. The data comes from settings-hooks' loadHooks(); this module only
|
|
5
|
+
* formats it, so it stays deterministic and unit-testable.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors Claude Code's /hooks view. The separate observe-only DB hooks
|
|
8
|
+
* (`cc hook add`) are not part of this block — a pointer to `cc hook list` is
|
|
9
|
+
* shown instead.
|
|
10
|
+
*
|
|
11
|
+
* Input shape (the settings.json `hooks` object):
|
|
12
|
+
* { <Event>: [ { matcher, hooks: [ { type, command, timeout } ] } ], ... }
|
|
13
|
+
* Event ∈ PreToolUse | PostToolUse | UserPromptSubmit | SessionStart |
|
|
14
|
+
* SessionEnd | Stop | PreCompact | SubagentStop | Notification
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** One hook command rendered to a single line. */
|
|
18
|
+
function fmtHook(h) {
|
|
19
|
+
if (!h || typeof h !== "object") return " (invalid hook)";
|
|
20
|
+
const cmd =
|
|
21
|
+
h.type === "command"
|
|
22
|
+
? String(h.command || "").trim() || "(no command)"
|
|
23
|
+
: `(${h.type || "unknown"} hook)`;
|
|
24
|
+
const to =
|
|
25
|
+
h.timeout != null && Number.isFinite(Number(h.timeout))
|
|
26
|
+
? ` [timeout ${Number(h.timeout)}s]`
|
|
27
|
+
: "";
|
|
28
|
+
return ` ${cmd}${to}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Render the loaded settings.json hooks block as a plain-text block.
|
|
33
|
+
* @param {object|null} hooks the merged `hooks` object, or null when none
|
|
34
|
+
*/
|
|
35
|
+
export function formatSettingsHooks(hooks) {
|
|
36
|
+
const events = hooks && typeof hooks === "object" ? Object.keys(hooks) : [];
|
|
37
|
+
if (events.length === 0) {
|
|
38
|
+
return (
|
|
39
|
+
"No settings.json hooks loaded.\n" +
|
|
40
|
+
" Define a `hooks` block in .claude/settings.json (PreToolUse / " +
|
|
41
|
+
"PostToolUse / UserPromptSubmit / SessionStart / Stop / PreCompact / …).\n" +
|
|
42
|
+
" Observe-only DB hooks: cc hook list"
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
let total = 0;
|
|
46
|
+
const body = [];
|
|
47
|
+
for (const ev of events) {
|
|
48
|
+
const entries = Array.isArray(hooks[ev]) ? hooks[ev] : [];
|
|
49
|
+
body.push(` ${ev}:`);
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
const matcher = entry?.matcher ? String(entry.matcher) : "*";
|
|
52
|
+
body.push(` matcher ${matcher}`);
|
|
53
|
+
const hs = Array.isArray(entry?.hooks) ? entry.hooks : [];
|
|
54
|
+
for (const h of hs) {
|
|
55
|
+
total += 1;
|
|
56
|
+
body.push(fmtHook(h));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const header = `settings.json hooks (decision-capable, ${total} command(s) across ${events.length} event(s)):`;
|
|
61
|
+
return (
|
|
62
|
+
header +
|
|
63
|
+
"\n" +
|
|
64
|
+
body.join("\n") +
|
|
65
|
+
"\n Test a hook: cc hook test <event> <tool> --run · observe-only DB hooks: cc hook list"
|
|
66
|
+
);
|
|
67
|
+
}
|