kennel 0.2.11 → 0.2.13
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/dist/cli/src/plugins/external.js +19 -7
- package/dist/cli/src/site/server-plugins.d.ts +1 -4
- package/dist/core/api-client.js +3 -11
- package/dist/core/runtime.js +84 -695
- package/dist/package/preview.js +99 -729
- package/dist/plugins/external.js +19 -7
- package/dist/site/server-plugins.d.ts +1 -4
- package/dist/site/server-plugins.js +28 -537
- package/kernel/apps/web/package.json +0 -1
- package/kernel/apps/web/src/app.css +0 -1
- package/kernel/apps/web/src/app.tsx +7 -24
- package/kernel/apps/web/src/folder-plugin-view.tsx +6 -3
- package/kernel/apps/web/src/plugins.ts +2 -14
- package/kernel/apps/web/vite.config.ts +22 -20
- package/kernel/packages/api/openapi.json +85 -224
- package/kernel/packages/api/package.json +0 -1
- package/kernel/packages/api/src/contracts/schemas.ts +1 -9
- package/kernel/packages/api/src/server/folder-metadata-plugin.ts +9 -151
- package/kernel/packages/api/src/server/plugins.ts +11 -26
- package/kernel/packages/api/src/shared/viewer-route.ts +3 -5
- package/kernel/packages/api-client/src/generated.d.ts +16 -53
- package/kernel/packages/markdown/README.md +2 -2
- package/kernel/packages/notes/package.json +1 -0
- package/kernel/packages/notes/src/client.tsx +0 -1
- package/kernel/packages/notes/src/manifest.ts +7 -0
- package/kernel/packages/notes/src/pages/notes-page.tsx +1 -1
- package/kernel/packages/notes/src/ui/folder-notes-list.tsx +52 -7
- package/kernel/packages/plugins/SKILL.md +3 -2
- package/kernel/packages/plugins/package.json +5 -1
- package/kernel/packages/plugins/src/hooks.ts +24 -0
- package/kernel/packages/plugins/src/index.ts +1 -7
- package/kernel/packages/plugins/src/page.ts +0 -7
- package/kernel/packages/plugins/src/types.ts +8 -0
- package/kernel/packages/plugins/tsconfig.json +1 -1
- package/kernel/packages/plugins/tsup.config.ts +1 -0
- package/kernel/packages/ui/src/components/folder-activity.tsx +16 -98
- package/kernel/packages/ui/src/components/folder-landing.tsx +4 -0
- package/kernel/packages/ui/src/components/markdown-copy-block.tsx +78 -0
- package/kernel/packages/ui/src/components/pagination.tsx +88 -2
- package/kernel/packages/ui/src/components/plugin-icon.tsx +19 -0
- package/kernel/packages/ui/src/lib/folder-activity.ts +4 -17
- package/kernel/packages/ui/src/lib/source-components.tsx +12 -6
- package/kernel/packages/ui/src/styles/folder-activity.css +1 -31
- package/package.json +2 -2
- package/web/assets/{abnfDiagram-VRR7QNED-CSaxgLw6.js → abnfDiagram-VRR7QNED-Dt7QEF5H.js} +1 -1
- package/web/assets/app-C1j063QX.js +2 -0
- package/web/assets/app-options-98-a6ivv.js +25 -0
- package/web/assets/{app-view-header-Cpx74SQs.js → app-view-header-BJ9CWTE1.js} +1 -1
- package/web/assets/{arc-DOrTJz--.js → arc-PFB0H7oD.js} +1 -1
- package/web/assets/{architectureDiagram-ZJ3FMSHR-EjOjwlGK.js → architectureDiagram-ZJ3FMSHR-BHLqEXlZ.js} +1 -1
- package/web/assets/{ask-tray-DLEoRbpV.js → ask-tray-C3gBesHJ.js} +1 -1
- package/web/assets/{blockDiagram-677ZJIJ3-Dg2LWLOW.js → blockDiagram-677ZJIJ3-UbnYoYDg.js} +1 -1
- package/web/assets/{button-C6arH7zt.js → button-CuuAtS1I.js} +1 -1
- package/web/assets/{c4Diagram-LMCZKHZV-CWHqGPk8.js → c4Diagram-LMCZKHZV-4OSx1V4W.js} +1 -1
- package/web/assets/channel-BuvY5cQN.js +1 -0
- package/web/assets/{chunk-2Q5K7J3B-Dzz0QWV_.js → chunk-2Q5K7J3B-CgxJ1aJb.js} +1 -1
- package/web/assets/{chunk-32BRIVSS-BocStooX.js → chunk-32BRIVSS-Bfwxg2LM.js} +1 -1
- package/web/assets/{chunk-5VM5RSS4-D8BF5Y5h.js → chunk-5VM5RSS4-BZN9a2hI.js} +1 -1
- package/web/assets/{chunk-EX3LRPZG-CWMl9KkL.js → chunk-EX3LRPZG-CrH6hhqq.js} +1 -1
- package/web/assets/{chunk-JWPE2WC7-BZEr7iFk.js → chunk-JWPE2WC7-Ddn7ZSp8.js} +1 -1
- package/web/assets/{chunk-MOJQB5TN-DbKnLJ33.js → chunk-MOJQB5TN-9lJ7f_hI.js} +1 -1
- package/web/assets/{chunk-RYQCIY6F-BF9KWoi2.js → chunk-RYQCIY6F-QrFo_00s.js} +1 -1
- package/web/assets/{chunk-V7JOEXUC-e88zamUH.js → chunk-V7JOEXUC-Dn0lQjVf.js} +1 -1
- package/web/assets/{chunk-VR4S4FIN-NDHM58HJ.js → chunk-VR4S4FIN-DXVPySkB.js} +1 -1
- package/web/assets/{chunk-XXDRQBXY-BtzSzNoD.js → chunk-XXDRQBXY-CBiFDOdZ.js} +1 -1
- package/web/assets/classDiagram-OUVF2IWQ-DCYNCJhe.js +1 -0
- package/web/assets/classDiagram-v2-EOCWNBFH-DCYNCJhe.js +1 -0
- package/web/assets/client-DBJY3XDL.js +43 -0
- package/web/assets/client-DKJs0w4y.js +6 -0
- package/web/assets/{command-BWtewOrt.js → command-onjTnuXT.js} +1 -1
- package/web/assets/{copy-context-YESgZ_hu.js → copy-context-CciRaLNN.js} +1 -1
- package/web/assets/{cose-bilkent-JH36ORCC-i7x8jZ9M.js → cose-bilkent-JH36ORCC-CGRic2um.js} +1 -1
- package/web/assets/{cynefin-VYW2F7L2-D8HPrHMt.js → cynefin-VYW2F7L2-Blk0Lu0l.js} +1 -1
- package/web/assets/{cynefinDiagram-TSTJHNR4-BtkeCNXb.js → cynefinDiagram-TSTJHNR4-DpnnHRDK.js} +1 -1
- package/web/assets/{dagre-VKFMJZFB-oIThwshO.js → dagre-VKFMJZFB-llzMokKp.js} +1 -1
- package/web/assets/{diagram-FQU43EPY-DTuhEo03.js → diagram-FQU43EPY-DC6xHovR.js} +1 -1
- package/web/assets/{diagram-G47NLZAW-BcQ_4_fE.js → diagram-G47NLZAW-B8GVS3EA.js} +1 -1
- package/web/assets/{diagram-NH7WQ7WH-BA4VC8Du.js → diagram-NH7WQ7WH-DWUaARfh.js} +1 -1
- package/web/assets/{diagram-OA4YK3LP-BOpyrmty.js → diagram-OA4YK3LP-9Uaes_Yi.js} +1 -1
- package/web/assets/{diagram-WEI45ONY-BzrSPDJ7.js → diagram-WEI45ONY-DPPTBWud.js} +1 -1
- package/web/assets/document-D23WzFsW.js +23 -0
- package/web/assets/{ebnfDiagram-CCIWWBDH-BNV_4xDp.js → ebnfDiagram-CCIWWBDH-BPrKneNw.js} +1 -1
- package/web/assets/{entities-D0qpC3B9.js → entities-DPg0B8vd.js} +1 -1
- package/web/assets/{erDiagram-Q63AITRT-NT1La9pi.js → erDiagram-Q63AITRT-CFqYBcnb.js} +1 -1
- package/web/assets/{file-viewer-C1N6vaip.js → file-viewer-Ck73SsLA.js} +1 -1
- package/web/assets/{flowDiagram-23GEKE2U-CIYWUYkz.js → flowDiagram-23GEKE2U-C7RpYqaT.js} +1 -1
- package/web/assets/folder-filter-bar-DzejUj87.js +4 -0
- package/web/assets/{folder-image-Bz0xznQT.js → folder-image-BjIicmQ6.js} +1 -1
- package/web/assets/folder-landing-CCIXZfkp.js +55 -0
- package/web/assets/folder-list-TuRwuTss.js +1 -0
- package/web/assets/folder-mobile-bar-Bqnfwi-z.js +1 -0
- package/web/assets/folder-plugin-view-CrinCX1o.js +2 -0
- package/web/assets/{ganttDiagram-NO4QXBWP-DeUfoXQA.js → ganttDiagram-NO4QXBWP-Cz2sxU8F.js} +1 -1
- package/web/assets/{gitGraphDiagram-IHSO6WYX-DMeTgUPh.js → gitGraphDiagram-IHSO6WYX-BSuz0yF-.js} +1 -1
- package/web/assets/{index-CCXE8zc9.js → index-BVyeNcuc.js} +1 -1
- package/web/assets/{index-CegvVQ1C.js → index-Cg-gtBkw.js} +1 -1
- package/web/assets/index-DLn_2LPp.js +2 -0
- package/web/assets/{index-DY0VGBht.js → index-DbVDdnzL.js} +1 -1
- package/web/assets/index-uY9jLiL5.css +1 -0
- package/web/assets/{infoDiagram-FWYZ7A6U-DI_P8Ghi.js → infoDiagram-FWYZ7A6U-CpeKgqoS.js} +1 -1
- package/web/assets/input-Bz_puamS.js +9 -0
- package/web/assets/{ishikawaDiagram-FXEZZL3T-B8bM-8CD.js → ishikawaDiagram-FXEZZL3T-5c2Tmknb.js} +1 -1
- package/web/assets/{journeyDiagram-5HDEW3XC-pviYejXU.js → journeyDiagram-5HDEW3XC-Cu-wRkR4.js} +1 -1
- package/web/assets/{kanban-definition-HUTT4EX6-DfvdDvpU.js → kanban-definition-HUTT4EX6-BunSqkPe.js} +1 -1
- package/web/assets/{linear-DNOuKTk_.js → linear-C8e8bGVv.js} +1 -1
- package/web/assets/{mermaid.core-CisVJ_Cs.js → mermaid.core-DLgjY1g2.js} +4 -4
- package/web/assets/{metadata-C7E_6HIN.js → metadata-DEfJKlnd.js} +1 -1
- package/web/assets/{mindmap-definition-LN4V7U3C-DzdcaduN.js → mindmap-definition-LN4V7U3C-W9ENYFOD.js} +1 -1
- package/web/assets/{pegDiagram-2B236MQR-D_7xhlXd.js → pegDiagram-2B236MQR-0vPlHCFp.js} +1 -1
- package/web/assets/{pieDiagram-ENE6RG2P-CisikHMW.js → pieDiagram-ENE6RG2P-CakaveRV.js} +1 -1
- package/web/assets/{popover-D7MTK-sz.js → popover-3AMcPJpt.js} +1 -1
- package/web/assets/{project-search-dialog-BsHc39D0.js → project-search-dialog-BSKA4peX.js} +1 -1
- package/web/assets/{quadrantDiagram-ABIIQ3AL-D6adg-7z.js → quadrantDiagram-ABIIQ3AL-jxHw_egj.js} +1 -1
- package/web/assets/{railroadDiagram-RFXS5EU6-CyPAHeJ-.js → railroadDiagram-RFXS5EU6-lIjDXPZt.js} +1 -1
- package/web/assets/{requirementDiagram-TGXJPOKE-CgpSiPTv.js → requirementDiagram-TGXJPOKE-C-JiT4bc.js} +1 -1
- package/web/assets/{sankeyDiagram-HTMAVEWB-BxvReW6S.js → sankeyDiagram-HTMAVEWB-SuLPAw9X.js} +1 -1
- package/web/assets/{search-DEgwpq-P.js → search-CKujW14f.js} +1 -1
- package/web/assets/{selection-popup-d94JnDPy.js → selection-popup-CtxT9SWn.js} +3 -3
- package/web/assets/{sequenceDiagram-DBY2YBRQ-uuplzETI.js → sequenceDiagram-DBY2YBRQ-o9UwTkZR.js} +1 -1
- package/web/assets/{sizeCapture-X5ZJPWSS-Bi3F7nOa.js → sizeCapture-X5ZJPWSS-ClbWGybF.js} +1 -1
- package/web/assets/{stateDiagram-2N3HPSRC-DqypF7lE.js → stateDiagram-2N3HPSRC-Ce4avoWx.js} +1 -1
- package/web/assets/stateDiagram-v2-6OUMAXLB-CsrPTZoJ.js +1 -0
- package/web/assets/{swimlanes-5IMT3BWC-CGD9YT1l.js → swimlanes-5IMT3BWC-DMZI4XZT.js} +2 -2
- package/web/assets/swimlanesDiagram-G3AALYLV-pShSVcTd.js +8 -0
- package/web/assets/{timeline-definition-FHXFAJF6-DCjNS9Ol.js → timeline-definition-FHXFAJF6-CPIpIgPN.js} +1 -1
- package/web/assets/{utils-DCaHk0Gm.js → utils-Cg80pk1W.js} +1 -1
- package/web/assets/{vennDiagram-L72KCM5P-BJ58yQgD.js → vennDiagram-L72KCM5P-_rha8uDZ.js} +1 -1
- package/web/assets/view-context-BDtIUHQy.js +229 -0
- package/web/assets/{viewer-capabilities-DCuJdf64.js → viewer-capabilities-YYZqMs56.js} +1 -1
- package/web/assets/{wardleyDiagram-EHGQE667-BiLuq9mr.js → wardleyDiagram-EHGQE667-D4EAOS35.js} +1 -1
- package/web/assets/{xychartDiagram-FW5EYKEG-DzAZpIRG.js → xychartDiagram-FW5EYKEG-DR8PwXpe.js} +1 -1
- package/web/index.html +2 -2
- package/kernel/packages/agents/eslint.config.js +0 -10
- package/kernel/packages/agents/package.json +0 -75
- package/kernel/packages/agents/src/agent-card.tsx +0 -334
- package/kernel/packages/agents/src/client.tsx +0 -13
- package/kernel/packages/agents/src/index.ts +0 -18
- package/kernel/packages/agents/src/manifest.ts +0 -7
- package/kernel/packages/agents/src/node.ts +0 -447
- package/kernel/packages/agents/src/profiles.ts +0 -137
- package/kernel/packages/agents/src/resolve.ts +0 -69
- package/kernel/packages/agents/src/server.ts +0 -60
- package/kernel/packages/agents/src/types.ts +0 -82
- package/kernel/packages/agents/src/viewer.tsx +0 -370
- package/kernel/packages/agents/test/profiles.test.mjs +0 -88
- package/kernel/packages/agents/test/resolve.test.mjs +0 -729
- package/kernel/packages/agents/tsconfig.json +0 -17
- package/kernel/packages/api/test/agents-loading.test.ts +0 -94
- package/kernel/packages/ui/src/components/folder-skill-list.tsx +0 -62
- package/web/assets/app-DoXXGPMx.js +0 -2
- package/web/assets/app-options-jTBHy0A7.js +0 -25
- package/web/assets/channel-54w4vQjC.js +0 -1
- package/web/assets/classDiagram-OUVF2IWQ-Bh9Ib2pw.js +0 -1
- package/web/assets/classDiagram-v2-EOCWNBFH-Bh9Ib2pw.js +0 -1
- package/web/assets/client-BgUDusrU.js +0 -5
- package/web/assets/client-COaHUqSC.js +0 -17
- package/web/assets/client-UC06V2VL.js +0 -22
- package/web/assets/document-BDtU3CbX.js +0 -19
- package/web/assets/folder-filter-bar-C_2Mobfq.js +0 -4
- package/web/assets/folder-landing-3gqbGaYS.js +0 -54
- package/web/assets/folder-list-DDI0TF2e.js +0 -1
- package/web/assets/folder-metadata-DjV3ZUra.js +0 -2
- package/web/assets/folder-mobile-bar-CF4CpJXL.js +0 -1
- package/web/assets/folder-plugin-view-C48J0HKe.js +0 -3
- package/web/assets/index-Bp9DidgD.js +0 -1
- package/web/assets/index-CXhBn-ar.js +0 -1
- package/web/assets/index-CtuOSBHa.js +0 -2
- package/web/assets/index-Dwhf8F_U.css +0 -1
- package/web/assets/select-DGaccqVB.js +0 -30
- package/web/assets/stateDiagram-v2-6OUMAXLB-EsEb0a5Q.js +0 -1
- package/web/assets/swimlanesDiagram-G3AALYLV-DKIYuN5l.js +0 -8
- package/web/assets/use-folder-filter-hA6fa7nm.js +0 -1
- package/web/assets/view-context-BrzQ7WBV.js +0 -229
|
@@ -1,519 +1,8 @@
|
|
|
1
1
|
// packages/api/src/server/plugins.ts
|
|
2
2
|
import { pathToFileURL } from "node:url";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
|
-
import { mkdir, stat as
|
|
5
|
-
import { dirname
|
|
6
|
-
|
|
7
|
-
// packages/agents/src/manifest.ts
|
|
8
|
-
var agentsManifest = {
|
|
9
|
-
id: "agents",
|
|
10
|
-
label: "Agents"
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// packages/agents/src/node.ts
|
|
14
|
-
import { lstat, readFile, realpath, stat } from "node:fs/promises";
|
|
15
|
-
import { homedir } from "node:os";
|
|
16
|
-
import { basename, dirname, resolve } from "node:path";
|
|
17
|
-
|
|
18
|
-
// packages/agents/src/profiles.ts
|
|
19
|
-
var CLIENT_ORDER = [
|
|
20
|
-
"generic",
|
|
21
|
-
"codex",
|
|
22
|
-
"claude",
|
|
23
|
-
"pi"
|
|
24
|
-
];
|
|
25
|
-
var PROFILES = {
|
|
26
|
-
generic: {
|
|
27
|
-
id: "generic",
|
|
28
|
-
label: "Generic",
|
|
29
|
-
scope: "root",
|
|
30
|
-
files: ["AGENTS.md"],
|
|
31
|
-
filesMode: "first",
|
|
32
|
-
globalDir: ".agents",
|
|
33
|
-
globalFiles: ["AGENTS.md"],
|
|
34
|
-
globalMode: "first",
|
|
35
|
-
verified: false,
|
|
36
|
-
note: "Reference view of the ancestor AGENTS.md chain. No client execution behavior is claimed.",
|
|
37
|
-
limits: "Walks to the filesystem root like Stepladder; only AGENTS.md files are read."
|
|
38
|
-
},
|
|
39
|
-
codex: {
|
|
40
|
-
id: "codex",
|
|
41
|
-
label: "Codex",
|
|
42
|
-
scope: "git",
|
|
43
|
-
files: ["AGENTS.override.md", "AGENTS.md"],
|
|
44
|
-
filesMode: "first",
|
|
45
|
-
globalDir: ".codex",
|
|
46
|
-
globalEnv: "CODEX_HOME",
|
|
47
|
-
globalFiles: ["AGENTS.override.md", "AGENTS.md"],
|
|
48
|
-
globalMode: "first",
|
|
49
|
-
verified: true,
|
|
50
|
-
note: "Verified from the Codex 0.154.0 binary: reads the repository root plus every directory from the CWD up to the root, and prefers AGENTS.override.md over AGENTS.md per directory.",
|
|
51
|
-
limits: "A configured model_instructions_file fallback is not applied here; a warning appears when it is configured."
|
|
52
|
-
},
|
|
53
|
-
claude: {
|
|
54
|
-
id: "claude",
|
|
55
|
-
label: "Claude Code",
|
|
56
|
-
scope: "root",
|
|
57
|
-
files: ["CLAUDE.md", ".claude/CLAUDE.md", "CLAUDE.local.md"],
|
|
58
|
-
filesMode: "all",
|
|
59
|
-
globalDir: ".claude",
|
|
60
|
-
globalFiles: ["CLAUDE.md"],
|
|
61
|
-
globalMode: "first",
|
|
62
|
-
verified: true,
|
|
63
|
-
note: "Verified from the Claude Code 2.1.274 binary: loads ~/.claude/CLAUDE.md and, walking to the filesystem root, each ancestor's CLAUDE.md, .claude/CLAUDE.md, and CLAUDE.local.md.",
|
|
64
|
-
limits: "Conditional .claude/rules/*.md files and @path imports are not expanded here."
|
|
65
|
-
},
|
|
66
|
-
pi: {
|
|
67
|
-
id: "pi",
|
|
68
|
-
label: "Pi",
|
|
69
|
-
scope: "root",
|
|
70
|
-
files: [
|
|
71
|
-
"AGENTS.override.md",
|
|
72
|
-
"AGENTS.md",
|
|
73
|
-
"AGENTS.MD",
|
|
74
|
-
"CLAUDE.md",
|
|
75
|
-
"CLAUDE.MD"
|
|
76
|
-
],
|
|
77
|
-
filesMode: "first",
|
|
78
|
-
globalDir: ".pi/agent",
|
|
79
|
-
globalEnv: "PI_CODING_AGENT_DIR",
|
|
80
|
-
globalFiles: [
|
|
81
|
-
"AGENTS.override.md",
|
|
82
|
-
"AGENTS.md",
|
|
83
|
-
"AGENTS.MD",
|
|
84
|
-
"CLAUDE.md",
|
|
85
|
-
"CLAUDE.MD"
|
|
86
|
-
],
|
|
87
|
-
globalMode: "first",
|
|
88
|
-
verified: true,
|
|
89
|
-
note: "Verified from the Pi 0.85.1 source (resource-loader.js): first match wins from AGENTS.override.md, AGENTS.md, AGENTS.MD, CLAUDE.md, CLAUDE.MD, in each ancestor directory and in the global directory.",
|
|
90
|
-
limits: "Uses the same candidate list for the global directory."
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
function parseClientFilter(value) {
|
|
94
|
-
if (value === "generic" || value === "codex" || value === "claude" || value === "pi") {
|
|
95
|
-
return value;
|
|
96
|
-
}
|
|
97
|
-
return "pi";
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// packages/agents/src/resolve.ts
|
|
101
|
-
var LEVEL_ORDER = {
|
|
102
|
-
project: 0,
|
|
103
|
-
parent: 1,
|
|
104
|
-
repository: 2,
|
|
105
|
-
linked: 3,
|
|
106
|
-
global: 4
|
|
107
|
-
};
|
|
108
|
-
function unique(values) {
|
|
109
|
-
return [...new Set(values)];
|
|
110
|
-
}
|
|
111
|
-
function pathSegments(path) {
|
|
112
|
-
const normalized = path.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
113
|
-
if (!normalized)
|
|
114
|
-
return 0;
|
|
115
|
-
return normalized.split("/").length;
|
|
116
|
-
}
|
|
117
|
-
function dedupeSources(sources) {
|
|
118
|
-
const merged = new Map;
|
|
119
|
-
for (const source of sources) {
|
|
120
|
-
const existing = merged.get(source.id);
|
|
121
|
-
if (!existing) {
|
|
122
|
-
merged.set(source.id, {
|
|
123
|
-
...source,
|
|
124
|
-
clientIds: [...source.clientIds],
|
|
125
|
-
sourcePaths: unique([...source.sourcePaths])
|
|
126
|
-
});
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
existing.clientIds = unique([...existing.clientIds, ...source.clientIds]);
|
|
130
|
-
existing.sourcePaths = unique([
|
|
131
|
-
...existing.sourcePaths,
|
|
132
|
-
...source.sourcePaths
|
|
133
|
-
]);
|
|
134
|
-
if (existing.status !== "loaded" && source.status === "loaded") {
|
|
135
|
-
existing.status = source.status;
|
|
136
|
-
existing.text = source.text;
|
|
137
|
-
existing.size = source.size;
|
|
138
|
-
existing.reason = source.reason;
|
|
139
|
-
}
|
|
140
|
-
if (source.override)
|
|
141
|
-
existing.override = true;
|
|
142
|
-
}
|
|
143
|
-
return [...merged.values()];
|
|
144
|
-
}
|
|
145
|
-
function sortSources(sources) {
|
|
146
|
-
return [...sources].sort((left, right) => {
|
|
147
|
-
const level = LEVEL_ORDER[left.level] - LEVEL_ORDER[right.level];
|
|
148
|
-
if (level !== 0)
|
|
149
|
-
return level;
|
|
150
|
-
const depth = pathSegments(right.directory) - pathSegments(left.directory);
|
|
151
|
-
if (depth !== 0)
|
|
152
|
-
return depth;
|
|
153
|
-
return left.filename.localeCompare(right.filename);
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// packages/agents/src/node.ts
|
|
158
|
-
async function canonicalize(path) {
|
|
159
|
-
try {
|
|
160
|
-
return await realpath(path);
|
|
161
|
-
} catch {
|
|
162
|
-
return null;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
async function hasGit(folder) {
|
|
166
|
-
const entry = await lstat(resolve(folder, ".git")).catch(() => {
|
|
167
|
-
return;
|
|
168
|
-
});
|
|
169
|
-
return Boolean(entry);
|
|
170
|
-
}
|
|
171
|
-
async function nearestGitRoot(folder) {
|
|
172
|
-
let current = folder;
|
|
173
|
-
while (true) {
|
|
174
|
-
if (await hasGit(current))
|
|
175
|
-
return current;
|
|
176
|
-
const parent = dirname(current);
|
|
177
|
-
if (parent === current)
|
|
178
|
-
return null;
|
|
179
|
-
current = parent;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
async function nearestRaggleRoot(folder) {
|
|
183
|
-
let current = folder;
|
|
184
|
-
while (true) {
|
|
185
|
-
const entry = await lstat(resolve(current, "raggle.json")).catch(() => {
|
|
186
|
-
return;
|
|
187
|
-
});
|
|
188
|
-
if (entry)
|
|
189
|
-
return current;
|
|
190
|
-
const parent = dirname(current);
|
|
191
|
-
if (parent === current)
|
|
192
|
-
return null;
|
|
193
|
-
current = parent;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
async function ancestorBoundary(folder, scope) {
|
|
197
|
-
let current = folder;
|
|
198
|
-
while (true) {
|
|
199
|
-
if (scope === "git" && await hasGit(current))
|
|
200
|
-
return current;
|
|
201
|
-
const parent = dirname(current);
|
|
202
|
-
if (parent === current)
|
|
203
|
-
return current;
|
|
204
|
-
current = parent;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
function ancestorChain(folder, boundary) {
|
|
208
|
-
const chain = [];
|
|
209
|
-
let current = folder;
|
|
210
|
-
while (true) {
|
|
211
|
-
chain.push(current);
|
|
212
|
-
if (current === boundary)
|
|
213
|
-
break;
|
|
214
|
-
const parent = dirname(current);
|
|
215
|
-
if (parent === current)
|
|
216
|
-
break;
|
|
217
|
-
current = parent;
|
|
218
|
-
}
|
|
219
|
-
return chain;
|
|
220
|
-
}
|
|
221
|
-
function sourceLevel(index, total, scope) {
|
|
222
|
-
if (total === 1)
|
|
223
|
-
return "project";
|
|
224
|
-
if (index === 0)
|
|
225
|
-
return "project";
|
|
226
|
-
if (scope === "git" && index === total - 1)
|
|
227
|
-
return "repository";
|
|
228
|
-
return "parent";
|
|
229
|
-
}
|
|
230
|
-
async function isRegularFile(path) {
|
|
231
|
-
const details = await stat(path).catch(() => {
|
|
232
|
-
return;
|
|
233
|
-
});
|
|
234
|
-
return details?.isFile() === true;
|
|
235
|
-
}
|
|
236
|
-
function mergeChains(chains) {
|
|
237
|
-
const byDirectory = new Map;
|
|
238
|
-
const order = [];
|
|
239
|
-
for (const chain of chains) {
|
|
240
|
-
for (const entry of chain) {
|
|
241
|
-
const existing = byDirectory.get(entry.directory);
|
|
242
|
-
if (!existing) {
|
|
243
|
-
byDirectory.set(entry.directory, {
|
|
244
|
-
...entry,
|
|
245
|
-
filenames: [...entry.filenames]
|
|
246
|
-
});
|
|
247
|
-
order.push(entry.directory);
|
|
248
|
-
} else {
|
|
249
|
-
for (const filename of entry.filenames) {
|
|
250
|
-
if (!existing.filenames.includes(filename)) {
|
|
251
|
-
existing.filenames.push(filename);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return order.map((directory) => byDirectory.get(directory));
|
|
258
|
-
}
|
|
259
|
-
async function selectFiles(directory, candidates, mode) {
|
|
260
|
-
if (mode === "all") {
|
|
261
|
-
const found = [];
|
|
262
|
-
for (const relative of candidates) {
|
|
263
|
-
if (await isRegularFile(resolve(directory, relative))) {
|
|
264
|
-
found.push({ filename: basename(relative), relative });
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return found;
|
|
268
|
-
}
|
|
269
|
-
for (const relative of candidates) {
|
|
270
|
-
if (await isRegularFile(resolve(directory, relative))) {
|
|
271
|
-
return [{ filename: basename(relative), relative }];
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
return [];
|
|
275
|
-
}
|
|
276
|
-
function expandHome(path, homeDir) {
|
|
277
|
-
if (path === "~")
|
|
278
|
-
return homeDir;
|
|
279
|
-
if (path.startsWith("~/"))
|
|
280
|
-
return resolve(homeDir, path.slice(2));
|
|
281
|
-
return path;
|
|
282
|
-
}
|
|
283
|
-
function globalDirectory(profile, homeDir) {
|
|
284
|
-
if (profile.globalDir === null)
|
|
285
|
-
return null;
|
|
286
|
-
const envValue = profile.globalEnv ? process.env[profile.globalEnv]?.trim() : undefined;
|
|
287
|
-
if (envValue)
|
|
288
|
-
return expandHome(envValue, homeDir);
|
|
289
|
-
if (profile.globalDir === "")
|
|
290
|
-
return homeDir;
|
|
291
|
-
return resolve(homeDir, profile.globalDir);
|
|
292
|
-
}
|
|
293
|
-
function readError(error) {
|
|
294
|
-
return error instanceof Error ? error.message : "Could not read file";
|
|
295
|
-
}
|
|
296
|
-
var INSTRUCTION_NAMES = new Set(Object.values(PROFILES).flatMap((profile) => [...profile.files, ...profile.globalFiles]).map((path) => basename(path).toLowerCase()));
|
|
297
|
-
async function codexModelInstructionsFile(codexHome) {
|
|
298
|
-
try {
|
|
299
|
-
const content = await readFile(resolve(codexHome, "config.toml"), "utf8");
|
|
300
|
-
const match = /^\s*model_instructions_file\s*=\s*["']?([^"'\n]+)["']?\s*$/m.exec(content);
|
|
301
|
-
return match?.[1]?.trim() ?? null;
|
|
302
|
-
} catch {
|
|
303
|
-
return null;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
async function loadSource(input) {
|
|
307
|
-
const real = await canonicalize(input.literalPath);
|
|
308
|
-
if (!real) {
|
|
309
|
-
return {
|
|
310
|
-
id: input.literalPath,
|
|
311
|
-
path: input.literalPath,
|
|
312
|
-
sourcePaths: [input.literalPath],
|
|
313
|
-
filename: input.filename,
|
|
314
|
-
directory: dirname(input.literalPath),
|
|
315
|
-
level: input.level,
|
|
316
|
-
status: "unreadable",
|
|
317
|
-
text: "",
|
|
318
|
-
size: 0,
|
|
319
|
-
clientIds: [input.clientId],
|
|
320
|
-
override: input.override,
|
|
321
|
-
applies: true,
|
|
322
|
-
reason: "Path cannot be resolved"
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
const record = {
|
|
326
|
-
id: real,
|
|
327
|
-
path: real,
|
|
328
|
-
sourcePaths: [input.literalPath],
|
|
329
|
-
filename: input.filename,
|
|
330
|
-
directory: dirname(real),
|
|
331
|
-
level: input.level,
|
|
332
|
-
status: "loaded",
|
|
333
|
-
text: "",
|
|
334
|
-
size: 0,
|
|
335
|
-
clientIds: [input.clientId],
|
|
336
|
-
override: input.override,
|
|
337
|
-
applies: true
|
|
338
|
-
};
|
|
339
|
-
if (!INSTRUCTION_NAMES.has(basename(real).toLowerCase())) {
|
|
340
|
-
record.status = "unsafe";
|
|
341
|
-
record.reason = "Symlink resolves to a non-instruction file";
|
|
342
|
-
return record;
|
|
343
|
-
}
|
|
344
|
-
const details = await stat(real).catch(() => {
|
|
345
|
-
return;
|
|
346
|
-
});
|
|
347
|
-
if (!details?.isFile()) {
|
|
348
|
-
record.status = "unreadable";
|
|
349
|
-
record.reason = "Not a regular file";
|
|
350
|
-
return record;
|
|
351
|
-
}
|
|
352
|
-
record.size = details.size;
|
|
353
|
-
if (input.readText) {
|
|
354
|
-
try {
|
|
355
|
-
record.text = await readFile(real, "utf8");
|
|
356
|
-
} catch (error) {
|
|
357
|
-
record.status = "unreadable";
|
|
358
|
-
record.reason = readError(error);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
return record;
|
|
362
|
-
}
|
|
363
|
-
async function resolveAgents(options) {
|
|
364
|
-
const homeDir = options.homeDir ?? homedir();
|
|
365
|
-
const client = options.client ?? "all";
|
|
366
|
-
const readText = options.readText ?? true;
|
|
367
|
-
const folder = await canonicalize(options.folder);
|
|
368
|
-
if (!folder)
|
|
369
|
-
throw new Error(`Folder not found: ${options.folder}`);
|
|
370
|
-
const repositoryRoot = await nearestGitRoot(folder);
|
|
371
|
-
const workspaceRoot = await nearestRaggleRoot(folder);
|
|
372
|
-
const profileIds = client === "all" ? CLIENT_ORDER : [client];
|
|
373
|
-
const sources = [];
|
|
374
|
-
const warnings = [];
|
|
375
|
-
const profileChains = [];
|
|
376
|
-
for (const profileId of profileIds) {
|
|
377
|
-
const profile = PROFILES[profileId];
|
|
378
|
-
const boundary = workspaceRoot ?? await ancestorBoundary(folder, profile.scope);
|
|
379
|
-
const ancestors = ancestorChain(folder, boundary);
|
|
380
|
-
const chain = [];
|
|
381
|
-
for (let index = 0;index < ancestors.length; index += 1) {
|
|
382
|
-
const directory = ancestors[index];
|
|
383
|
-
if (!directory)
|
|
384
|
-
continue;
|
|
385
|
-
const level = sourceLevel(index, ancestors.length, profile.scope);
|
|
386
|
-
const files = await selectFiles(directory, profile.files, profile.filesMode);
|
|
387
|
-
chain.push({
|
|
388
|
-
directory,
|
|
389
|
-
level,
|
|
390
|
-
filenames: files.map((file) => file.filename)
|
|
391
|
-
});
|
|
392
|
-
for (const file of files) {
|
|
393
|
-
const source = await loadSource({
|
|
394
|
-
clientId: profileId,
|
|
395
|
-
filename: file.filename,
|
|
396
|
-
level,
|
|
397
|
-
literalPath: resolve(directory, file.relative),
|
|
398
|
-
override: file.filename === "AGENTS.override.md",
|
|
399
|
-
readText
|
|
400
|
-
});
|
|
401
|
-
sources.push(source);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
profileChains.push(chain);
|
|
405
|
-
for (const linkedFolder of options.linkedFolders ?? []) {
|
|
406
|
-
const canonicalLinked = await canonicalize(linkedFolder);
|
|
407
|
-
if (!canonicalLinked || canonicalLinked === folder)
|
|
408
|
-
continue;
|
|
409
|
-
const linkedFiles = await selectFiles(canonicalLinked, profile.files, profile.filesMode);
|
|
410
|
-
chain.push({
|
|
411
|
-
directory: canonicalLinked,
|
|
412
|
-
level: "linked",
|
|
413
|
-
filenames: linkedFiles.map((file) => file.filename)
|
|
414
|
-
});
|
|
415
|
-
for (const file of linkedFiles) {
|
|
416
|
-
const source = await loadSource({
|
|
417
|
-
clientId: profileId,
|
|
418
|
-
filename: file.filename,
|
|
419
|
-
level: "linked",
|
|
420
|
-
literalPath: resolve(canonicalLinked, file.relative),
|
|
421
|
-
override: file.filename === "AGENTS.override.md",
|
|
422
|
-
readText
|
|
423
|
-
});
|
|
424
|
-
sources.push(source);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
const globalDir = globalDirectory(profile, homeDir);
|
|
428
|
-
if (globalDir) {
|
|
429
|
-
const globals = await selectFiles(globalDir, profile.globalFiles, profile.globalMode);
|
|
430
|
-
for (const file of globals) {
|
|
431
|
-
const source = await loadSource({
|
|
432
|
-
clientId: profileId,
|
|
433
|
-
filename: file.filename,
|
|
434
|
-
level: "global",
|
|
435
|
-
literalPath: resolve(globalDir, file.relative),
|
|
436
|
-
override: file.filename === "AGENTS.override.md",
|
|
437
|
-
readText
|
|
438
|
-
});
|
|
439
|
-
sources.push(source);
|
|
440
|
-
}
|
|
441
|
-
if (globals.length === 0 && profile.globalFiles.length > 0) {
|
|
442
|
-
warnings.push({
|
|
443
|
-
kind: "missing",
|
|
444
|
-
path: globalDir,
|
|
445
|
-
clientIds: [profileId],
|
|
446
|
-
reason: "No global instruction file found in this directory"
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
if (profileId === "codex") {
|
|
451
|
-
const codexHome = globalDirectory(profile, homeDir);
|
|
452
|
-
if (codexHome) {
|
|
453
|
-
const fallback = await codexModelInstructionsFile(codexHome);
|
|
454
|
-
if (fallback) {
|
|
455
|
-
warnings.push({
|
|
456
|
-
kind: "unsupported",
|
|
457
|
-
clientIds: [profileId],
|
|
458
|
-
reason: `Codex model_instructions_file (${fallback}) is configured but not applied here`
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
const deduped = dedupeSources(sources);
|
|
465
|
-
const ordered = sortSources(deduped);
|
|
466
|
-
return {
|
|
467
|
-
folder,
|
|
468
|
-
repositoryRoot,
|
|
469
|
-
client,
|
|
470
|
-
sources: ordered,
|
|
471
|
-
warnings,
|
|
472
|
-
chain: mergeChains(profileChains)
|
|
473
|
-
};
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// packages/agents/src/server.ts
|
|
477
|
-
function createAgentsPlugin(options = {}) {
|
|
478
|
-
return {
|
|
479
|
-
...agentsManifest,
|
|
480
|
-
async detect(context) {
|
|
481
|
-
try {
|
|
482
|
-
const result = await resolveAgents({
|
|
483
|
-
folder: context.folder,
|
|
484
|
-
client: "all",
|
|
485
|
-
homeDir: options.homeDir,
|
|
486
|
-
linkedFolders: context.linkedFolders,
|
|
487
|
-
readText: false
|
|
488
|
-
});
|
|
489
|
-
return { count: result.sources.length, status: "available" };
|
|
490
|
-
} catch {
|
|
491
|
-
return { status: "available" };
|
|
492
|
-
}
|
|
493
|
-
},
|
|
494
|
-
async handle(context, subpath) {
|
|
495
|
-
const client = parseClientFilter(subpath.trim() || null);
|
|
496
|
-
const result = await resolveAgents({
|
|
497
|
-
folder: context.folder,
|
|
498
|
-
client,
|
|
499
|
-
homeDir: options.homeDir,
|
|
500
|
-
linkedFolders: context.linkedFolders
|
|
501
|
-
});
|
|
502
|
-
return {
|
|
503
|
-
kind: "available",
|
|
504
|
-
data: {
|
|
505
|
-
client,
|
|
506
|
-
folder: result.folder,
|
|
507
|
-
repositoryRoot: result.repositoryRoot,
|
|
508
|
-
sources: result.sources,
|
|
509
|
-
status: "available",
|
|
510
|
-
warnings: result.warnings,
|
|
511
|
-
chain: result.chain
|
|
512
|
-
}
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
|
-
}
|
|
4
|
+
import { mkdir, stat as stat2, writeFile } from "node:fs/promises";
|
|
5
|
+
import { dirname, resolve as resolve2, sep as sep2 } from "node:path";
|
|
517
6
|
|
|
518
7
|
// packages/plugins/dist/chunk-AX4A4GYF.js
|
|
519
8
|
var FolderPluginFailure = class extends Error {
|
|
@@ -524,12 +13,19 @@ var FolderPluginFailure = class extends Error {
|
|
|
524
13
|
};
|
|
525
14
|
|
|
526
15
|
// packages/notes/src/server.ts
|
|
527
|
-
import { readdir, stat
|
|
528
|
-
import { basename
|
|
16
|
+
import { readdir, stat } from "node:fs/promises";
|
|
17
|
+
import { basename, extname, relative, resolve, sep } from "node:path";
|
|
529
18
|
|
|
530
19
|
// packages/notes/src/manifest.ts
|
|
531
20
|
var notesManifest = {
|
|
532
21
|
id: "notes",
|
|
22
|
+
icon: {
|
|
23
|
+
paths: [
|
|
24
|
+
"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z",
|
|
25
|
+
"M14 2v6h6",
|
|
26
|
+
"M8 13h8M8 17h6"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
533
29
|
label: "Notes"
|
|
534
30
|
};
|
|
535
31
|
|
|
@@ -542,7 +38,7 @@ async function listMarkdownFiles(folder) {
|
|
|
542
38
|
for (const entry of entries) {
|
|
543
39
|
if (entry.name === "node_modules" || entry.name.startsWith("."))
|
|
544
40
|
continue;
|
|
545
|
-
const path =
|
|
41
|
+
const path = resolve(current, entry.name);
|
|
546
42
|
if (entry.isDirectory()) {
|
|
547
43
|
await visit(path);
|
|
548
44
|
continue;
|
|
@@ -550,12 +46,12 @@ async function listMarkdownFiles(folder) {
|
|
|
550
46
|
if (!entry.isFile() || !markdownExtensions.has(extname(entry.name))) {
|
|
551
47
|
continue;
|
|
552
48
|
}
|
|
553
|
-
const details = await
|
|
49
|
+
const details = await stat(path).catch(() => {
|
|
554
50
|
return;
|
|
555
51
|
});
|
|
556
52
|
files.push({
|
|
557
53
|
activityAt: details?.mtimeMs ?? 0,
|
|
558
|
-
name:
|
|
54
|
+
name: basename(entry.name, extname(entry.name)),
|
|
559
55
|
relativePath: relative(folder, path).split(sep).join("/")
|
|
560
56
|
});
|
|
561
57
|
}
|
|
@@ -608,16 +104,11 @@ function configuredFolderServerRegistry(registry, resolvedConfig) {
|
|
|
608
104
|
];
|
|
609
105
|
return new Map(ids.map((id) => [id, registry.get(id)]));
|
|
610
106
|
}
|
|
611
|
-
function createFolderServerPlugins(
|
|
612
|
-
return [
|
|
613
|
-
createAgentsPlugin({
|
|
614
|
-
homeDir: options.agentsHomeDir
|
|
615
|
-
}),
|
|
616
|
-
createNotesPlugin()
|
|
617
|
-
];
|
|
107
|
+
function createFolderServerPlugins() {
|
|
108
|
+
return [createNotesPlugin()];
|
|
618
109
|
}
|
|
619
|
-
function folderServerRegistry(
|
|
620
|
-
return new Map(createFolderServerPlugins(
|
|
110
|
+
function folderServerRegistry() {
|
|
111
|
+
return new Map(createFolderServerPlugins().map((plugin) => [plugin.id, plugin]));
|
|
621
112
|
}
|
|
622
113
|
function externalServerEntries() {
|
|
623
114
|
const source = process.env.KENNEL_EXTERNAL_SERVER_ENTRIES;
|
|
@@ -637,14 +128,14 @@ function externalServerEntries() {
|
|
|
637
128
|
return { id: item.id, module: item.module, symbol: item.symbol, trigger: item.trigger };
|
|
638
129
|
});
|
|
639
130
|
}
|
|
640
|
-
async function folderServerRegistryAsync(
|
|
641
|
-
const registry = folderServerRegistry(
|
|
131
|
+
async function folderServerRegistryAsync() {
|
|
132
|
+
const registry = folderServerRegistry();
|
|
642
133
|
for (const entry of externalServerEntries()) {
|
|
643
134
|
if (registry.has(entry.id))
|
|
644
135
|
throw new Error(`External plugin id collides with core plugin: ${entry.id}`);
|
|
645
136
|
const imported = await import(pathToFileURL(entry.module).href);
|
|
646
137
|
const value = imported[entry.symbol];
|
|
647
|
-
const plugin = typeof value === "function" ? value(
|
|
138
|
+
const plugin = typeof value === "function" ? value() : value;
|
|
648
139
|
if (!plugin || typeof plugin !== "object")
|
|
649
140
|
throw new Error(`External plugin ${entry.id} did not export ${entry.symbol}`);
|
|
650
141
|
const server = plugin;
|
|
@@ -656,7 +147,7 @@ async function folderServerRegistryAsync(options = {}) {
|
|
|
656
147
|
...server,
|
|
657
148
|
async detect(context) {
|
|
658
149
|
const detection = await server.detect(context);
|
|
659
|
-
if (detection.status === "unavailable" && existsSync(
|
|
150
|
+
if (detection.status === "unavailable" && existsSync(resolve2(context.folder, entry.trigger))) {
|
|
660
151
|
return { status: "available" };
|
|
661
152
|
}
|
|
662
153
|
return detection;
|
|
@@ -694,8 +185,8 @@ async function externalApiHandlers() {
|
|
|
694
185
|
return handlers;
|
|
695
186
|
}
|
|
696
187
|
async function scaffoldFolderPlugins(folder, options = {}) {
|
|
697
|
-
const root =
|
|
698
|
-
const registry = folderServerRegistry(
|
|
188
|
+
const root = resolve2(folder);
|
|
189
|
+
const registry = folderServerRegistry();
|
|
699
190
|
const created = [];
|
|
700
191
|
const skipped = [];
|
|
701
192
|
const supported = [];
|
|
@@ -705,7 +196,7 @@ async function scaffoldFolderPlugins(folder, options = {}) {
|
|
|
705
196
|
const context = { folder: root };
|
|
706
197
|
const result = await plugin.init(context);
|
|
707
198
|
const files = result.files.filter((file) => {
|
|
708
|
-
const target =
|
|
199
|
+
const target = resolve2(root, file.path);
|
|
709
200
|
const contained = target === root || target.startsWith(root + sep2);
|
|
710
201
|
return contained && file.path !== ".";
|
|
711
202
|
});
|
|
@@ -714,15 +205,15 @@ async function scaffoldFolderPlugins(folder, options = {}) {
|
|
|
714
205
|
files: files.map((file) => file.path)
|
|
715
206
|
});
|
|
716
207
|
for (const file of files) {
|
|
717
|
-
const target =
|
|
718
|
-
const exists = await
|
|
208
|
+
const target = resolve2(root, file.path);
|
|
209
|
+
const exists = await stat2(target).then(() => true).catch(() => false);
|
|
719
210
|
if (exists && !options.force) {
|
|
720
211
|
skipped.push({ path: file.path, plugin: plugin.id });
|
|
721
212
|
continue;
|
|
722
213
|
}
|
|
723
214
|
if (options.write === false)
|
|
724
215
|
continue;
|
|
725
|
-
await mkdir(
|
|
216
|
+
await mkdir(dirname(target), { recursive: true });
|
|
726
217
|
await writeFile(target, file.content);
|
|
727
218
|
created.push({ path: file.path, plugin: plugin.id });
|
|
728
219
|
}
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
"@lexical/markdown": "0.49.0",
|
|
23
23
|
"@lexical/react": "0.49.0",
|
|
24
24
|
"@lexical/rich-text": "0.49.0",
|
|
25
|
-
"@raggle-ai/agents": "workspace:*",
|
|
26
25
|
"kennel-plugins": "workspace:*",
|
|
27
26
|
"@raggle-ai/kennel-api": "workspace:*",
|
|
28
27
|
"@raggle-ai/kennel-preview": "workspace:*",
|