peaks-cli 1.4.1 → 1.4.2

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 (57) hide show
  1. package/README.md +0 -53
  2. package/dist/src/cli/commands/core-artifact-commands.js +21 -0
  3. package/dist/src/cli/commands/memory-commands.d.ts +13 -0
  4. package/dist/src/cli/commands/memory-commands.js +60 -0
  5. package/dist/src/cli/commands/retrospective-commands.d.ts +9 -0
  6. package/dist/src/cli/commands/retrospective-commands.js +58 -0
  7. package/dist/src/cli/program.js +16 -22
  8. package/dist/src/services/fuzzy-matching/fuzzy-match-service.d.ts +15 -0
  9. package/dist/src/services/fuzzy-matching/fuzzy-match-service.js +56 -0
  10. package/dist/src/services/fuzzy-matching/types.d.ts +20 -0
  11. package/dist/src/services/fuzzy-matching/types.js +1 -0
  12. package/dist/src/services/memory/memory-search-service.d.ts +61 -0
  13. package/dist/src/services/memory/memory-search-service.js +80 -0
  14. package/dist/src/services/recommendations/capability-seed-items.js +0 -1
  15. package/dist/src/services/recommendations/capability-seed-mappings.js +0 -1
  16. package/dist/src/services/recommendations/capability-seed-sources.js +0 -1
  17. package/dist/src/services/retrospective/retrospective-search-service.d.ts +37 -0
  18. package/dist/src/services/retrospective/retrospective-search-service.js +75 -0
  19. package/dist/src/services/standards/project-context.d.ts +1 -1
  20. package/dist/src/services/standards/project-context.js +0 -4
  21. package/dist/src/services/standards/project-standards-service.js +1 -3
  22. package/dist/src/services/workspace/migrate-1-4-1-service.js +1 -1
  23. package/dist/src/shared/version.d.ts +1 -1
  24. package/dist/src/shared/version.js +1 -1
  25. package/package.json +3 -7
  26. package/skills/peaks-solo/SKILL.md +1 -1
  27. package/skills/peaks-solo/references/completion-handoff.md +3 -1
  28. package/dist/src/cli/commands/shadcn-commands.d.ts +0 -3
  29. package/dist/src/cli/commands/shadcn-commands.js +0 -35
  30. package/dist/src/cli/commands/skill-context-stats-command.d.ts +0 -40
  31. package/dist/src/cli/commands/skill-context-stats-command.js +0 -96
  32. package/dist/src/cli/commands/skill-scope-commands.d.ts +0 -51
  33. package/dist/src/cli/commands/skill-scope-commands.js +0 -310
  34. package/dist/src/services/shadcn/shadcn-service.d.ts +0 -27
  35. package/dist/src/services/shadcn/shadcn-service.js +0 -128
  36. package/dist/src/services/skill-scope/adapters/_stub-helper.d.ts +0 -39
  37. package/dist/src/services/skill-scope/adapters/_stub-helper.js +0 -98
  38. package/dist/src/services/skill-scope/adapters/claude-code.d.ts +0 -59
  39. package/dist/src/services/skill-scope/adapters/claude-code.js +0 -304
  40. package/dist/src/services/skill-scope/adapters/codex.d.ts +0 -2
  41. package/dist/src/services/skill-scope/adapters/codex.js +0 -12
  42. package/dist/src/services/skill-scope/adapters/cursor.d.ts +0 -2
  43. package/dist/src/services/skill-scope/adapters/cursor.js +0 -13
  44. package/dist/src/services/skill-scope/adapters/qoder.d.ts +0 -2
  45. package/dist/src/services/skill-scope/adapters/qoder.js +0 -13
  46. package/dist/src/services/skill-scope/adapters/tongyi.d.ts +0 -2
  47. package/dist/src/services/skill-scope/adapters/tongyi.js +0 -13
  48. package/dist/src/services/skill-scope/adapters/trae.d.ts +0 -2
  49. package/dist/src/services/skill-scope/adapters/trae.js +0 -12
  50. package/dist/src/services/skill-scope/detect.d.ts +0 -81
  51. package/dist/src/services/skill-scope/detect.js +0 -513
  52. package/dist/src/services/skill-scope/registry.d.ts +0 -41
  53. package/dist/src/services/skill-scope/registry.js +0 -83
  54. package/dist/src/services/skill-scope/source-of-truth.d.ts +0 -44
  55. package/dist/src/services/skill-scope/source-of-truth.js +0 -118
  56. package/dist/src/services/skill-scope/types.d.ts +0 -195
  57. package/dist/src/services/skill-scope/types.js +0 -97
@@ -1,304 +0,0 @@
1
- /**
2
- * `peaks skill scope` — Claude Code adapter (full impl, slice 025.1).
3
- *
4
- * Strategy (tech-doc-025 §3):
5
- * 1. PRIMARY: write `.claude/settings.local.json` with
6
- * `permissions.allow: ["Skill(name)", ...]` + `permissions.deny: [...]`.
7
- * 2. FALLBACK (R1, `--shadow-fallback`): when the runtime probe determines
8
- * Claude Code rejects `Skill(name)` in `permissions.deny`, write a
9
- * shadow stub at `.claude/skills/<name>/SKILL.md` for each denylisted
10
- * skill. Tagged with `_peaks_scope_disabled: true` (R6).
11
- *
12
- * Idempotency: dedupe the allow/deny arrays; shadow-stub writes skip
13
- * when the marker is already present. AC11.
14
- */
15
- import { existsSync } from 'node:fs';
16
- import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
17
- import { dirname, join } from 'node:path';
18
- /** Adapter id. */
19
- const IDE_ID = 'claude-code';
20
- /** Format the `Skill(name)` string Claude Code's permission system uses. */
21
- export function skillRef(name) {
22
- return `Skill(${name})`;
23
- }
24
- /** Dedupe a list preserving the first-seen order. */
25
- function dedupe(list) {
26
- const seen = new Set();
27
- const out = [];
28
- for (const item of list) {
29
- if (!seen.has(item)) {
30
- seen.add(item);
31
- out.push(item);
32
- }
33
- }
34
- return out;
35
- }
36
- const EMPTY_SETTINGS = { permissions: { allow: [], deny: [] } };
37
- /**
38
- * Read the existing `.claude/settings.local.json` (returns empty settings
39
- * if the file does not exist). On parse failure returns empty settings
40
- * and a warning rather than throwing — the user can still write fresh
41
- * settings.
42
- */
43
- async function readSettingsLocal(projectRoot) {
44
- const file = join(projectRoot, '.claude', 'settings.local.json');
45
- if (!existsSync(file))
46
- return { settings: EMPTY_SETTINGS, existed: false, malformed: false };
47
- try {
48
- const raw = await readFile(file, 'utf8');
49
- const parsed = JSON.parse(raw);
50
- if (parsed === null || typeof parsed !== 'object') {
51
- return { settings: EMPTY_SETTINGS, existed: true, malformed: true };
52
- }
53
- const obj = parsed;
54
- const permsRaw = obj.permissions;
55
- const perms = permsRaw !== null && typeof permsRaw === 'object'
56
- ? {
57
- allow: Array.isArray(permsRaw.allow)
58
- ? permsRaw.allow
59
- : [],
60
- deny: Array.isArray(permsRaw.deny)
61
- ? permsRaw.deny
62
- : [],
63
- }
64
- : { allow: [], deny: [] };
65
- return { settings: { ...obj, permissions: perms }, existed: true, malformed: false };
66
- }
67
- catch {
68
- return { settings: EMPTY_SETTINGS, existed: true, malformed: true };
69
- }
70
- }
71
- /**
72
- * Write the JSON file atomically via `.peaks-tmp` + `rename`. Removes the
73
- * temp file on partial failure.
74
- */
75
- async function writeJsonAtomic(file, data) {
76
- await mkdir(dirname(file), { recursive: true });
77
- const tmp = `${file}.peaks-tmp`;
78
- try {
79
- await writeFile(tmp, JSON.stringify(data, null, 2) + '\n', 'utf8');
80
- await rename(tmp, file);
81
- }
82
- catch (error) {
83
- if (existsSync(tmp)) {
84
- try {
85
- await rm(tmp, { force: true });
86
- }
87
- catch { /* best-effort */ }
88
- }
89
- throw error;
90
- }
91
- }
92
- /**
93
- * Map allowlist/denylist → permissions.allow/permissions.deny. Never sorts;
94
- * preserves input order. Always dedupes.
95
- */
96
- export function toPermissions(allowlist, denylist) {
97
- return {
98
- permissions: {
99
- allow: dedupe(allowlist.map(skillRef)),
100
- deny: dedupe(denylist.map(skillRef)),
101
- },
102
- };
103
- }
104
- /**
105
- * Strip any peaks-* name from the denylist (G6 hard constraint). Returns
106
- * the cleaned denylist + the list of stripped names for the audit log.
107
- */
108
- export function stripPeaksFromDenylist(denylist) {
109
- const cleaned = [];
110
- const stripped = [];
111
- for (const name of denylist) {
112
- if (name.startsWith('peaks-')) {
113
- stripped.push(name);
114
- }
115
- else {
116
- cleaned.push(name);
117
- }
118
- }
119
- return { cleaned, stripped };
120
- }
121
- /** Render the shadow-stub SKILL.md body (R6 marker). */
122
- function shadowStubBody(name) {
123
- return `---
124
- name: ${name}
125
- description: _peaks_scope_disabled
126
- _peaks_scope_disabled: true
127
- ---
128
- # Disabled by \`peaks skill scope --apply\`
129
-
130
- This skill is shadowed because the project has marked it as out of scope.
131
- To restore, run \`peaks skill scope --reset\` or edit \`.peaks/scope/skills.json\`.
132
- `;
133
- }
134
- async function writeShadowStub(projectRoot, name) {
135
- const file = join(projectRoot, '.claude', 'skills', name, 'SKILL.md');
136
- await mkdir(dirname(file), { recursive: true });
137
- // Skip if already has the marker
138
- if (existsSync(file)) {
139
- try {
140
- const existing = await readFile(file, 'utf8');
141
- if (existing.includes('_peaks_scope_disabled: true')) {
142
- return file;
143
- }
144
- }
145
- catch { /* fall through and overwrite */ }
146
- }
147
- await writeFile(file, shadowStubBody(name), 'utf8');
148
- return file;
149
- }
150
- /**
151
- * Runtime probe for whether Claude Code supports `Skill(name)` syntax in
152
- * `permissions.deny` (R1). For slice 025.1 we return `unknown` and let
153
- * the caller decide. Replace this with a real check when Claude Code's
154
- * `permissions.deny` schema is documented.
155
- */
156
- export async function probeSkillDenySupport() {
157
- return 'unknown';
158
- }
159
- /**
160
- * Decision: should the denylist use shadow stubs instead of `permissions.deny`?
161
- * Returns true when:
162
- * - The caller passes `shadowFallback: true`, OR
163
- * - The runtime probe returns `support-allow-only` / `unknown`.
164
- */
165
- async function shouldUseShadowStubs(input) {
166
- if (input.shadowFallback)
167
- return true;
168
- const probe = await probeSkillDenySupport();
169
- return probe !== 'support-allow-and-deny';
170
- }
171
- /** Strip the peaks-* shadow stubs written by a previous apply. */
172
- function shadowStubDir(projectRoot, name) {
173
- return join(projectRoot, '.claude', 'skills', name, 'SKILL.md');
174
- }
175
- async function removeShadowStubIfPresent(projectRoot, name) {
176
- const file = shadowStubDir(projectRoot, name);
177
- if (!existsSync(file))
178
- return false;
179
- try {
180
- const raw = await readFile(file, 'utf8');
181
- if (!raw.includes('_peaks_scope_disabled: true'))
182
- return false;
183
- await rm(file, { force: true });
184
- return true;
185
- }
186
- catch {
187
- return false;
188
- }
189
- }
190
- export class ClaudeCodeSkillScope {
191
- ide = IDE_ID;
192
- supported = true;
193
- constructor(_opts) {
194
- // projectRoot is supplied on every method call; the class is stateless.
195
- void _opts;
196
- }
197
- /** detect(): returns 1.0 when the project root has a .claude/ dir. */
198
- async detect(projectRoot) {
199
- return existsSync(join(projectRoot, '.claude')) ? 1.0 : 0.5;
200
- }
201
- async applyScope(input) {
202
- const written = [];
203
- const removed = [];
204
- // G6: strip peaks-* from the denylist.
205
- const { cleaned: cleanedDeny, stripped } = stripPeaksFromDenylist(input.denylist);
206
- if (stripped.length > 0) {
207
- removed.push(...stripped);
208
- }
209
- const useShadows = await shouldUseShadowStubs(input);
210
- // 1. Write (or skip) settings.local.json
211
- const { settings: existing } = await readSettingsLocal(input.projectRoot);
212
- const next = toPermissions(input.allowlist, cleanedDeny);
213
- // Preserve existing non-permissions fields (theme, env, etc.).
214
- const preserved = { ...existing };
215
- delete preserved.permissions;
216
- // Merge with the user's pre-existing allow/deny entries (deduped).
217
- const existingAllow = (existing.permissions.allow ?? []);
218
- const existingDeny = (existing.permissions.deny ?? []);
219
- const merged = {
220
- ...preserved,
221
- permissions: {
222
- allow: dedupe([...existingAllow, ...next.permissions.allow]),
223
- deny: dedupe([...existingDeny, ...next.permissions.deny]),
224
- },
225
- };
226
- if (input.simulateWriteFailure) {
227
- throw new Error('simulated write failure (settings.local.json)');
228
- }
229
- const settingsFile = join(input.projectRoot, '.claude', 'settings.local.json');
230
- await writeJsonAtomic(settingsFile, merged);
231
- written.push(settingsFile);
232
- // 2. Optionally write shadow stubs for the (stripped, cleaned) denylist
233
- let usedShadowStub = false;
234
- if (useShadows) {
235
- usedShadowStub = true;
236
- for (const name of cleanedDeny) {
237
- const stub = await writeShadowStub(input.projectRoot, name);
238
- written.push(stub);
239
- }
240
- }
241
- return {
242
- ide: this.ide,
243
- ok: true,
244
- writtenFiles: written,
245
- usedShadowStub,
246
- notSupported: false,
247
- strippedFromDenylist: stripped,
248
- };
249
- }
250
- async showScope(projectRoot) {
251
- const settingsFile = join(projectRoot, '.claude', 'settings.local.json');
252
- let native = null;
253
- if (existsSync(settingsFile)) {
254
- try {
255
- native = JSON.parse(await readFile(settingsFile, 'utf8'));
256
- }
257
- catch {
258
- native = null;
259
- }
260
- }
261
- return { source: null, native, ide: this.ide };
262
- }
263
- async resetScope(input) {
264
- const removed = [];
265
- const settingsFile = join(input.projectRoot, '.claude', 'settings.local.json');
266
- if (existsSync(settingsFile)) {
267
- // Only remove if it has a permissions.allow/deny field shaped by us,
268
- // otherwise leave the user's hand-curated file alone.
269
- try {
270
- const raw = await readFile(settingsFile, 'utf8');
271
- const parsed = JSON.parse(raw);
272
- if (parsed !== null &&
273
- typeof parsed === 'object' &&
274
- parsed.permissions !== undefined) {
275
- await rm(settingsFile, { force: true });
276
- removed.push(settingsFile);
277
- }
278
- }
279
- catch {
280
- // best-effort
281
- }
282
- }
283
- // Also remove shadow stubs (we don't know which skills are stubbed, so
284
- // we don't blindly walk .claude/skills; the caller can re-run detect +
285
- // reset if they need a full sweep). For the explicit case we know
286
- // about, we strip any stub whose marker is present.
287
- const skillsDir = join(input.projectRoot, '.claude', 'skills');
288
- if (existsSync(skillsDir)) {
289
- // Best-effort scan: only act when the file is unmistakably a stub.
290
- const { readdirSync } = await import('node:fs');
291
- const entries = readdirSync(skillsDir, { withFileTypes: true });
292
- for (const entry of entries) {
293
- if (!entry.isDirectory())
294
- continue;
295
- const removedStub = await removeShadowStubIfPresent(input.projectRoot, entry.name);
296
- if (removedStub) {
297
- removed.push(join(input.projectRoot, '.claude', 'skills', entry.name, 'SKILL.md'));
298
- }
299
- }
300
- }
301
- return { ide: this.ide, removedFiles: removed };
302
- }
303
- }
304
- export const CLAUDE_CODE_SKILL_SCOPE = new ClaudeCodeSkillScope();
@@ -1,2 +0,0 @@
1
- import type { SkillScopeAdapter } from '../types.js';
2
- export declare const CODEX_SKILL_SCOPE: SkillScopeAdapter;
@@ -1,12 +0,0 @@
1
- // TODO(slice-025.4-codex): research Codex's per-project skill scoping
2
- // config format. Codex uses `.codex/` for project-local config.
3
- //
4
- // Until the real format is known, this stub:
5
- // 1. Writes `.peaks/scope/codex-skills.json` (source-of-truth) on every
6
- // `applyScope` so the user's intent is captured on disk.
7
- // 2. Returns NOT_SUPPORTED with a clear message pointing at this slice.
8
- //
9
- // When implementing, replace the makeStubAdapter call with the real
10
- // CodexSkillScope class.
11
- import { makeStubAdapter } from './_stub-helper.js';
12
- export const CODEX_SKILL_SCOPE = makeStubAdapter('codex', 'slice-025.4-codex', 'Codex');
@@ -1,2 +0,0 @@
1
- import type { SkillScopeAdapter } from '../types.js';
2
- export declare const CURSOR_SKILL_SCOPE: SkillScopeAdapter;
@@ -1,13 +0,0 @@
1
- // TODO(slice-025.3-cursor): research Cursor's per-project skill scoping
2
- // config format. Cursor uses `.cursor/` for project-local config; the
3
- // skill-scope hook may live there or in `.cursor/rules/`.
4
- //
5
- // Until the real format is known, this stub:
6
- // 1. Writes `.peaks/scope/cursor-skills.json` (source-of-truth) on every
7
- // `applyScope` so the user's intent is captured on disk.
8
- // 2. Returns NOT_SUPPORTED with a clear message pointing at this slice.
9
- //
10
- // When implementing, replace the makeStubAdapter call with the real
11
- // CursorSkillScope class.
12
- import { makeStubAdapter } from './_stub-helper.js';
13
- export const CURSOR_SKILL_SCOPE = makeStubAdapter('cursor', 'slice-025.3-cursor', 'Cursor');
@@ -1,2 +0,0 @@
1
- import type { SkillScopeAdapter } from '../types.js';
2
- export declare const QODER_SKILL_SCOPE: SkillScopeAdapter;
@@ -1,13 +0,0 @@
1
- // TODO(slice-025.5-qoder): research Qoder's per-project skill scoping
2
- // config format. Qoder is an AI IDE by Alibaba; per-project config dir
3
- // is unconfirmed at slice 025.1.
4
- //
5
- // Until the real format is known, this stub:
6
- // 1. Writes `.peaks/scope/qoder-skills.json` (source-of-truth) on every
7
- // `applyScope` so the user's intent is captured on disk.
8
- // 2. Returns NOT_SUPPORTED with a clear message pointing at this slice.
9
- //
10
- // When implementing, replace the makeStubAdapter call with the real
11
- // QoderSkillScope class.
12
- import { makeStubAdapter } from './_stub-helper.js';
13
- export const QODER_SKILL_SCOPE = makeStubAdapter('qoder', 'slice-025.5-qoder', 'Qoder');
@@ -1,2 +0,0 @@
1
- import type { SkillScopeAdapter } from '../types.js';
2
- export declare const TONGYI_SKILL_SCOPE: SkillScopeAdapter;
@@ -1,13 +0,0 @@
1
- // TODO(slice-025.6-tongyi): research Tongyi Lingma's per-project skill
2
- // scoping config format. Tongyi Lingma is an AI IDE by Alibaba; per-
3
- // project config dir is unconfirmed at slice 025.1.
4
- //
5
- // Until the real format is known, this stub:
6
- // 1. Writes `.peaks/scope/tongyi-lingma-skills.json` (source-of-truth)
7
- // on every `applyScope` so the user's intent is captured on disk.
8
- // 2. Returns NOT_SUPPORTED with a clear message pointing at this slice.
9
- //
10
- // When implementing, replace the makeStubAdapter call with the real
11
- // TongyiSkillScope class.
12
- import { makeStubAdapter } from './_stub-helper.js';
13
- export const TONGYI_SKILL_SCOPE = makeStubAdapter('tongyi-lingma', 'slice-025.6-tongyi', 'Tongyi Lingma');
@@ -1,2 +0,0 @@
1
- import type { SkillScopeAdapter } from '../types.js';
2
- export declare const TRAE_SKILL_SCOPE: SkillScopeAdapter;
@@ -1,12 +0,0 @@
1
- // TODO(slice-025.2-trae): research Trae's per-project skill scoping config
2
- // format. Likely candidates: `.trae/skills.json` or `.trae/settings.json`.
3
- //
4
- // Until the real format is known, this stub:
5
- // 1. Writes `.peaks/scope/trae-skills.json` (source-of-truth) on every
6
- // `applyScope` so the user's intent is captured on disk.
7
- // 2. Returns NOT_SUPPORTED with a clear message pointing at this slice.
8
- //
9
- // When implementing, replace the makeStubAdapter call with the real
10
- // TraeSkillScope class.
11
- import { makeStubAdapter } from './_stub-helper.js';
12
- export const TRAE_SKILL_SCOPE = makeStubAdapter('trae', 'slice-025.2-trae', 'Trae IDE');
@@ -1,81 +0,0 @@
1
- /**
2
- * Detection algorithm for `peaks skill scope`.
3
- *
4
- * Pure function: given a project root and the installed-skills path, the
5
- * algorithm produces a `DetectResult` (signals + per-skill classification
6
- * + counts). No filesystem writes, no randomness, no time-of-day. AC11.
7
- *
8
- * Three layers:
9
- * 1. `extractProjectSignals(projectRoot)` — read package.json + tsconfig +
10
- * file tree (top-50 extensions).
11
- * 2. `classifySkill(skill, signals, hardcodedRules)` — keyword matching
12
- * against the skill's SKILL.md description.
13
- * 3. `detectSkillScope({ projectRoot, installedSkillsPath })` — top-level
14
- * orchestrator that returns the JSON envelope (AC1).
15
- */
16
- import type { ProjectSignals, SkillKind, SkillScopeCounts, SkillScopeRecord } from './types.js';
17
- /**
18
- * Walk `src/` (recursively) AND the project root, collecting the top-50
19
- * unique file extensions (sorted lexicographically) AND the per-extension
20
- * file count (used by R003.1 to compute fractional share).
21
- */
22
- export interface ScanResult {
23
- readonly extensions: readonly string[];
24
- readonly counts: Readonly<Record<string, number>>;
25
- readonly totalFiles: number;
26
- }
27
- export declare function scanFileTree(projectRoot: string, maxExtensions?: number): ScanResult;
28
- /**
29
- * Build the `ProjectSignals` object from the project root.
30
- */
31
- export declare function extractProjectSignals(projectRoot: string): Promise<ProjectSignals>;
32
- export interface InstalledSkill {
33
- readonly name: string;
34
- readonly description: string;
35
- readonly skillPath: string;
36
- }
37
- interface HardcodedRules {
38
- readonly alwaysRelevant: ReadonlySet<string>;
39
- readonly nonTsPrefixes: readonly string[];
40
- }
41
- /**
42
- * Infer the `SkillKind` for a skill by name. Used for the JSON envelope.
43
- */
44
- export declare function inferSkillKind(name: string, alwaysRelevant: ReadonlySet<string>): SkillKind;
45
- /**
46
- * Classify a single skill given the project signals. Returns the relevance
47
- * + a list of human-readable reasons (stable for fixtures, so unit tests
48
- * can assert exact strings).
49
- */
50
- export declare function classifySkill(skill: InstalledSkill, signals: ProjectSignals, rules: HardcodedRules): SkillScopeRecord;
51
- export interface DetectInput {
52
- readonly projectRoot: string;
53
- readonly installedSkillsPath?: string;
54
- readonly detectedIde?: string | null;
55
- }
56
- export interface DetectResult {
57
- readonly detectedIde: string | null;
58
- readonly projectSignals: ProjectSignals;
59
- readonly skills: readonly SkillScopeRecord[];
60
- readonly counts: SkillScopeCounts;
61
- }
62
- /**
63
- * Discover the installed skills under `installedSkillsPath` (default:
64
- * `~/.claude/skills`). Each subdir containing a SKILL.md counts as an
65
- * installed skill.
66
- */
67
- export declare function listInstalledSkills(installedSkillsPath: string): Promise<InstalledSkill[]>;
68
- /**
69
- * The default installed-skills path: `~/.claude/skills`. Resolved at call
70
- * time so the orchestrator stays pure-ish (no module-level side effects).
71
- */
72
- export declare function defaultInstalledSkillsPath(): string;
73
- /**
74
- * Top-level orchestrator. Reads package.json + tsconfig + file tree,
75
- * discovers installed skills, classifies each one, returns the JSON
76
- * envelope. Idempotent: same input → same output. No filesystem writes.
77
- */
78
- export declare function detectSkillScope(input: DetectInput): Promise<DetectResult>;
79
- /** Compute a stable summary hash (used by tests to assert no time-dependent fields). */
80
- export declare function detectSummary(result: DetectResult): string;
81
- export {};