mulmoterminal 8.3.0 → 8.4.0

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.
Files changed (122) hide show
  1. package/README.md +5 -0
  2. package/blueprints/local/checks/dev-proxy.mjs +31 -0
  3. package/blueprints/local/checks/devProxyRules.d.mts +2 -0
  4. package/blueprints/local/checks/devProxyRules.mjs +28 -0
  5. package/blueprints/local/checks/scaffold.sh +1 -0
  6. package/blueprints/local/checks/smoke.sh +3 -1
  7. package/blueprints/local/skills/scaffold/SKILL.md +4 -0
  8. package/common/appActions.ts +2 -0
  9. package/common/blueprint/personLanguage.ts +9 -0
  10. package/common/keymap.ts +1 -0
  11. package/common/resolveRelativeSegments.ts +17 -0
  12. package/common/skillsSh.ts +49 -0
  13. package/dist/assets/{abnfDiagram-O67JEVCF-CKlUuyns.js → abnfDiagram-O67JEVCF-BMJe_qSR.js} +1 -1
  14. package/dist/assets/architecture-7GRP2DOG-CQYRVr5T.js +1 -0
  15. package/dist/assets/{architectureDiagram-NJMV4G6O-Cr60a0xK.js → architectureDiagram-NJMV4G6O-CseCKT16.js} +1 -1
  16. package/dist/assets/{blockDiagram-BEXU5L5S-B46LCZEF.js → blockDiagram-BEXU5L5S-C_bBMH24.js} +1 -1
  17. package/dist/assets/{c4Diagram-YGBWAQC7-T1j5qLhM.js → c4Diagram-YGBWAQC7-Bg6KmyZJ.js} +1 -1
  18. package/dist/assets/channel-B5axSRgo.js +1 -0
  19. package/dist/assets/{chunk-3FUC2YCW-BFPbRdvj.js → chunk-3FUC2YCW-tIeOlJZX.js} +1 -1
  20. package/dist/assets/{chunk-5DYCD2WN-DTwKhTLB.js → chunk-5DYCD2WN-CinKT1P6.js} +1 -1
  21. package/dist/assets/{chunk-742MDFTN-BlcDxB5j.js → chunk-742MDFTN-CE6nTSpj.js} +1 -1
  22. package/dist/assets/{chunk-7INBJB4K-xunRHb1j.js → chunk-7INBJB4K-TFtrTNHV.js} +1 -1
  23. package/dist/assets/{chunk-7M6MHVWA-DX65iUsh.js → chunk-7M6MHVWA-DmHoJgOY.js} +1 -1
  24. package/dist/assets/{chunk-7PRAP22T-0bKDqaeU.js → chunk-7PRAP22T-BUWRPJc_.js} +1 -1
  25. package/dist/assets/{chunk-GTNCS2PH-BN14lNpR.js → chunk-GTNCS2PH-CSNeDal_.js} +1 -1
  26. package/dist/assets/{chunk-GWA4HPMP-BAet7AvE.js → chunk-GWA4HPMP-C8BOPXNx.js} +1 -1
  27. package/dist/assets/{chunk-MBY4JIJT-DByeaoOT.js → chunk-MBY4JIJT-DEORW7Ck.js} +1 -1
  28. package/dist/assets/{chunk-NETBCI7D-DS63BA-9.js → chunk-NETBCI7D-L49Jk_E9.js} +1 -1
  29. package/dist/assets/{chunk-O7XYJQB3-RWvzInqy.js → chunk-O7XYJQB3-CqjPWB3Q.js} +1 -1
  30. package/dist/assets/{chunk-UA2S7LBM-D5BRkqDP.js → chunk-UA2S7LBM-cthu0rPF.js} +1 -1
  31. package/dist/assets/{chunk-WEXAMYUT-CWS1aTuv.js → chunk-WEXAMYUT-wQNZySO6.js} +1 -1
  32. package/dist/assets/{chunk-Z7XXMR3K-BmgvUbyV.js → chunk-Z7XXMR3K-D9D1mU1_.js} +1 -1
  33. package/dist/assets/{chunk-ZIGJFQKS-B7uoh93M.js → chunk-ZIGJFQKS-Cx4E0oT8.js} +1 -1
  34. package/dist/assets/{classDiagram-v2-NBCMYWYE-_Zn3IQPd.js → classDiagram-v2-NBCMYWYE-B1LN5Zlb.js} +1 -1
  35. package/dist/assets/{cynefin-OW5HDTMX-BhwDPtZE.js → cynefin-OW5HDTMX-DmROkadB.js} +1 -1
  36. package/dist/assets/{cynefinDiagram-VND7K2PF-DQRFRLyY.js → cynefinDiagram-VND7K2PF-BFRJrkh4.js} +1 -1
  37. package/dist/assets/{dagre-6A5THRUB-CAyH0RVf.js → dagre-6A5THRUB-I6gOhVGS.js} +1 -1
  38. package/dist/assets/{diagram-22UHCM2B-CDVq4xZt.js → diagram-22UHCM2B-D5Wflzqf.js} +1 -1
  39. package/dist/assets/{diagram-3UASUU5V-71cR4x2a.js → diagram-3UASUU5V-Ce90GEZ1.js} +1 -1
  40. package/dist/assets/{diagram-ATOU4E4O-B77AU3Mm.js → diagram-ATOU4E4O-60ZXyYBU.js} +1 -1
  41. package/dist/assets/{diagram-CDSNMT55-BorMYeZ1.js → diagram-CDSNMT55-hiXGNU8j.js} +1 -1
  42. package/dist/assets/{diagram-MLGK6HIB-DkE6ngy6.js → diagram-MLGK6HIB-BR88YYX6.js} +1 -1
  43. package/dist/assets/{diagram-MPIPVDR6-CgGs4ob9.js → diagram-MPIPVDR6-Cqnbn4F4.js} +1 -1
  44. package/dist/assets/{dist-BQUQODA8.js → dist-BmjYs08q.js} +1 -1
  45. package/dist/assets/{dist-KoB2Fn7k.js → dist-Dq0OztIz.js} +1 -1
  46. package/dist/assets/{dist-DYLBD_lC.js → dist-gE0rejm0.js} +1 -1
  47. package/dist/assets/{dist-wRL2l7Jx.js → dist-nEjBbvRK.js} +1 -1
  48. package/dist/assets/{dist-CzIpHy0d.js → dist-xl1LbNic.js} +1 -1
  49. package/dist/assets/{ebnfDiagram-ZINNZB2B-DLAg5XxB.js → ebnfDiagram-ZINNZB2B-CugVDzQo.js} +1 -1
  50. package/dist/assets/{elk-276RUBZZ-D9nvt0XC.js → elk-276RUBZZ-DTXnKIqg.js} +1 -1
  51. package/dist/assets/{erDiagram-OPXOYQCR-D3WDLlbz.js → erDiagram-OPXOYQCR-DnreR4ia.js} +1 -1
  52. package/dist/assets/eventmodeling-NTZA5JFV-CeDzNLTA.js +1 -0
  53. package/dist/assets/flowDiagram-KWPJA3E3-D61LNXTW.js +1 -0
  54. package/dist/assets/{ganttDiagram-FUAMR5RP-BGVSRLOl.js → ganttDiagram-FUAMR5RP-BUvHkK--.js} +1 -1
  55. package/dist/assets/{gitGraph-4MIJSDKK-CVyREC8W.js → gitGraph-4MIJSDKK-C27fy8A_.js} +1 -1
  56. package/dist/assets/{gitGraphDiagram-X574FWY7-BSmV1hek.js → gitGraphDiagram-X574FWY7-CA-iSIM4.js} +1 -1
  57. package/dist/assets/{index-eTV11Zyw.js → index-BuZJeFfI.js} +307 -307
  58. package/dist/assets/index-D1X0QBlU.css +1 -0
  59. package/dist/assets/{info-A6RAGUB7-Ch23BJyi.js → info-A6RAGUB7-YNvMX-bh.js} +1 -1
  60. package/dist/assets/{infoDiagram-VRGFBTTK-Cq8RzFTi.js → infoDiagram-VRGFBTTK-ylnH1h3f.js} +1 -1
  61. package/dist/assets/{ishikawaDiagram-OU5B5YK6-B3Bx_dM4.js → ishikawaDiagram-OU5B5YK6-BZYB967i.js} +1 -1
  62. package/dist/assets/{journeyDiagram-ZHPQQLJL-3C2yy2Ai.js → journeyDiagram-ZHPQQLJL-DHoAW6ud.js} +1 -1
  63. package/dist/assets/{kanban-definition-PNTS6WVX-X09o9QMI.js → kanban-definition-PNTS6WVX-ChY5lEVB.js} +1 -1
  64. package/dist/assets/{line-DRK0p1A0.js → line-BlQ-oYXZ.js} +1 -1
  65. package/dist/assets/{mermaid-parser.core-jR7u2UoU.js → mermaid-parser.core-BglGjiX7.js} +3 -3
  66. package/dist/assets/{mermaid.core-BRUnk_mY.js → mermaid.core-D_feebOp.js} +4 -4
  67. package/dist/assets/{mindmap-definition-NLK3R4M7-BLFj8zux.js → mindmap-definition-NLK3R4M7-DEmf5lft.js} +1 -1
  68. package/dist/assets/{packet-AYTQ26CC-DJdWa_92.js → packet-AYTQ26CC-Btozglzp.js} +1 -1
  69. package/dist/assets/{pegDiagram-GJSIUBJH-DJhNtjB1.js → pegDiagram-GJSIUBJH-CxzI81VG.js} +1 -1
  70. package/dist/assets/{pie-WAS4IAKB-CZdX7gwc.js → pie-WAS4IAKB-CHdIL4XS.js} +1 -1
  71. package/dist/assets/{pieDiagram-5QR66LMP-6SpfMbRT.js → pieDiagram-5QR66LMP-CYuG-K8p.js} +1 -1
  72. package/dist/assets/{quadrantDiagram-O4NWA36T-1j2j6cCS.js → quadrantDiagram-O4NWA36T-olbaJGbx.js} +1 -1
  73. package/dist/assets/{radar-RG4KPBEZ-ByiCNLS6.js → radar-RG4KPBEZ-CXfmqza_.js} +1 -1
  74. package/dist/assets/{railroad-74A4TZTK-C-JsNW52.js → railroad-74A4TZTK-DktczNqs.js} +1 -1
  75. package/dist/assets/railroad-abnf-HS5TGJTU-BEOQf0Us.js +1 -0
  76. package/dist/assets/railroad-ebnf-LZEXJU2U-rrPJi-cs.js +1 -0
  77. package/dist/assets/railroad-peg-WCYAUIDC-tX6-lMU7.js +1 -0
  78. package/dist/assets/{railroadDiagram-XR7U4H2S-7dFhcasc.js → railroadDiagram-XR7U4H2S-Ji9BR77e.js} +1 -1
  79. package/dist/assets/{requirementDiagram-PLB6GJNP-BAqomR3o.js → requirementDiagram-PLB6GJNP-BxNVcE9-.js} +1 -1
  80. package/dist/assets/{sankeyDiagram-IPEJSGJF-DhkXOhoR.js → sankeyDiagram-IPEJSGJF-CvdwvhuZ.js} +1 -1
  81. package/dist/assets/{sequenceDiagram-PO4LG4MO-lDBjo1e1.js → sequenceDiagram-PO4LG4MO-BF4SIny2.js} +1 -1
  82. package/dist/assets/{stateDiagram-v2-GCMORJYK-CRo5UhQk.js → stateDiagram-v2-GCMORJYK-C3y6MZWu.js} +1 -1
  83. package/dist/assets/{swimlanes-2SLR337P-7TmzpJwY.js → swimlanes-2SLR337P-K7ElGbB9.js} +1 -1
  84. package/dist/assets/swimlanesDiagram-TC7HE7FX-CFlahFb_.js +8 -0
  85. package/dist/assets/{timeline-definition-EJHVYXUP-5aLv5D93.js → timeline-definition-EJHVYXUP-D_zYXuLh.js} +1 -1
  86. package/dist/assets/{treeView-Q6P3EWNA-D5CE4D1g.js → treeView-Q6P3EWNA-iyBeMAT-.js} +1 -1
  87. package/dist/assets/{treemap-WGGIJYW6-BMUEZMzm.js → treemap-WGGIJYW6-DvCmDE8k.js} +1 -1
  88. package/dist/assets/{usecaseDiagram-POWQR4AR-DpHwlMrg.js → usecaseDiagram-POWQR4AR-C996nxeH.js} +1 -1
  89. package/dist/assets/{vennDiagram-UO4OBE2U-5VroYfor.js → vennDiagram-UO4OBE2U--FWf99Gr.js} +1 -1
  90. package/dist/assets/{wardley-WFR3VGLG-jMOUNxbQ.js → wardley-WFR3VGLG-De248F-Z.js} +1 -1
  91. package/dist/assets/{wardleyDiagram-VNRHLVJA-DZq6IR2g.js → wardleyDiagram-VNRHLVJA-DGGVc5GT.js} +1 -1
  92. package/dist/assets/{xychartDiagram-PMCCYNJV-xtu9TBWy.js → xychartDiagram-PMCCYNJV-DnWp9mGa.js} +1 -1
  93. package/dist/index.html +2 -2
  94. package/docs/guide/en/v8.4.0.md +84 -0
  95. package/docs/guide/ja/v8.4.0.md +81 -0
  96. package/package.json +8 -6
  97. package/server/agents/cursor-last-turn.ts +1 -1
  98. package/server/backends/html.ts +12 -28
  99. package/server/backends/shapescript.ts +14 -27
  100. package/server/backends/sharedApp/declare.ts +80 -57
  101. package/server/backends/skillsSh.ts +106 -0
  102. package/server/backends/sourceEditorDispatchRoute.ts +38 -0
  103. package/server/config/agent-entry-routes.ts +4 -24
  104. package/server/config/on-disk-entry.ts +28 -0
  105. package/server/config/theme-entry-routes.ts +3 -8
  106. package/server/files/files-tree-routes.ts +11 -4
  107. package/server/files/mdImageSrc.ts +3 -12
  108. package/server/routes/skill-catalog-routes.ts +46 -2
  109. package/server/session/claude-fullscreen-env.ts +20 -0
  110. package/server/session/claude-fullscreen.ts +38 -0
  111. package/server/session/spawn-claude.ts +3 -1
  112. package/server/session/transcript-view-cursor.ts +1 -8
  113. package/server/skills/mulmoterminal-keys/SKILL.md +1 -1
  114. package/dist/assets/architecture-7GRP2DOG-CQzNA5AV.js +0 -1
  115. package/dist/assets/channel-C8wFkwL-.js +0 -1
  116. package/dist/assets/eventmodeling-NTZA5JFV-CU2CI2_j.js +0 -1
  117. package/dist/assets/flowDiagram-KWPJA3E3-DYQcChuP.js +0 -1
  118. package/dist/assets/index-C9dQ4nPc.css +0 -1
  119. package/dist/assets/railroad-abnf-HS5TGJTU-Bk0OY70O.js +0 -1
  120. package/dist/assets/railroad-ebnf-LZEXJU2U-BNzqEfH4.js +0 -1
  121. package/dist/assets/railroad-peg-WCYAUIDC-DiFnHh30.js +0 -1
  122. package/dist/assets/swimlanesDiagram-TC7HE7FX-S0DcrBn_.js +0 -8
package/README.md CHANGED
@@ -1758,6 +1758,11 @@ narrow and tall for one record you are discussing — and each position keeps it
1758
1758
  each enabled plugin (skills shown as `plugin:skill`), and the `.claude/skills` of each folder a
1759
1759
  terminal has run in (folders with none are left out). A project skill with the same name as one
1760
1760
  of yours is marked as overriding it. The search (name, description or folder) narrows both lists.
1761
+ Switch to **skills.sh** to search the public directory at [skills.sh](https://skills.sh) for
1762
+ skills you do not have yet and read one before installing it: its `SKILL.md`, every file it would
1763
+ bring, and a warning listing the files that can run code. Nothing is installed from the viewer —
1764
+ it shows the `npx skills add …` line to copy and run yourself. Your search words go to skills.sh
1765
+ only when you press **Search**.
1761
1766
  - **Grid of parallel sessions** — the + Terminal / grid view runs many sessions at once,
1762
1767
  auto-sizing by count across pages. Cell borders signal state at a glance — **working**
1763
1768
  (pulsing blue), **blocked** (amber — needs a permission / answer), **done** (blue —
@@ -0,0 +1,31 @@
1
+ // Resolves the app's own Vite config through the app's own Vite, plugins included, as `yarn dev` would, and holds its proxy to
2
+ // devProxyRules.mjs. Prints each problem and exits 1 when there is any; an app without a Vite config has no proxy. The
3
+ // config is looked for at the root and in client/, where the scaffold keeps the screens.
4
+ import { existsSync } from "node:fs";
5
+ import { createRequire } from "node:module";
6
+ import path from "node:path";
7
+ import { pathToFileURL } from "node:url";
8
+ import { proxyProblems } from "./devProxyRules.mjs";
9
+
10
+ const CONFIG_NAMES = ["vite.config.ts", "vite.config.mts", "vite.config.cts", "vite.config.js", "vite.config.mjs", "vite.config.cjs"];
11
+ const CONFIG_DIRS = [".", "client"];
12
+ const configFiles = CONFIG_DIRS.flatMap((dir) => CONFIG_NAMES.map((name) => path.resolve(dir, name))).filter((file) => existsSync(file));
13
+ if (configFiles.length === 0) process.exit(0);
14
+
15
+ let vite;
16
+ try {
17
+ vite = await import(pathToFileURL(createRequire(path.resolve("package.json")).resolve("vite")).href);
18
+ } catch (error) {
19
+ console.error(`could not load this app's vite to read its config: ${error instanceof Error ? error.message : error}`);
20
+ process.exit(1);
21
+ }
22
+ const problemsOf = async (configFile) => {
23
+ // resolveConfig, not loadConfigFromFile: a plugin's config hook can add or change the proxy, and the dev server uses
24
+ // what the hooks leave.
25
+ const resolved = await vite.resolveConfig({ configFile, logLevel: "silent" }, "serve", "development");
26
+ const label = path.relative(process.cwd(), configFile);
27
+ return proxyProblems(resolved.server?.proxy).map((problem) => problem.replace("vite.config", label));
28
+ };
29
+ const problems = (await Promise.all(configFiles.map(problemsOf))).flat();
30
+ problems.forEach((problem) => console.error(problem));
31
+ process.exit(problems.length > 0 ? 1 : 0);
@@ -0,0 +1,2 @@
1
+ // Types for devProxyRules.mjs, which the pack runs with plain node and the specs import.
2
+ export declare function proxyProblems(proxy: Readonly<Record<string, unknown>> | null | undefined): string[];
@@ -0,0 +1,28 @@
1
+ // The dev server's proxy must hand the API the Host the browser used. The API refuses a change whose Origin is not its
2
+ // own Host (skills/api), and under `yarn dev` the browser's Origin is the Vite port: a proxy that rewrites the Host to
3
+ // the API's own port makes every change look cross-site. Vite rewrites it for a proxy written as a plain string (it
4
+ // adds changeOrigin: true) and for one that sets changeOrigin: true itself.
5
+
6
+ /** Every proxy entry of a resolved Vite config that rewrites the Host, as a problem the agent can act on. */
7
+ export function proxyProblems(proxy) {
8
+ if (proxy === undefined || proxy === null) return [];
9
+ return Object.entries(proxy).flatMap(([context, options]) => {
10
+ const where = `vite.config server.proxy["${context}"]`;
11
+ if (typeof options === "string") {
12
+ return [
13
+ `${where} is the string ${JSON.stringify(options)}: Vite then rewrites the Host to the API's port, so the API refuses every change made in yarn dev as cross-site. Write { target: ${JSON.stringify(options)}, changeOrigin: false }`,
14
+ ];
15
+ }
16
+ const rewritten = Object.keys(options?.headers ?? {}).filter((name) => ["host", "origin"].includes(name.toLowerCase()));
17
+ return [
18
+ ...(options?.changeOrigin === true
19
+ ? [
20
+ `${where} sets changeOrigin: true: the API then sees its own port as the Host while the browser sends the Vite port as the Origin, and refuses every change made in yarn dev as cross-site. Set changeOrigin: false`,
21
+ ]
22
+ : []),
23
+ ...(rewritten.length > 0
24
+ ? [`${where} sets the ${rewritten.join(" and ")} header itself: the API compares Origin with Host, so leave both as the browser sent them`]
25
+ : []),
26
+ ];
27
+ });
28
+ }
@@ -8,5 +8,6 @@ for d in server/migrations test; do
8
8
  [ -d "$d" ] || { echo "missing $d/" >&2; exit 1; }
9
9
  done
10
10
  grep -q '"start"' package.json || { echo "package.json has no start script" >&2; exit 1; }
11
+ node --no-warnings "$(dirname "$0")/dev-proxy.mjs"
11
12
  yarn build
12
13
  yarn test
@@ -1,7 +1,9 @@
1
1
  #!/bin/sh
2
2
  # Builds, starts the built server on a spare port with the default settings, and checks that
3
- # /api/health and / answer — and that, left at its defaults, it listens on this computer only.
3
+ # /api/health and / answer — and that, left at its defaults, it listens on this computer only. First, that the dev
4
+ # server's proxy keeps the Host, or every change made under yarn dev is refused as cross-site (dev-proxy.mjs).
4
5
  set -eu
6
+ node --no-warnings "$(dirname "$0")/dev-proxy.mjs"
5
7
  . "$(dirname "$0")/serve.sh"
6
8
  curl -fsS --max-time 5 "http://127.0.0.1:$port/api/health" | grep -q '"ok":true' || { echo '/api/health did not answer {"ok":true}' >&2; exit 1; }
7
9
  curl -fsS --max-time 5 "http://127.0.0.1:$port/" | grep -q 'id="app"' || { echo "/ does not serve the app" >&2; exit 1; }
@@ -20,6 +20,10 @@ data/ the database file lives here; data/*.db is in .gitignore
20
20
  does not ship.
21
21
  - Scripts: `dev` (server + vite together), `build` (vite build to dist/client and the server with tsc or tsup to
22
22
  dist/server), `start` (runs the BUILT server: `node dist/server/index.js`), `test` (`vitest run`).
23
+ - Under `yarn dev`, Vite forwards `/api` to the server. Write the proxy as an object with `changeOrigin: false`
24
+ (`"/api": { target: "http://127.0.0.1:3000", changeOrigin: false }`), never as a plain string: a string makes Vite
25
+ rewrite the `Host` to the server's port, and the API, which refuses a change whose `Origin` is not its own `Host`,
26
+ then refuses every change made in development. The check loads the Vite config and says so.
23
27
  - `GET /api/health` answers `{ "ok": true }`. In production the server serves `dist/client` and falls back to
24
28
  `index.html` for screen routes.
25
29
  - The server exports a function that builds the app for a given database path, so tests run against a
@@ -14,6 +14,7 @@ export const SCREEN_ACTIONS = [
14
14
  "screen-rooms",
15
15
  "screen-blueprints",
16
16
  "screen-worklog",
17
+ "screen-skills",
17
18
  ] as const satisfies readonly KeymapAction[];
18
19
 
19
20
  export const ORDER_ACTIONS = ["order-auto", "order-manual", "order-priority"] as const satisfies readonly KeymapAction[];
@@ -52,6 +53,7 @@ const SCREEN_OF = {
52
53
  "screen-rooms": "rooms",
53
54
  "screen-blueprints": "blueprints",
54
55
  "screen-worklog": "worklog",
56
+ "screen-skills": "skills",
55
57
  } as const satisfies Record<ScreenAction, string>;
56
58
 
57
59
  /** The screen a screen action goes to. */
@@ -15,6 +15,15 @@ export const PERSON_LANGUAGES: Readonly<Record<PersonLanguage, string>> = {
15
15
  ko: "Korean",
16
16
  };
17
17
 
18
+ /** Each language in its own words, for a choice the person makes whatever language the screen is in. */
19
+ export const PERSON_LANGUAGE_NAMES: Readonly<Record<PersonLanguage, string>> = {
20
+ en: "English",
21
+ ja: "日本語",
22
+ "zh-CN": "简体中文",
23
+ "zh-TW": "繁體中文",
24
+ ko: "한국어",
25
+ };
26
+
18
27
  export const isPersonLanguage = (raw: string): raw is PersonLanguage => personLanguageSchema.safeParse(raw).success;
19
28
 
20
29
  /** The prompt line that says it; none for a build started before the language was recorded. */
package/common/keymap.ts CHANGED
@@ -61,6 +61,7 @@ export const KEYMAP_ACTIONS = [
61
61
  "screen-rooms",
62
62
  "screen-blueprints",
63
63
  "screen-worklog",
64
+ "screen-skills",
64
65
  "settings-open",
65
66
  "sound-toggle",
66
67
  "view-toggle",
@@ -0,0 +1,17 @@
1
+ // Lexical only: no filesystem, no separator other than `/`. Callers normalise backslashes first,
2
+ // and each decides for itself what root the result is relative to — this does not widen any.
3
+
4
+ /** `rel` with `.` and empty segments dropped and `..` applied, `/`-joined — or null when it climbs
5
+ * above its root, or resolves to the root itself (there is then no file to name). */
6
+ export function resolveRelativeSegments(rel: string): string | null {
7
+ const out: string[] = [];
8
+ for (const segment of rel.split("/")) {
9
+ if (segment === "" || segment === ".") continue;
10
+ if (segment === "..") {
11
+ if (out.pop() === undefined) return null;
12
+ continue;
13
+ }
14
+ out.push(segment);
15
+ }
16
+ return out.length ? out.join("/") : null;
17
+ }
@@ -0,0 +1,49 @@
1
+ // Searching skills.sh from the Skills viewer (#2835): the shapes the server hands the overlay, and the
2
+ // rules both sides decide from. Read-only — nothing here installs a skill; the overlay offers the
3
+ // `npx skills add` line for the user to run themselves.
4
+
5
+ /** One search hit. `source` is the GitHub `owner/repo`, `skillId` the skill's directory name there. */
6
+ export interface RemoteSkill {
7
+ source: string;
8
+ skillId: string;
9
+ name: string;
10
+ installs: number;
11
+ }
12
+
13
+ export interface RemoteSkillFile {
14
+ path: string;
15
+ bytes: number;
16
+ }
17
+
18
+ /** A skill as skills.sh serves it: its SKILL.md, and every file it would bring with it. */
19
+ export interface RemoteSkillDoc {
20
+ markdown: string;
21
+ files: RemoteSkillFile[];
22
+ }
23
+
24
+ // GitHub's own character set for owner and repository names, and the skill-directory names skills.sh
25
+ // serves. Anything else is refused before it is put into a URL.
26
+ const OWNER_REPO_RE = /^[A-Za-z0-9-]+\/[A-Za-z0-9._-]+$/;
27
+ const SKILL_ID_RE = /^[A-Za-z0-9._-]+$/;
28
+
29
+ export const isRemoteSource = (value: string): boolean => OWNER_REPO_RE.test(value) && !value.split("/").some((part) => part === "." || part === "..");
30
+ export const isRemoteSkillId = (value: string): boolean => SKILL_ID_RE.test(value) && value !== "." && value !== "..";
31
+
32
+ /** The line that installs it with the official CLI, for the user to run — the viewer never runs it. */
33
+ export const installCommand = (skill: Pick<RemoteSkill, "source" | "skillId">): string => `npx skills add ${skill.source} --skill ${skill.skillId}`;
34
+
35
+ export const skillsShPageUrl = (skill: Pick<RemoteSkill, "source" | "skillId">): string => `https://skills.sh/${skill.source}/${skill.skillId}`;
36
+
37
+ // A skill is instructions the agent follows with the user's permissions; files that RUN are the part
38
+ // worth pointing out before anyone installs it.
39
+ const EXECUTABLE_EXTENSIONS = new Set(["sh", "bash", "zsh", "py", "js", "mjs", "cjs", "ts", "rb", "pl", "php", "ps1", "bat", "cmd", "exe"]);
40
+
41
+ export function isExecutableFile(path: string): boolean {
42
+ const name = path.split("/").pop() ?? "";
43
+ const dot = name.lastIndexOf(".");
44
+ return dot > 0 && EXECUTABLE_EXTENSIONS.has(name.slice(dot + 1).toLowerCase());
45
+ }
46
+
47
+ /** Whether a skill of this name is already on disk, so the hit can say so. Matched by name, the way
48
+ * claude resolves `/name` — the same name from another repository still counts. */
49
+ export const isInstalledLocally = (skill: Pick<RemoteSkill, "skillId">, localSlugs: ReadonlySet<string>): boolean => localSlugs.has(skill.skillId);
@@ -1 +1 @@
1
- import{m as e,t}from"./mermaid-parser.core-jR7u2UoU.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-CllyRBe0.js";import"./chunk-O7XYJQB3-RWvzInqy.js";import{n as i,r as a,t as o}from"./chunk-GTNCS2PH-BN14lNpR.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-BRUnk_mY.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
1
+ import{m as e,t}from"./mermaid-parser.core-BglGjiX7.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-CllyRBe0.js";import"./chunk-O7XYJQB3-CqjPWB3Q.js";import{n as i,r as a,t as o}from"./chunk-GTNCS2PH-CSNeDal_.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-D_feebOp.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
@@ -0,0 +1 @@
1
+ import"./chunk-FOHPRMQF-DzxwRta7.js";import{M as e}from"./mermaid-parser.core-BglGjiX7.js";export{e as createArchitectureServices};