chainlesschain 0.162.71 → 0.162.73
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 +3 -2
- package/src/assets/web-panel/assets/{AIOps-pes7_jGr.js → AIOps-DTI_-iZ_.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DiHWdeH1.js → ActionButton-CtpbGicW.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C51UX-V_.js → Analytics-C1HwMd7E.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BE6LJLw9.js → AppLayout-Db953rqB.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-CtTkLTe2.js → Audit-CuIi9Vup.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-lmpVwPxc.js → Backup-DwR7Wlve.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Dr7DR1E1.js → BaseInput-B5wNMp7S.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DXph6klA.js → Chat-DivalHgk.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-RefrXxqp.js → ChatBubbleRenderer-BwPSr02C.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BF0aS5R9.js → Checkbox-CJrXPCJH.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B-oHWNTV.js → Codegen-BieZvOkC.js} +1 -1
- package/src/assets/web-panel/assets/{Col-B6KdyRTE.js → Col-BzvPsQgb.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D5ac0KyO.js → Community-CWcAMlpQ.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dc61O2eQ.js → Compact-Bj_BLBpw.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-a48qvNmd.js → Compliance-DKvo0WAi.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CIF9lSRj.js → Cowork-DRajk8JO.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-C_gkf4xd.js → Cron-DPz9MoUo.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CJt15PzW.js → Crosschain-BpSuvmns.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D8I_okEj.js → DID-Co98G00H.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-O4q-qCF2.js → Dashboard-8TSG0W7f.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-flRziiaw.js → Dropdown-CKViu7w3.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CnnkfGPw.js → EmailListRenderer-BqfdADvJ.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-CYAJpGqd.js → FamilyGuardDashboard-aWu1imGZ.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Dm3WqzQ_.js → Federation-w4YpT8EN.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CpAIter6.js → FormItemContext-CAk4CXid.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-ChzXcyuN.js → GenericCardRenderer-MoJw4J2L.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DElmMsL4.js → Git-HNU_a9Jz.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-EWmgn9io.js → Governance-BkIXWYUS.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-VtOR_sef.js → Inference-CnquB88h.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-OMqlGkMR.js → KnowledgeGraph-PGSMF-uq.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CTgYDsTZ.js → Logs-DCc-nYzu.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-DZIUTbn8.js → Marketplace-CyGX8XEt.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DWeOErCA.js → McpTools-DBkZ5yUL.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-DwFBp-ev.js → Memory-DmYLRCwo.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-D42xBfE3.js → MobileBridge-CszJjeNc.js} +2 -2
- package/src/assets/web-panel/assets/{MobileProjects-BHCHauUl.js → MobileProjects-DWgtDsta.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CabnNsyS.js → Mtc-Bmt_Pmg4.js} +3 -3
- package/src/assets/web-panel/assets/{MtcAudit-Ddx9Awu5.js → MtcAudit-BmG0ys0l.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-CJpYBZ8f.js → Multisig-DNd5iMmD.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BvPJskVG.js → NLProgramming-yxbNl09B.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-92ELvJM2.js → Notes-CQ0qAzI4.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CXz0SUzP.js → NotificationSettings-CIzkE4ao.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-4iWRkMr-.js → OrderTableRenderer-e1VMUxTi.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DblqJPeY.js → Organization-BNBIlf_R.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CHfS3HwD.js → Overflow-C5GzzJTq.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DIg0pLIG.js → P2P-DjL2jIED.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BhD3DGjk.js → PdhVaultBrowser-C2EYDmpW.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-Ct7bwrz8.js → Permissions-BVGCXxDp.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-DG9c1eas.js → PersonalDataHub-B1xBro16.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-BwQnEqG0.js → Pipeline-DIYWiDnt.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BvWaf-Ba.js → Privacy--Qx3QdO1.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BFzMHtiW.js → ProjectInit-DYOEcV04.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DDpokSpH.js → ProjectSettings-BcOx5-KS.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-3IL8lyPl.js → Projects-CO69txk4.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-C6BsEzSR.js → Providers-Bj8pCgzo.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Mh6690Ey.js → QuickAsk-Cukpq-4s.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CJbZ6wgA.js → Recommend-DJB5wUfM.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-GDcyl6iQ.js → Reputation-B9t0-nT0.js} +1 -1
- package/src/assets/web-panel/assets/{Row-6p4DKFSi.js → Row-4cniRgxC.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BLhrkoDq.js → RssFeed-Y4db_T9t.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Ckiyt35t.js → Search-DggZDzlc.js} +1 -1
- package/src/assets/web-panel/assets/{Security-qhh-B5Qt.js → Security-C67A6kED.js} +4 -4
- package/src/assets/web-panel/assets/{Services-D7a2OwKm.js → Services-BocBjvaa.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CSMxupKd.js → Skeleton-C9jI-iOy.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CGpMng8w.js → Skills-2baFHKOW.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CYtaU3Ar.js → Sla-CnowXeRb.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BTCsu1uM.js → SpeechSettings-DWGBkmUt.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Cnzx2L5I.js → SyncSettings-B89qwCgX.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-C1_WvNc0.js +1 -0
- package/src/assets/web-panel/assets/{Templates-Ccdx_C3w.js → Templates-P8dBhbxa.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-ZN8c86j3.js → Tenant-DHo0pxrm.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-Dr-HvjH-.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-CjgirE9d.js → TimelineRenderer-DM7dOaUR.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-QoRpi6Wf.js → Tokens-DnJxqOPM.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CEQKJkhs.js → Trigger-C-FLgMzr.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-UTuAzV1q.js → Trust-CIT_RVqA.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-JDs9I7fl.js → UkeySign-Cg9VS6y6.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BACYQQSd.js → VideoEditing-BzoxE8mA.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-C-SKluhH.js → Wallet-ZkmCII8R.js} +3 -3
- package/src/assets/web-panel/assets/{WebAuthn-9chizTFy.js → WebAuthn-CptQdp3u.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-0mF-LAUo.js → WorkflowEditor-Vkz28khO.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Di7QINiP.js → chat-DXdmvvEA.js} +1 -1
- package/src/assets/web-panel/assets/{colors-SBmhHMM9.js → colors-De7FCj5l.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BmbETbNj.js → compact-item-DnT3XzME.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C7hFnsJ7.js → createContext-ECZfCCqd.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-gaA8VqZf.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CFtthKDD.js → hasIn-Uodg6pAt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRBc1Ewn.js → index-1dWvOqru.js} +1 -1
- package/src/assets/web-panel/assets/{index-WjZVyLn7.js → index-BC8SOuGi.js} +1 -1
- package/src/assets/web-panel/assets/{index-CovTrPpI.js → index-BUMNJRCl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSnTUPQx.js → index-Bg1RsfAJ.js} +3 -3
- package/src/assets/web-panel/assets/{index-NxxQTlPJ.js → index-Blo85ZKd.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClIp4Vin.js → index-BtJ8BHU0.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4etIqbf.js → index-C01WM7Pk.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWfObC0n.js → index-C4KhsGXo.js} +1 -1
- package/src/assets/web-panel/assets/{index-sz0w-D-C.js → index-C6JgjkY7.js} +1 -1
- package/src/assets/web-panel/assets/{index-lRVjtXeH.js → index-C9_Cnvha.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCcCs7LJ.js → index-CCguvASR.js} +1 -1
- package/src/assets/web-panel/assets/{index-C6tZzsb9.js → index-CLzPxAp4.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0yO3vWh.js → index-CMuqxCVw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcawAm_i.js → index-COTabJQd.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cib-RTws.js → index-CPjI3AGE.js} +1 -1
- package/src/assets/web-panel/assets/{index-C07kpleB.js → index-CaDZ-LMg.js} +1 -1
- package/src/assets/web-panel/assets/{index-DEYnWiq1.js → index-CbbfcGeJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgXQwqXr.js → index-CcLDjTgI.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2CN7coN.js → index-CffZBdA1.js} +1 -1
- package/src/assets/web-panel/assets/{index-PN02VlUB.js → index-CwXP0KcT.js} +1 -1
- package/src/assets/web-panel/assets/{index-_hO8-EnW.js → index-D2YOclGO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dk4ez5rf.js → index-DBsl2SuZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6vNUp6c.js → index-DCvmjxu9.js} +1 -1
- package/src/assets/web-panel/assets/{index-sA4vr5WV.js → index-DGwgEqwl.js} +1 -1
- package/src/assets/web-panel/assets/{index-DI2xH1fU.js → index-DOIeo8Qs.js} +1 -1
- package/src/assets/web-panel/assets/{index-_a2NG3iP.js → index-DPcpxSQt.js} +1 -1
- package/src/assets/web-panel/assets/index-DTpmiTGK.js +1 -0
- package/src/assets/web-panel/assets/{index-CWDk3nDZ.js → index-Db33l8Ix.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNpb8m5a.js → index-Dbfj4QL5.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dww6gCzI.js → index-Dd9Bx3tJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bpo7UVJe.js → index-Dkvf5upf.js} +1 -1
- package/src/assets/web-panel/assets/index-DwpvMYUU.js +1 -0
- package/src/assets/web-panel/assets/{index-BT2uOwmA.js → index-Dy0AT-uc.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2fhXmhW.js → index-FU8Zo5cp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcRTX_WO.js → index-JVwNC4yP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dps9xdE8.js → index-JqSxr1A7.js} +1 -1
- package/src/assets/web-panel/assets/{index-D134XFWR.js → index-KV6dXwKC.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8CeUlN0.js → index-LwNszM-5.js} +1 -1
- package/src/assets/web-panel/assets/{index-CcBhsVYn.js → index-cHnmjGqB.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-B1zCwkvT.js → initDefaultProps-B3H1sf95.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BDGIV9KA.js → motion-DreYO5eb.js} +1 -1
- package/src/assets/web-panel/assets/{move-BITqgluK.js → move-B0OVU04M.js} +1 -1
- package/src/assets/web-panel/assets/{omit-uD97QKBF.js → omit-PcEEXHLZ.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CZpXhSIE.js → pickAttrs-DH6-hDkF.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-ByUvT_08.js → placementArrow-DFamUSEw.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BQG9LlBs.js → responsiveObserve-DT1grAyh.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Bx9TyeEE.js → slide-41lCsY6d.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-XWaMqYM8.js → statusUtils-FzJ7j2T7.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BZ-nMyDB.js → styleChecker-D0Zvn50h.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-D_iwA3vx.js → useFlexGapSupport-BTxsJE5n.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DuvW_aRX.js → useFs-DRVttEr3.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BO7orS0d.js → usePersonalDataHub-BSe7NVv0.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Cc_fqAL4.js → vnode-D8O7tUXh.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BGkBp90M.js → zoom-CMQc1RZ4.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +12 -0
- package/src/commands/cowork.js +8 -0
- package/src/commands/crosschain.js +32 -4
- package/src/commands/init.js +10 -10
- package/src/commands/loop.js +9 -3
- package/src/commands/memory.js +6 -4
- package/src/commands/orchestrate.js +5 -2
- package/src/commands/video.js +5 -1
- package/src/lib/agents.js +16 -5
- package/src/lib/cowork-workflow.js +357 -136
- package/src/lib/micro-compact.js +52 -0
- package/src/lib/output-styles.js +41 -7
- package/src/lib/permission-rules.cjs +39 -0
- package/src/lib/project-root.cjs +87 -0
- package/src/lib/settings-hooks.cjs +18 -6
- package/src/lib/settings-loader.cjs +12 -5
- package/src/lib/skill-loader.js +62 -43
- package/src/lib/slash-commands.js +18 -2
- package/src/repl/agent-repl.js +228 -20
- package/src/repl/chat-repl.js +4 -2
- package/src/repl/permission-tier.js +60 -0
- package/src/repl/stream-decision.js +16 -0
- package/src/repl/think-command.js +36 -0
- package/src/runtime/agent-core.js +67 -10
- package/src/runtime/file-ref-expander.js +209 -18
- package/src/runtime/headless-runner.js +3 -3
- package/src/runtime/headless-stream.js +16 -3
- package/src/runtime/mcp-config.js +78 -1
- package/src/assets/web-panel/assets/Tasks-BhnGtqaZ.js +0 -1
- package/src/assets/web-panel/assets/Terminal-BfgM0oyN.js +0 -3
- package/src/assets/web-panel/assets/devWarning-gNvbyy4j.js +0 -1
- package/src/assets/web-panel/assets/index-BNXpMnIY.js +0 -1
- package/src/assets/web-panel/assets/index-gfHxqT1Q.js +0 -1
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
* Read(./src/**) → read_file/list_dir on a path under <cwd>/src
|
|
14
14
|
* Edit(//etc/**) → edit_file on an absolute path under /etc
|
|
15
15
|
* WebFetch(domain:example.com) → web_fetch of https://example.com/…
|
|
16
|
+
* Bash(command:rm*) → run_shell whose `command` arg matches `rm*` (CC
|
|
17
|
+
* 2.1.178 `Tool(param:value)` — matches any named
|
|
18
|
+
* input parameter, incl. arbitrary MCP tool args;
|
|
19
|
+
* `*` crosses `/` here, unlike path globs)
|
|
20
|
+
* mcp__db__query(table:users) → that MCP tool whose `table` arg is "users"
|
|
16
21
|
* Bash → every run_shell call
|
|
17
22
|
* * → every tool call (Claude-Code deny-all idiom)
|
|
18
23
|
* Bash(*) → every run_shell call (lone-`*` pattern = match-all)
|
|
@@ -197,6 +202,30 @@ function matchUrl(pattern, url) {
|
|
|
197
202
|
return globToRegExp(pattern).test(u);
|
|
198
203
|
}
|
|
199
204
|
|
|
205
|
+
/** Match a single named-parameter value — `Tool(param:value)`. `prefix:*` →
|
|
206
|
+
* starts-with; otherwise glob/exact. Unlike path globs, `*` here crosses `/`
|
|
207
|
+
* because param values are arbitrary strings (commands often embed paths),
|
|
208
|
+
* not filesystem path segments. */
|
|
209
|
+
function matchParamValue(pattern, value) {
|
|
210
|
+
const v = value == null ? "" : String(value);
|
|
211
|
+
if (pattern === "*" || pattern === "**") return true;
|
|
212
|
+
if (pattern.endsWith(":*")) {
|
|
213
|
+
const prefix = pattern.slice(0, -2).trim();
|
|
214
|
+
return v === prefix || v.startsWith(prefix);
|
|
215
|
+
}
|
|
216
|
+
if (pattern.includes("*") || pattern.includes("?")) {
|
|
217
|
+
const re =
|
|
218
|
+
"^" +
|
|
219
|
+
pattern
|
|
220
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
221
|
+
.replace(/\*/g, ".*")
|
|
222
|
+
.replace(/\?/g, ".") +
|
|
223
|
+
"$";
|
|
224
|
+
return new RegExp(re).test(v);
|
|
225
|
+
}
|
|
226
|
+
return v === pattern;
|
|
227
|
+
}
|
|
228
|
+
|
|
200
229
|
/**
|
|
201
230
|
* Does `pattern` (the inside of `Tool(...)`, or null for a bare rule) match the
|
|
202
231
|
* given tool call? `null` pattern always matches.
|
|
@@ -208,6 +237,15 @@ function matchPattern(pattern, actualTool, args, cwd) {
|
|
|
208
237
|
// command/url/path containing `/` can't slip past a deny-all (globToRegExp's
|
|
209
238
|
// `*` → `[^/]*` otherwise excludes slashes).
|
|
210
239
|
if (pattern === "*" || pattern === "**") return true;
|
|
240
|
+
// Claude-Code 2.1.178: `Tool(param:value)` matches a NAMED input parameter,
|
|
241
|
+
// generalizing the positional command/path/url targets below. Treated as a
|
|
242
|
+
// param rule only when `param` is a bare identifier AND an actual key in the
|
|
243
|
+
// tool's args — so command idioms (`git push:*`) and `domain:host` (whose
|
|
244
|
+
// prefix is not an arg key) correctly fall through to the matching below.
|
|
245
|
+
const pv = pattern.match(/^([A-Za-z_]\w*):([\s\S]*)$/);
|
|
246
|
+
if (pv && Object.prototype.hasOwnProperty.call(args || {}, pv[1])) {
|
|
247
|
+
return matchParamValue(pv[2].trim(), (args || {})[pv[1]]);
|
|
248
|
+
}
|
|
211
249
|
const target = extractTarget(actualTool, args, cwd);
|
|
212
250
|
if (target.kind === "command") {
|
|
213
251
|
return target.value ? matchCommand(pattern, target.value) : false;
|
|
@@ -328,6 +366,7 @@ module.exports = {
|
|
|
328
366
|
extractTarget,
|
|
329
367
|
matchCommand,
|
|
330
368
|
matchUrl,
|
|
369
|
+
matchParamValue,
|
|
331
370
|
matchPattern,
|
|
332
371
|
evaluatePermissionRules,
|
|
333
372
|
suggestAllowRule,
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* project-root — locate the nearest ancestor project root by walking up from a
|
|
3
|
+
* starting directory until a `.git` marker is found.
|
|
4
|
+
*
|
|
5
|
+
* Shared by the `.claude` / `.chainlesschain` discovery layers (settings.json
|
|
6
|
+
* permission rules, output-styles, slash-commands, sub-agents) so that running
|
|
7
|
+
* `cc` from a project SUBDIRECTORY still picks up the project-root config —
|
|
8
|
+
* Claude-Code 2.1.178 "closest `.claude` directory wins" parity. This mirrors
|
|
9
|
+
* the git-root resolution already used by skill-loader + project-instructions,
|
|
10
|
+
* which previously left these four layers as the only cwd-only stragglers (so a
|
|
11
|
+
* subdir run silently dropped the project's permission rules — a safety gap).
|
|
12
|
+
*
|
|
13
|
+
* A single `.cjs` module so the CJS `settings-loader` can `require` it and the
|
|
14
|
+
* ESM loaders can `import` it — one source of truth for the walk.
|
|
15
|
+
*
|
|
16
|
+
* DEFENSIVE BY DESIGN: callers thread their own (often mocked) `fs` / `path`
|
|
17
|
+
* through `deps`. If `.git` is not found via that `fs`, or the injected `path`
|
|
18
|
+
* lacks `dirname` / `resolve`, the walk bails to `null` and the caller keeps its
|
|
19
|
+
* existing cwd-only behavior unchanged — keeping the heavily-mocked unit tests
|
|
20
|
+
* green while real runs (real `node:path`) walk up correctly.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const fsDefault = require("node:fs");
|
|
24
|
+
const pathDefault = require("node:path");
|
|
25
|
+
|
|
26
|
+
const _deps = { fs: fsDefault, path: pathDefault };
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Walk up from `cwd` to the nearest directory containing `.git`. Returns the
|
|
30
|
+
* resolved root path, or `null` when none is found (or deps are unusable).
|
|
31
|
+
* @param {string} cwd
|
|
32
|
+
* @param {{ fs?: object, path?: object }} [deps]
|
|
33
|
+
*/
|
|
34
|
+
function findGitProjectRoot(cwd, deps = {}) {
|
|
35
|
+
const fs = deps.fs || _deps.fs;
|
|
36
|
+
const path = deps.path || _deps.path;
|
|
37
|
+
if (!fs || typeof fs.existsSync !== "function") return null;
|
|
38
|
+
if (!path || typeof path.dirname !== "function" || typeof path.join !== "function") {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
let dir;
|
|
42
|
+
try {
|
|
43
|
+
dir = typeof path.resolve === "function" ? path.resolve(cwd || ".") : String(cwd || ".");
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
// Bounded walk (64 levels) so a malformed `dirname` can never spin forever.
|
|
48
|
+
for (let i = 0; i < 64 && dir; i++) {
|
|
49
|
+
try {
|
|
50
|
+
if (fs.existsSync(path.join(dir, ".git"))) return dir;
|
|
51
|
+
} catch {
|
|
52
|
+
/* unreadable dir → keep walking up */
|
|
53
|
+
}
|
|
54
|
+
let parent;
|
|
55
|
+
try {
|
|
56
|
+
parent = path.dirname(dir);
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
if (!parent || parent === dir) break;
|
|
61
|
+
dir = parent;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The extra project-root base directory to ADD to a cwd-based discovery list
|
|
68
|
+
* when running from a subdirectory. Returns the git root when it exists AND is a
|
|
69
|
+
* strict ancestor of `cwd`; returns `null` when `cwd` is itself the root (its
|
|
70
|
+
* own dirs already cover it) or no root is found.
|
|
71
|
+
* @param {string} cwd
|
|
72
|
+
* @param {{ fs?: object, path?: object }} [deps]
|
|
73
|
+
*/
|
|
74
|
+
function projectRootBase(cwd, deps = {}) {
|
|
75
|
+
const root = findGitProjectRoot(cwd, deps);
|
|
76
|
+
if (!root) return null;
|
|
77
|
+
const path = deps.path || _deps.path;
|
|
78
|
+
let resolvedCwd = cwd;
|
|
79
|
+
try {
|
|
80
|
+
if (path && typeof path.resolve === "function") resolvedCwd = path.resolve(cwd || ".");
|
|
81
|
+
} catch {
|
|
82
|
+
/* fall through with raw cwd */
|
|
83
|
+
}
|
|
84
|
+
return root === resolvedCwd ? null : root;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { findGitProjectRoot, projectRootBase, _deps };
|
|
@@ -28,6 +28,7 @@ const path = require("node:path");
|
|
|
28
28
|
const os = require("node:os");
|
|
29
29
|
const fsDefault = require("node:fs");
|
|
30
30
|
const { SUGGEST_UMBRELLA } = require("./permission-rules.cjs");
|
|
31
|
+
const { projectRootBase } = require("./project-root.cjs");
|
|
31
32
|
|
|
32
33
|
const _deps = { fs: fsDefault, homedir: () => os.homedir() };
|
|
33
34
|
|
|
@@ -44,14 +45,25 @@ const HOOK_EVENTS = Object.freeze([
|
|
|
44
45
|
"Notification",
|
|
45
46
|
]);
|
|
46
47
|
|
|
47
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Same hierarchy as settings-loader (user < project-root < cwd < --settings).
|
|
50
|
+
* When run from a SUBDIRECTORY, the project-root `.claude` hooks apply (below
|
|
51
|
+
* cwd's, above the user layer) — same walk-up as settings-loader's settingsPaths
|
|
52
|
+
* (shared `projectRootBase`, threaded through this loader's own `_deps.fs` to
|
|
53
|
+
* keep test injection intact). Hooks RUN SHELL COMMANDS, so a guard hook in the
|
|
54
|
+
* project-root settings must NOT silently vanish when `cc` is invoked from a
|
|
55
|
+
* subdirectory. `projectRootBase` returns null when cwd IS the root.
|
|
56
|
+
*/
|
|
48
57
|
function settingsFiles(cwd, explicitFile) {
|
|
49
58
|
const home = _deps.homedir();
|
|
50
|
-
const list = [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
path.join(
|
|
54
|
-
|
|
59
|
+
const list = [path.join(home, ".claude", "settings.json")];
|
|
60
|
+
const root = projectRootBase(cwd, { fs: _deps.fs, path });
|
|
61
|
+
if (root) {
|
|
62
|
+
list.push(path.join(root, ".claude", "settings.json"));
|
|
63
|
+
list.push(path.join(root, ".claude", "settings.local.json"));
|
|
64
|
+
}
|
|
65
|
+
list.push(path.join(cwd, ".claude", "settings.json"));
|
|
66
|
+
list.push(path.join(cwd, ".claude", "settings.local.json"));
|
|
55
67
|
if (explicitFile) list.push(path.resolve(cwd, explicitFile));
|
|
56
68
|
return list;
|
|
57
69
|
}
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
const fsDefault = require("node:fs");
|
|
28
28
|
const path = require("node:path");
|
|
29
29
|
const os = require("node:os");
|
|
30
|
+
const { projectRootBase } = require("./project-root.cjs");
|
|
30
31
|
|
|
31
32
|
const _deps = { fs: fsDefault, homedir: () => os.homedir() };
|
|
32
33
|
|
|
@@ -72,11 +73,17 @@ function accrete(target, sources, arr, file, kind) {
|
|
|
72
73
|
/** The ordered list of candidate settings files for a cwd. */
|
|
73
74
|
function settingsPaths(cwd, explicitFile) {
|
|
74
75
|
const home = _deps.homedir();
|
|
75
|
-
const list = [
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
const list = [path.join(home, ".claude", "settings.json")];
|
|
77
|
+
// When run from a subdirectory, the project-root `.claude` sits BELOW cwd's
|
|
78
|
+
// own (closest wins) but ABOVE the user layer — so its rules apply yet a
|
|
79
|
+
// cwd-local settings file still overrides them. Null when cwd IS the root.
|
|
80
|
+
const root = projectRootBase(cwd, { fs: _deps.fs, path });
|
|
81
|
+
if (root) {
|
|
82
|
+
list.push(path.join(root, ".claude", "settings.json"));
|
|
83
|
+
list.push(path.join(root, ".claude", "settings.local.json"));
|
|
84
|
+
}
|
|
85
|
+
list.push(path.join(cwd, ".claude", "settings.json"));
|
|
86
|
+
list.push(path.join(cwd, ".claude", "settings.local.json"));
|
|
80
87
|
if (explicitFile) list.push(path.resolve(cwd, explicitFile));
|
|
81
88
|
return list;
|
|
82
89
|
}
|
package/src/lib/skill-loader.js
CHANGED
|
@@ -78,6 +78,10 @@ export const LAYER_NAMES = [
|
|
|
78
78
|
"workspace",
|
|
79
79
|
];
|
|
80
80
|
|
|
81
|
+
/** Max directory depth to descend when scanning a skill layer for nested
|
|
82
|
+
* `<group>/<skill>/SKILL.md` layouts (infinite-recursion / deep-tree guard). */
|
|
83
|
+
export const MAX_SKILL_NEST_DEPTH = 5;
|
|
84
|
+
|
|
81
85
|
/**
|
|
82
86
|
* Simple YAML frontmatter parser (no dependencies)
|
|
83
87
|
* Shared utility extracted from skill.js
|
|
@@ -348,54 +352,69 @@ export class CLISkillLoader {
|
|
|
348
352
|
*/
|
|
349
353
|
_loadFromDir(dir, layer) {
|
|
350
354
|
const skills = [];
|
|
351
|
-
|
|
355
|
+
this._collectSkills(dir, layer, skills, 0);
|
|
356
|
+
return skills;
|
|
357
|
+
}
|
|
352
358
|
|
|
359
|
+
/**
|
|
360
|
+
* Recursively collect skills under `dir`. A directory containing a SKILL.md
|
|
361
|
+
* is a skill (a leaf — we do NOT descend into its asset/script subdirs); a
|
|
362
|
+
* directory WITHOUT one is treated as a grouping/category folder and is
|
|
363
|
+
* descended into, so nested layouts like `.claude/skills/<group>/<skill>/`
|
|
364
|
+
* load too (Claude-Code 2.1.178 nested-skills parity). Depth-capped.
|
|
365
|
+
*/
|
|
366
|
+
_collectSkills(dir, layer, out, depth) {
|
|
367
|
+
if (!dir || !fs.existsSync(dir)) return;
|
|
368
|
+
let entries;
|
|
353
369
|
try {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
id: data.name || entry.name,
|
|
367
|
-
displayName: data.displayName || entry.name,
|
|
368
|
-
description: data.description || "",
|
|
369
|
-
version: data.version || "1.0.0",
|
|
370
|
-
category: data.category || "uncategorized",
|
|
371
|
-
activation: data.activation || "manual",
|
|
372
|
-
tags: data.tags || [],
|
|
373
|
-
userInvocable: data.userInvocable !== false,
|
|
374
|
-
handler: data.handler || null,
|
|
375
|
-
capabilities: data.capabilities || [],
|
|
376
|
-
os: data.os || [],
|
|
377
|
-
// CLI pack extended fields
|
|
378
|
-
executionMode: data.executionMode || null,
|
|
379
|
-
cliDomain: data.cliDomain || null,
|
|
380
|
-
cliVersionHash: data.cliVersionHash || null,
|
|
381
|
-
dirName: entry.name,
|
|
382
|
-
hasHandler: fs.existsSync(path.join(dir, entry.name, "handler.js")),
|
|
383
|
-
body,
|
|
384
|
-
// Skill-Embedded MCP: inline server declarations in a
|
|
385
|
-
// ```mcp-servers fenced code block. Empty array if absent.
|
|
386
|
-
mcpServers: parseSkillMcpServers(body),
|
|
387
|
-
source: layer,
|
|
388
|
-
skillDir: path.join(dir, entry.name),
|
|
389
|
-
});
|
|
390
|
-
} catch {
|
|
391
|
-
// Skip malformed skill files
|
|
370
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
371
|
+
} catch {
|
|
372
|
+
return; // Directory unreadable
|
|
373
|
+
}
|
|
374
|
+
for (const entry of entries) {
|
|
375
|
+
if (!entry.isDirectory()) continue;
|
|
376
|
+
const skillDir = path.join(dir, entry.name);
|
|
377
|
+
const skillMd = path.join(skillDir, "SKILL.md");
|
|
378
|
+
if (!fs.existsSync(skillMd)) {
|
|
379
|
+
// Grouping folder → descend (bounded) to find nested skills.
|
|
380
|
+
if (depth < MAX_SKILL_NEST_DEPTH) {
|
|
381
|
+
this._collectSkills(skillDir, layer, out, depth + 1);
|
|
392
382
|
}
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
try {
|
|
386
|
+
const content = fs.readFileSync(skillMd, "utf-8");
|
|
387
|
+
const { data, body } = parseSkillMd(content);
|
|
388
|
+
|
|
389
|
+
out.push({
|
|
390
|
+
id: data.name || entry.name,
|
|
391
|
+
displayName: data.displayName || entry.name,
|
|
392
|
+
description: data.description || "",
|
|
393
|
+
version: data.version || "1.0.0",
|
|
394
|
+
category: data.category || "uncategorized",
|
|
395
|
+
activation: data.activation || "manual",
|
|
396
|
+
tags: data.tags || [],
|
|
397
|
+
userInvocable: data.userInvocable !== false,
|
|
398
|
+
handler: data.handler || null,
|
|
399
|
+
capabilities: data.capabilities || [],
|
|
400
|
+
os: data.os || [],
|
|
401
|
+
// CLI pack extended fields
|
|
402
|
+
executionMode: data.executionMode || null,
|
|
403
|
+
cliDomain: data.cliDomain || null,
|
|
404
|
+
cliVersionHash: data.cliVersionHash || null,
|
|
405
|
+
dirName: entry.name,
|
|
406
|
+
hasHandler: fs.existsSync(path.join(skillDir, "handler.js")),
|
|
407
|
+
body,
|
|
408
|
+
// Skill-Embedded MCP: inline server declarations in a
|
|
409
|
+
// ```mcp-servers fenced code block. Empty array if absent.
|
|
410
|
+
mcpServers: parseSkillMcpServers(body),
|
|
411
|
+
source: layer,
|
|
412
|
+
skillDir,
|
|
413
|
+
});
|
|
414
|
+
} catch {
|
|
415
|
+
// Skip malformed skill files
|
|
393
416
|
}
|
|
394
|
-
} catch {
|
|
395
|
-
// Directory unreadable
|
|
396
417
|
}
|
|
397
|
-
|
|
398
|
-
return skills;
|
|
399
418
|
}
|
|
400
419
|
|
|
401
420
|
/**
|
|
@@ -23,6 +23,7 @@ import pathDefault from "node:path";
|
|
|
23
23
|
import { homedir } from "node:os";
|
|
24
24
|
import { execSync as execSyncDefault } from "node:child_process";
|
|
25
25
|
import { expandFileRefs } from "../runtime/file-ref-expander.js";
|
|
26
|
+
import { projectRootBase } from "./project-root.cjs";
|
|
26
27
|
|
|
27
28
|
const _deps = { fs: fsDefault, path: pathDefault, execSync: execSyncDefault };
|
|
28
29
|
|
|
@@ -62,16 +63,31 @@ export const BANG_TIMEOUT_MS = 10_000;
|
|
|
62
63
|
* on a name clash). `opts.home` overrides the personal root for tests.
|
|
63
64
|
*/
|
|
64
65
|
export function commandDirs(cwd = process.cwd(), opts = {}) {
|
|
66
|
+
const fs = opts.deps?.fs || _deps.fs;
|
|
65
67
|
const path = opts.deps?.path || _deps.path;
|
|
66
68
|
const home = opts.home || homedir();
|
|
67
69
|
// Project-native `.chainlesschain/commands/` takes precedence, then the
|
|
68
70
|
// Claude-Code-portable `.claude/commands/` (so existing definitions work
|
|
69
71
|
// unchanged), then personal. Both project dirs share the "project" scope.
|
|
70
|
-
|
|
72
|
+
const dirs = [
|
|
71
73
|
{ dir: path.join(cwd, ".chainlesschain", "commands"), scope: "project" },
|
|
72
74
|
{ dir: path.join(cwd, ".claude", "commands"), scope: "project" },
|
|
73
|
-
{ dir: path.join(home, ".claude", "commands"), scope: "personal" },
|
|
74
75
|
];
|
|
76
|
+
// Subdirectory run: also scan the project-root `.claude` (cwd stays closest
|
|
77
|
+
// and wins on a name clash via discoverCommands' reverse + last-write-wins).
|
|
78
|
+
const root = projectRootBase(cwd, { fs, path });
|
|
79
|
+
if (root) {
|
|
80
|
+
dirs.push({
|
|
81
|
+
dir: path.join(root, ".chainlesschain", "commands"),
|
|
82
|
+
scope: "project",
|
|
83
|
+
});
|
|
84
|
+
dirs.push({
|
|
85
|
+
dir: path.join(root, ".claude", "commands"),
|
|
86
|
+
scope: "project",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
dirs.push({ dir: path.join(home, ".claude", "commands"), scope: "personal" });
|
|
90
|
+
return dirs;
|
|
75
91
|
}
|
|
76
92
|
|
|
77
93
|
/** Recursively collect `*.md` files under `dir` as `{file, rel}` (rel uses /). */
|