domain-knowledge-kit 0.2.16 → 0.2.19
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.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/features/agent/commands/init.d.ts +90 -1
- package/dist/features/agent/commands/init.d.ts.map +1 -1
- package/dist/features/agent/commands/init.js +206 -48
- package/dist/features/agent/commands/init.js.map +1 -1
- package/dist/features/agent/commands/prime.d.ts.map +1 -1
- package/dist/features/agent/commands/prime.js +2 -1
- package/dist/features/agent/commands/prime.js.map +1 -1
- package/dist/features/agent/commands/update.d.ts +27 -0
- package/dist/features/agent/commands/update.d.ts.map +1 -0
- package/dist/features/agent/commands/update.js +316 -0
- package/dist/features/agent/commands/update.js.map +1 -0
- package/dist/features/agent/dkk-artifacts.d.ts +76 -0
- package/dist/features/agent/dkk-artifacts.d.ts.map +1 -0
- package/dist/features/agent/dkk-artifacts.js +328 -0
- package/dist/features/agent/dkk-artifacts.js.map +1 -0
- package/dist/features/agent/install-mode.d.ts +34 -0
- package/dist/features/agent/install-mode.d.ts.map +1 -0
- package/dist/features/agent/install-mode.js +78 -0
- package/dist/features/agent/install-mode.js.map +1 -0
- package/dist/features/agent/mcp-register.d.ts +20 -0
- package/dist/features/agent/mcp-register.d.ts.map +1 -0
- package/dist/features/agent/mcp-register.js +116 -0
- package/dist/features/agent/mcp-register.js.map +1 -0
- package/dist/features/agent/settings-prune.d.ts +29 -0
- package/dist/features/agent/settings-prune.d.ts.map +1 -0
- package/dist/features/agent/settings-prune.js +70 -0
- package/dist/features/agent/settings-prune.js.map +1 -0
- package/dist/features/agent/tests/settings-prune.test.d.ts +2 -0
- package/dist/features/agent/tests/settings-prune.test.d.ts.map +1 -0
- package/dist/features/agent/tests/settings-prune.test.js +118 -0
- package/dist/features/agent/tests/settings-prune.test.js.map +1 -0
- package/dist/features/scaffold/commands/new-domain.d.ts +22 -0
- package/dist/features/scaffold/commands/new-domain.d.ts.map +1 -1
- package/dist/features/scaffold/commands/new-domain.js +44 -28
- package/dist/features/scaffold/commands/new-domain.js.map +1 -1
- package/dist/version.d.ts +4 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +15 -0
- package/dist/version.js.map +1 -0
- package/package.json +3 -3
- package/tools/dkk/claude/hooks/post-edit-validate.mjs +25 -8
- package/tools/dkk/claude/hooks/session-start-prime.mjs +3 -16
- package/tools/dkk/claude/hooks/stop-validate.mjs +25 -6
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical identification of DKK-managed AI assistant artifacts in a
|
|
3
|
+
* consumer's repo. Used by `dkk update` to safely sweep stale files and
|
|
4
|
+
* prune stale settings.json entries without touching user-authored content.
|
|
5
|
+
*
|
|
6
|
+
* Naming convention (single source of truth — keep changes here):
|
|
7
|
+
*
|
|
8
|
+
* - **Files** in `.claude/skills/`, `.claude/agents/`, `.claude/commands/`
|
|
9
|
+
* are DKK-managed if their first path segment matches `dkk-*`.
|
|
10
|
+
* - **Hooks** in `.claude/hooks/` are identified by basename — only those
|
|
11
|
+
* whose `.mjs` filename appears in the bundled settings.json template's
|
|
12
|
+
* hook command strings are owned by DKK.
|
|
13
|
+
* - **Skill directories** in `.github/skills/` are DKK-managed if they
|
|
14
|
+
* match `dkk-*`.
|
|
15
|
+
* - **permissions.allow** entries are DKK-managed iff they appear verbatim
|
|
16
|
+
* in the bundled settings.json template's `permissions.allow`.
|
|
17
|
+
* - **LEGACY_DKK_PATHS** captures artifact paths that prior versions of
|
|
18
|
+
* DKK installed and that current versions no longer ship — `update`
|
|
19
|
+
* removes them so users on old releases don't carry stale files forever.
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
22
|
+
import { basename, join, relative } from "node:path";
|
|
23
|
+
import { packageClaudeDir, packageSkillsDir } from "../../shared/paths.js";
|
|
24
|
+
import { extractHookBasename } from "./commands/init.js";
|
|
25
|
+
/**
|
|
26
|
+
* Repo-relative paths that previous DKK versions installed but the current
|
|
27
|
+
* release no longer ships. `dkk update` removes any of these still present
|
|
28
|
+
* in a target repo. Append new entries here when a template file is
|
|
29
|
+
* renamed or retired.
|
|
30
|
+
*/
|
|
31
|
+
export const LEGACY_DKK_PATHS = [
|
|
32
|
+
".github/skills/dkk-domain-knowledge",
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Walk `tools/dkk/claude/` in the running DKK package and return the set of
|
|
36
|
+
* artifact basenames the template currently ships. Derived at runtime so
|
|
37
|
+
* future template additions don't require code changes here.
|
|
38
|
+
*/
|
|
39
|
+
export function dkkClaudeFiles() {
|
|
40
|
+
const inv = { hooks: [], skills: [], agents: [], commands: [] };
|
|
41
|
+
const src = packageClaudeDir();
|
|
42
|
+
if (!existsSync(src))
|
|
43
|
+
return inv;
|
|
44
|
+
inv.hooks = listFilesIfDir(join(src, "hooks"));
|
|
45
|
+
inv.skills = listDirsIfDir(join(src, "skills"));
|
|
46
|
+
inv.agents = listFilesIfDir(join(src, "agents"));
|
|
47
|
+
inv.commands = listFilesIfDir(join(src, "commands"));
|
|
48
|
+
return inv;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Skill directories the bundled `.github/skills/` template installs (e.g.
|
|
52
|
+
* `dkk-flow-implementer`). Returned as bare directory names.
|
|
53
|
+
*/
|
|
54
|
+
export function dkkGithubSkillDirs() {
|
|
55
|
+
const src = packageSkillsDir();
|
|
56
|
+
if (!existsSync(src))
|
|
57
|
+
return [];
|
|
58
|
+
return listDirsIfDir(src);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* `permissions.allow` entries the bundled `settings.json` template ships.
|
|
62
|
+
* Empty array if the template is missing or unparseable — callers should
|
|
63
|
+
* treat that as "DKK doesn't own any permissions" rather than erroring.
|
|
64
|
+
*/
|
|
65
|
+
export function dkkPermissionAllowEntries() {
|
|
66
|
+
const settings = readBundledSettings();
|
|
67
|
+
if (!settings)
|
|
68
|
+
return [];
|
|
69
|
+
return settings.permissions?.allow ?? [];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Hook script basenames referenced by the bundled `settings.json` template
|
|
73
|
+
* (e.g. `session-start-prime.mjs`). Used to identify DKK-owned hook entries
|
|
74
|
+
* in a consumer's settings.json so they can be pruned cleanly.
|
|
75
|
+
*/
|
|
76
|
+
export function dkkHookBasenames() {
|
|
77
|
+
const settings = readBundledSettings();
|
|
78
|
+
if (!settings?.hooks)
|
|
79
|
+
return [];
|
|
80
|
+
const out = new Set();
|
|
81
|
+
for (const entries of Object.values(settings.hooks)) {
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
for (const hook of entry.hooks ?? []) {
|
|
84
|
+
const b = extractHookBasename(hook.command);
|
|
85
|
+
if (b)
|
|
86
|
+
out.add(b);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return [...out];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Read and parse the bundled `settings.json` template. Returns `null` if
|
|
94
|
+
* the file is missing or unparseable (failures are silent — see callers).
|
|
95
|
+
*/
|
|
96
|
+
function readBundledSettings() {
|
|
97
|
+
const path = join(packageClaudeDir(), "settings.json");
|
|
98
|
+
if (!existsSync(path))
|
|
99
|
+
return null;
|
|
100
|
+
try {
|
|
101
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function listFilesIfDir(dir) {
|
|
108
|
+
if (!existsSync(dir))
|
|
109
|
+
return [];
|
|
110
|
+
return readdirSync(dir).filter((n) => {
|
|
111
|
+
try {
|
|
112
|
+
return statSync(join(dir, n)).isFile();
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function listDirsIfDir(dir) {
|
|
120
|
+
if (!existsSync(dir))
|
|
121
|
+
return [];
|
|
122
|
+
return readdirSync(dir).filter((n) => {
|
|
123
|
+
try {
|
|
124
|
+
return statSync(join(dir, n)).isDirectory();
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Walk a target repo's `.claude/` and `.github/skills/` trees and return
|
|
133
|
+
* the set of paths the predicates flag as DKK-managed.
|
|
134
|
+
*/
|
|
135
|
+
export function scanInstalledArtifacts(root) {
|
|
136
|
+
const hookBasenames = new Set(dkkHookBasenames());
|
|
137
|
+
const scan = {
|
|
138
|
+
dkkPrefixedClaude: [],
|
|
139
|
+
dkkHooks: [],
|
|
140
|
+
githubSkillDirs: [],
|
|
141
|
+
legacy: [],
|
|
142
|
+
};
|
|
143
|
+
// .claude/skills, .claude/agents, .claude/commands — match dkk-* prefix.
|
|
144
|
+
for (const sub of ["skills", "agents", "commands"]) {
|
|
145
|
+
const dir = join(root, ".claude", sub);
|
|
146
|
+
if (!existsSync(dir))
|
|
147
|
+
continue;
|
|
148
|
+
for (const name of readdirSync(dir)) {
|
|
149
|
+
if (!name.startsWith("dkk-"))
|
|
150
|
+
continue;
|
|
151
|
+
const path = join(dir, name);
|
|
152
|
+
// skills/ is nested (one dir per skill); agents/ + commands/ are flat files.
|
|
153
|
+
if (sub === "skills") {
|
|
154
|
+
// Push the directory itself; sweep deletes recursively.
|
|
155
|
+
scan.dkkPrefixedClaude.push(path);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
scan.dkkPrefixedClaude.push(path);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// .claude/hooks — match basenames the bundled template defines.
|
|
163
|
+
const hooksDir = join(root, ".claude", "hooks");
|
|
164
|
+
if (existsSync(hooksDir)) {
|
|
165
|
+
for (const name of readdirSync(hooksDir)) {
|
|
166
|
+
if (hookBasenames.has(name))
|
|
167
|
+
scan.dkkHooks.push(join(hooksDir, name));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// .github/skills/dkk-*
|
|
171
|
+
const ghSkills = join(root, ".github", "skills");
|
|
172
|
+
if (existsSync(ghSkills)) {
|
|
173
|
+
for (const name of readdirSync(ghSkills)) {
|
|
174
|
+
if (!name.startsWith("dkk-"))
|
|
175
|
+
continue;
|
|
176
|
+
scan.githubSkillDirs.push(join(ghSkills, name));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Legacy paths.
|
|
180
|
+
for (const legacyRel of LEGACY_DKK_PATHS) {
|
|
181
|
+
const abs = join(root, legacyRel);
|
|
182
|
+
if (existsSync(abs))
|
|
183
|
+
scan.legacy.push(abs);
|
|
184
|
+
}
|
|
185
|
+
return scan;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Compute the add / replace / remove triage between the bundled template
|
|
189
|
+
* and a target repo. Paths are returned as repo-relative POSIX paths.
|
|
190
|
+
*
|
|
191
|
+
* `toAdd` and `toReplace` are derived by enumerating the bundled template's
|
|
192
|
+
* shipped files; `toRemove` is the set of installed DKK-managed paths that
|
|
193
|
+
* have no counterpart in the new template.
|
|
194
|
+
*/
|
|
195
|
+
export function computeArtifactDiff(root) {
|
|
196
|
+
const diff = { toAdd: [], toReplace: [], toRemove: [] };
|
|
197
|
+
const claudeSrc = packageClaudeDir();
|
|
198
|
+
const skillsSrc = packageSkillsDir();
|
|
199
|
+
const inv = dkkClaudeFiles();
|
|
200
|
+
const installed = scanInstalledArtifacts(root);
|
|
201
|
+
const expectedInstalled = new Set();
|
|
202
|
+
// Hooks: flat files.
|
|
203
|
+
for (const name of inv.hooks) {
|
|
204
|
+
const srcPath = join(claudeSrc, "hooks", name);
|
|
205
|
+
const destPath = join(root, ".claude", "hooks", name);
|
|
206
|
+
expectedInstalled.add(destPath);
|
|
207
|
+
if (!existsSync(destPath)) {
|
|
208
|
+
diff.toAdd.push(toRel(root, destPath));
|
|
209
|
+
}
|
|
210
|
+
else if (!filesEqual(srcPath, destPath)) {
|
|
211
|
+
diff.toReplace.push(toRel(root, destPath));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// settings.json is intentionally left out of the diff: the prune+merge
|
|
215
|
+
// phase handles it independently and its content always differs from a
|
|
216
|
+
// fresh template (user customisations + additive merge state). Including
|
|
217
|
+
// it here would either always show "replace" on every run (noisy) or
|
|
218
|
+
// misleadingly suggest the file will be force-overwritten.
|
|
219
|
+
// Skills: nested (skill/<file>).
|
|
220
|
+
for (const skillName of inv.skills) {
|
|
221
|
+
const skillSrc = join(claudeSrc, "skills", skillName);
|
|
222
|
+
const skillDest = join(root, ".claude", "skills", skillName);
|
|
223
|
+
expectedInstalled.add(skillDest);
|
|
224
|
+
if (!existsSync(skillDest)) {
|
|
225
|
+
diff.toAdd.push(toRel(root, skillDest));
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
// Compare each file inside the skill dir.
|
|
229
|
+
let anyDiff = false;
|
|
230
|
+
for (const fileName of readdirSync(skillSrc)) {
|
|
231
|
+
const f = join(skillSrc, fileName);
|
|
232
|
+
try {
|
|
233
|
+
if (!statSync(f).isFile())
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const df = join(skillDest, fileName);
|
|
240
|
+
if (!existsSync(df) || !filesEqual(f, df)) {
|
|
241
|
+
anyDiff = true;
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (anyDiff)
|
|
246
|
+
diff.toReplace.push(toRel(root, skillDest));
|
|
247
|
+
}
|
|
248
|
+
// Agents + commands: flat files.
|
|
249
|
+
for (const [sub, names] of [["agents", inv.agents], ["commands", inv.commands]]) {
|
|
250
|
+
for (const name of names) {
|
|
251
|
+
const srcPath = join(claudeSrc, sub, name);
|
|
252
|
+
const destPath = join(root, ".claude", sub, name);
|
|
253
|
+
expectedInstalled.add(destPath);
|
|
254
|
+
if (!existsSync(destPath)) {
|
|
255
|
+
diff.toAdd.push(toRel(root, destPath));
|
|
256
|
+
}
|
|
257
|
+
else if (!filesEqual(srcPath, destPath)) {
|
|
258
|
+
diff.toReplace.push(toRel(root, destPath));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// .github/skills/<dkk-*>
|
|
263
|
+
if (existsSync(skillsSrc)) {
|
|
264
|
+
for (const skillName of dkkGithubSkillDirs()) {
|
|
265
|
+
const skillSrcDir = join(skillsSrc, skillName);
|
|
266
|
+
const skillDestDir = join(root, ".github", "skills", skillName);
|
|
267
|
+
expectedInstalled.add(skillDestDir);
|
|
268
|
+
if (!existsSync(skillDestDir)) {
|
|
269
|
+
diff.toAdd.push(toRel(root, skillDestDir));
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
let anyDiff = false;
|
|
273
|
+
for (const fileName of readdirSync(skillSrcDir)) {
|
|
274
|
+
const f = join(skillSrcDir, fileName);
|
|
275
|
+
try {
|
|
276
|
+
if (!statSync(f).isFile())
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
const df = join(skillDestDir, fileName);
|
|
283
|
+
if (!existsSync(df) || !filesEqual(f, df)) {
|
|
284
|
+
anyDiff = true;
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (anyDiff)
|
|
289
|
+
diff.toReplace.push(toRel(root, skillDestDir));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// toRemove: any installed dkk-managed path not present in `expectedInstalled`,
|
|
293
|
+
// plus everything in `legacy` (which by definition is no longer shipped).
|
|
294
|
+
// De-duplicate because a legacy path can match both the `dkk-*` prefix
|
|
295
|
+
// predicate AND the LEGACY_DKK_PATHS list.
|
|
296
|
+
const seenRemove = new Set();
|
|
297
|
+
const candidates = [
|
|
298
|
+
...installed.dkkPrefixedClaude,
|
|
299
|
+
...installed.dkkHooks,
|
|
300
|
+
...installed.githubSkillDirs,
|
|
301
|
+
...installed.legacy,
|
|
302
|
+
];
|
|
303
|
+
for (const path of candidates) {
|
|
304
|
+
if (expectedInstalled.has(path))
|
|
305
|
+
continue;
|
|
306
|
+
if (seenRemove.has(path))
|
|
307
|
+
continue;
|
|
308
|
+
seenRemove.add(path);
|
|
309
|
+
diff.toRemove.push(toRel(root, path));
|
|
310
|
+
}
|
|
311
|
+
return diff;
|
|
312
|
+
}
|
|
313
|
+
function filesEqual(a, b) {
|
|
314
|
+
try {
|
|
315
|
+
return readFileSync(a, "utf-8") === readFileSync(b, "utf-8");
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function toRel(root, abs) {
|
|
322
|
+
return relative(root, abs).replace(/\\/g, "/");
|
|
323
|
+
}
|
|
324
|
+
/** True if `name` (basename or first path segment) starts with `dkk-`. */
|
|
325
|
+
export function isDkkPrefixed(path) {
|
|
326
|
+
return basename(path).startsWith("dkk-");
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=dkk-artifacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dkk-artifacts.js","sourceRoot":"","sources":["../../../src/features/agent/dkk-artifacts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type InstallMode = "global" | "local" | "npx" | "unknown";
|
|
2
|
+
export interface InstallInfo {
|
|
3
|
+
/** How the running dkk binary was installed. */
|
|
4
|
+
mode: InstallMode;
|
|
5
|
+
/** Absolute path to the package root of the running install. */
|
|
6
|
+
packageRoot: string;
|
|
7
|
+
/** Absolute path to the npm global prefix's `node_modules` if resolvable, else null. */
|
|
8
|
+
globalNodeModules: string | null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Inspect the running dkk binary's location and return its install mode.
|
|
12
|
+
*
|
|
13
|
+
* Resolution order:
|
|
14
|
+
* 1. Path lives under `~/.npm/_npx/` → `npx`. npx installs are transient
|
|
15
|
+
* caches; upgrading them is meaningless.
|
|
16
|
+
* 2. Path lives under the npm global `node_modules/` (resolved by
|
|
17
|
+
* `npm root -g`) → `global`.
|
|
18
|
+
* 3. Otherwise treat as `local` — covers devDependency installs and
|
|
19
|
+
* direct `tsx src/cli.ts` (dev) invocations alike. Callers that care
|
|
20
|
+
* about the difference can re-check by looking for a host
|
|
21
|
+
* `package.json` that depends on the package.
|
|
22
|
+
* 4. If `npm root -g` fails (npm not on PATH, unlikely) → `unknown`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function detectInstallMode(): InstallInfo;
|
|
25
|
+
/**
|
|
26
|
+
* Query the npm registry for the latest published version of `pkgName`.
|
|
27
|
+
*
|
|
28
|
+
* Uses `npm view <pkg> version` because it respects the user's npm config
|
|
29
|
+
* (registry overrides, auth tokens, proxies) without us having to
|
|
30
|
+
* re-implement any of that. Returns `null` on failure — callers should
|
|
31
|
+
* treat that as "can't check" rather than failing the whole command.
|
|
32
|
+
*/
|
|
33
|
+
export declare function fetchLatestVersion(): string | null;
|
|
34
|
+
//# sourceMappingURL=install-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-mode.d.ts","sourceRoot":"","sources":["../../../src/features/agent/install-mode.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,IAAI,EAAE,WAAW,CAAC;IAClB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,wFAAwF;IACxF,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,CAkB/C;AAgBD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAYlD"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect how the running `dkk` binary was installed.
|
|
3
|
+
*
|
|
4
|
+
* `dkk update` needs to know this to pick the right `npm install`
|
|
5
|
+
* incantation (global vs. local devDep) and to refuse upgrade attempts
|
|
6
|
+
* under `npx`, where there's no persistent install to upgrade.
|
|
7
|
+
*/
|
|
8
|
+
import { execFileSync } from "node:child_process";
|
|
9
|
+
import { sep, normalize } from "node:path";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { packageRoot } from "../../shared/paths.js";
|
|
12
|
+
import { pkgName } from "../../version.js";
|
|
13
|
+
/**
|
|
14
|
+
* Inspect the running dkk binary's location and return its install mode.
|
|
15
|
+
*
|
|
16
|
+
* Resolution order:
|
|
17
|
+
* 1. Path lives under `~/.npm/_npx/` → `npx`. npx installs are transient
|
|
18
|
+
* caches; upgrading them is meaningless.
|
|
19
|
+
* 2. Path lives under the npm global `node_modules/` (resolved by
|
|
20
|
+
* `npm root -g`) → `global`.
|
|
21
|
+
* 3. Otherwise treat as `local` — covers devDependency installs and
|
|
22
|
+
* direct `tsx src/cli.ts` (dev) invocations alike. Callers that care
|
|
23
|
+
* about the difference can re-check by looking for a host
|
|
24
|
+
* `package.json` that depends on the package.
|
|
25
|
+
* 4. If `npm root -g` fails (npm not on PATH, unlikely) → `unknown`.
|
|
26
|
+
*/
|
|
27
|
+
export function detectInstallMode() {
|
|
28
|
+
const pkgRoot = normalize(packageRoot());
|
|
29
|
+
const globalNm = resolveGlobalNodeModules();
|
|
30
|
+
const npxPrefix = normalize(`${homedir()}${sep}.npm${sep}_npx${sep}`);
|
|
31
|
+
if (pkgRoot.startsWith(npxPrefix)) {
|
|
32
|
+
return { mode: "npx", packageRoot: pkgRoot, globalNodeModules: globalNm };
|
|
33
|
+
}
|
|
34
|
+
if (globalNm && pkgRoot.startsWith(normalize(globalNm) + sep)) {
|
|
35
|
+
return { mode: "global", packageRoot: pkgRoot, globalNodeModules: globalNm };
|
|
36
|
+
}
|
|
37
|
+
if (!globalNm) {
|
|
38
|
+
return { mode: "unknown", packageRoot: pkgRoot, globalNodeModules: null };
|
|
39
|
+
}
|
|
40
|
+
return { mode: "local", packageRoot: pkgRoot, globalNodeModules: globalNm };
|
|
41
|
+
}
|
|
42
|
+
function resolveGlobalNodeModules() {
|
|
43
|
+
try {
|
|
44
|
+
const out = execFileSync("npm", ["root", "-g"], {
|
|
45
|
+
encoding: "utf-8",
|
|
46
|
+
timeout: 10_000,
|
|
47
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
48
|
+
});
|
|
49
|
+
const path = out.trim();
|
|
50
|
+
return path.length > 0 ? path : null;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Query the npm registry for the latest published version of `pkgName`.
|
|
58
|
+
*
|
|
59
|
+
* Uses `npm view <pkg> version` because it respects the user's npm config
|
|
60
|
+
* (registry overrides, auth tokens, proxies) without us having to
|
|
61
|
+
* re-implement any of that. Returns `null` on failure — callers should
|
|
62
|
+
* treat that as "can't check" rather than failing the whole command.
|
|
63
|
+
*/
|
|
64
|
+
export function fetchLatestVersion() {
|
|
65
|
+
try {
|
|
66
|
+
const out = execFileSync("npm", ["view", pkgName, "version"], {
|
|
67
|
+
encoding: "utf-8",
|
|
68
|
+
timeout: 15_000,
|
|
69
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
70
|
+
});
|
|
71
|
+
const v = out.trim();
|
|
72
|
+
return /^\d+\.\d+\.\d+/.test(v) ? v : null;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=install-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-mode.js","sourceRoot":"","sources":["../../../src/features/agent/install-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAa3C;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,wBAAwB,EAAE,CAAC;IAE5C,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,OAAO,EAAE,GAAG,GAAG,OAAO,GAAG,OAAO,GAAG,EAAE,CAAC,CAAC;IACtE,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC;IAC5E,CAAC;IAED,IAAI,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;QAC9D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC;IAC/E,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAC5E,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC;AAC9E,CAAC;AAED,SAAS,wBAAwB;IAC/B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE;YAC9C,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,MAAM;YACf,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE;YAC5D,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,MAAM;YACf,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACrB,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type McpRegisterOutcome = {
|
|
2
|
+
status: "already-registered";
|
|
3
|
+
via: "project" | "claude-cli";
|
|
4
|
+
} | {
|
|
5
|
+
status: "registered";
|
|
6
|
+
via: "claude-cli" | "mcp-json";
|
|
7
|
+
} | {
|
|
8
|
+
status: "skipped";
|
|
9
|
+
reason: string;
|
|
10
|
+
} | {
|
|
11
|
+
status: "failed";
|
|
12
|
+
reason: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Detect existing registration → register via `claude mcp add` → fall back
|
|
16
|
+
* to writing `.mcp.json`. Returns a structured outcome rather than logging
|
|
17
|
+
* so callers can format the result as part of a larger summary.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ensureMcpRegistered(root: string): McpRegisterOutcome;
|
|
20
|
+
//# sourceMappingURL=mcp-register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-register.d.ts","sourceRoot":"","sources":["../../../src/features/agent/mcp-register.ts"],"names":[],"mappings":"AAuBA,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,oBAAoB,CAAC;IAAC,GAAG,EAAE,SAAS,GAAG,YAAY,CAAA;CAAE,GAC/D;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,GAAG,EAAE,YAAY,GAAG,UAAU,CAAA;CAAE,GACxD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AASzC;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CA6BpE"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register the DKK MCP server with Claude Code, with a fallback for
|
|
3
|
+
* environments where the `claude` CLI is unavailable.
|
|
4
|
+
*
|
|
5
|
+
* Order of attempts:
|
|
6
|
+
*
|
|
7
|
+
* 1. If a `dkk` MCP server is already present in the project's `.mcp.json`,
|
|
8
|
+
* skip — we don't want to overwrite a user's customised entry.
|
|
9
|
+
* 2. If `which claude` succeeds, run `claude mcp add dkk -- dkk mcp`.
|
|
10
|
+
* This writes into the user's Claude config (`~/.claude.json` or
|
|
11
|
+
* equivalent), which is the canonical place for project-agnostic
|
|
12
|
+
* Claude Code config.
|
|
13
|
+
* 3. Fallback: merge `{ "mcpServers": { "dkk": { "command": "dkk", "args": ["mcp"] } } }`
|
|
14
|
+
* into the project's `.mcp.json`, preserving any other servers
|
|
15
|
+
* already registered there.
|
|
16
|
+
*
|
|
17
|
+
* Failures are reported but never throw — `dkk update` continues even if
|
|
18
|
+
* MCP registration can't be completed automatically.
|
|
19
|
+
*/
|
|
20
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
21
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
const SERVER_NAME = "dkk";
|
|
24
|
+
/**
|
|
25
|
+
* Detect existing registration → register via `claude mcp add` → fall back
|
|
26
|
+
* to writing `.mcp.json`. Returns a structured outcome rather than logging
|
|
27
|
+
* so callers can format the result as part of a larger summary.
|
|
28
|
+
*/
|
|
29
|
+
export function ensureMcpRegistered(root) {
|
|
30
|
+
if (isRegisteredInProject(root)) {
|
|
31
|
+
return { status: "already-registered", via: "project" };
|
|
32
|
+
}
|
|
33
|
+
if (isRegisteredInClaudeCli()) {
|
|
34
|
+
return { status: "already-registered", via: "claude-cli" };
|
|
35
|
+
}
|
|
36
|
+
if (hasClaudeCli()) {
|
|
37
|
+
const result = spawnSync("claude", ["mcp", "add", SERVER_NAME, "--", "dkk", "mcp"], {
|
|
38
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
39
|
+
encoding: "utf-8",
|
|
40
|
+
timeout: 20_000,
|
|
41
|
+
});
|
|
42
|
+
if (result.status === 0) {
|
|
43
|
+
return { status: "registered", via: "claude-cli" };
|
|
44
|
+
}
|
|
45
|
+
// Fall through to .mcp.json if `claude mcp add` failed for some reason;
|
|
46
|
+
// we'd rather have a working entry than fail loudly here.
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
writeToMcpJson(root);
|
|
50
|
+
return { status: "registered", via: "mcp-json" };
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
54
|
+
return { status: "failed", reason: msg };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function isRegisteredInProject(root) {
|
|
58
|
+
const path = join(root, ".mcp.json");
|
|
59
|
+
if (!existsSync(path))
|
|
60
|
+
return false;
|
|
61
|
+
try {
|
|
62
|
+
const config = JSON.parse(readFileSync(path, "utf-8"));
|
|
63
|
+
return Boolean(config.mcpServers && SERVER_NAME in config.mcpServers);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function hasClaudeCli() {
|
|
70
|
+
try {
|
|
71
|
+
execFileSync("which", ["claude"], {
|
|
72
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
73
|
+
timeout: 5_000,
|
|
74
|
+
});
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function isRegisteredInClaudeCli() {
|
|
82
|
+
if (!hasClaudeCli())
|
|
83
|
+
return false;
|
|
84
|
+
try {
|
|
85
|
+
const out = execFileSync("claude", ["mcp", "list"], {
|
|
86
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
87
|
+
encoding: "utf-8",
|
|
88
|
+
timeout: 10_000,
|
|
89
|
+
});
|
|
90
|
+
// `claude mcp list` prints one server per line; match a token-bounded
|
|
91
|
+
// `dkk` rather than a substring so we don't false-positive on
|
|
92
|
+
// names like `dkk-extended`.
|
|
93
|
+
return new RegExp(`(^|\\s|:)${SERVER_NAME}(\\s|:|$)`, "m").test(out);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function writeToMcpJson(root) {
|
|
100
|
+
const path = join(root, ".mcp.json");
|
|
101
|
+
let config = {};
|
|
102
|
+
if (existsSync(path)) {
|
|
103
|
+
try {
|
|
104
|
+
config = JSON.parse(readFileSync(path, "utf-8"));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Corrupt .mcp.json — refuse to clobber it.
|
|
108
|
+
throw new Error(`.mcp.json exists but is not valid JSON; cannot merge dkk entry`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!config.mcpServers)
|
|
112
|
+
config.mcpServers = {};
|
|
113
|
+
config.mcpServers[SERVER_NAME] = { command: "dkk", args: ["mcp"] };
|
|
114
|
+
writeFileSync(path, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=mcp-register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-register.js","sourceRoot":"","sources":["../../../src/features/agent/mcp-register.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prune DKK-owned entries from a Claude `settings.json` payload.
|
|
3
|
+
*
|
|
4
|
+
* Used by `dkk update` to clear stale entries (e.g. hooks for scripts that
|
|
5
|
+
* have been renamed or removed) before re-applying the additive merge with
|
|
6
|
+
* the new template. User-authored entries are preserved untouched.
|
|
7
|
+
*
|
|
8
|
+
* Decision boundaries (see [[dkk-artifacts]] for the predicate source of
|
|
9
|
+
* truth):
|
|
10
|
+
*
|
|
11
|
+
* - A `permissions.allow` entry is DKK-owned iff it appears verbatim in
|
|
12
|
+
* the bundled template's allow list. Exact string equality is the right
|
|
13
|
+
* bar because the template's allow patterns are stable identifiers.
|
|
14
|
+
* - A `hooks.<event>` sub-entry is DKK-owned iff **every** `hooks[].command`
|
|
15
|
+
* inside it resolves via {@link extractHookBasename} to a DKK basename.
|
|
16
|
+
* Mixed entries (some DKK, some user-authored) are left intact and
|
|
17
|
+
* reported as warnings — pruning them partially would mutate
|
|
18
|
+
* user-authored data.
|
|
19
|
+
*/
|
|
20
|
+
import { type ClaudeSettings } from "./commands/init.js";
|
|
21
|
+
export interface PruneResult {
|
|
22
|
+
pruned: ClaudeSettings;
|
|
23
|
+
/** Human-readable summary of what was removed. */
|
|
24
|
+
removed: string[];
|
|
25
|
+
/** Hook entries that contained a mix of DKK + user-owned commands; left intact. */
|
|
26
|
+
mixedHookWarnings: string[];
|
|
27
|
+
}
|
|
28
|
+
export declare function pruneDkkEntries(settings: ClaudeSettings, dkkAllow: ReadonlySet<string>, dkkHookBasenames: ReadonlySet<string>): PruneResult;
|
|
29
|
+
//# sourceMappingURL=settings-prune.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-prune.d.ts","sourceRoot":"","sources":["../../../src/features/agent/settings-prune.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE9E,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,cAAc,CAAC;IACvB,kDAAkD;IAClD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mFAAmF;IACnF,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,EAC7B,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAC,GACpC,WAAW,CAmDb"}
|