peaks-cli 1.4.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/.claude-plugin/marketplace.json +51 -0
  2. package/CHANGELOG.md +238 -0
  3. package/README-en.md +226 -0
  4. package/README.md +142 -165
  5. package/dist/src/cli/commands/agent-commands.d.ts +20 -0
  6. package/dist/src/cli/commands/agent-commands.js +48 -0
  7. package/dist/src/cli/commands/audit-commands.d.ts +18 -0
  8. package/dist/src/cli/commands/audit-commands.js +138 -0
  9. package/dist/src/cli/commands/classify-classify-commands.d.ts +19 -0
  10. package/dist/src/cli/commands/classify-classify-commands.js +151 -0
  11. package/dist/src/cli/commands/code-review-commands.d.ts +34 -0
  12. package/dist/src/cli/commands/code-review-commands.js +83 -0
  13. package/dist/src/cli/commands/config-commands.js +90 -0
  14. package/dist/src/cli/commands/context-commands.d.ts +21 -0
  15. package/dist/src/cli/commands/context-commands.js +167 -0
  16. package/dist/src/cli/commands/core-artifact-commands.js +81 -2
  17. package/dist/src/cli/commands/hook-handle.js +50 -0
  18. package/dist/src/cli/commands/loop-commands.d.ts +21 -0
  19. package/dist/src/cli/commands/loop-commands.js +128 -0
  20. package/dist/src/cli/commands/memory-commands.d.ts +13 -0
  21. package/dist/src/cli/commands/memory-commands.js +60 -0
  22. package/dist/src/cli/commands/openspec-commands.js +37 -0
  23. package/dist/src/cli/commands/preferences-commands.d.ts +2 -0
  24. package/dist/src/cli/commands/preferences-commands.js +147 -0
  25. package/dist/src/cli/commands/retrospective-commands.d.ts +9 -0
  26. package/dist/src/cli/commands/retrospective-commands.js +58 -0
  27. package/dist/src/cli/commands/skill-conformance-commands.d.ts +9 -0
  28. package/dist/src/cli/commands/skill-conformance-commands.js +39 -0
  29. package/dist/src/cli/commands/understand-commands.js +34 -0
  30. package/dist/src/cli/commands/upgrade-commands.d.ts +23 -0
  31. package/dist/src/cli/commands/upgrade-commands.js +57 -0
  32. package/dist/src/cli/commands/workflow-commands.js +70 -0
  33. package/dist/src/cli/commands/workspace-commands.js +86 -0
  34. package/dist/src/cli/program.js +46 -22
  35. package/dist/src/services/agent/ecc-agent-service.d.ts +47 -0
  36. package/dist/src/services/agent/ecc-agent-service.js +143 -0
  37. package/dist/src/services/artifacts/request-artifact-service.js +14 -0
  38. package/dist/src/services/audit/backing-detector.d.ts +24 -0
  39. package/dist/src/services/audit/backing-detector.js +59 -0
  40. package/dist/src/services/audit/classifier.d.ts +38 -0
  41. package/dist/src/services/audit/classifier.js +127 -0
  42. package/dist/src/services/audit/enforcers/active-skill-resolver.d.ts +29 -0
  43. package/dist/src/services/audit/enforcers/active-skill-resolver.js +71 -0
  44. package/dist/src/services/audit/enforcers/design-draft-confirm.d.ts +25 -0
  45. package/dist/src/services/audit/enforcers/design-draft-confirm.js +54 -0
  46. package/dist/src/services/audit/enforcers/lint-audit-regression.d.ts +21 -0
  47. package/dist/src/services/audit/enforcers/lint-audit-regression.js +86 -0
  48. package/dist/src/services/audit/enforcers/lint-catalog-governance.d.ts +27 -0
  49. package/dist/src/services/audit/enforcers/lint-catalog-governance.js +38 -0
  50. package/dist/src/services/audit/enforcers/lint-cli-back.d.ts +16 -0
  51. package/dist/src/services/audit/enforcers/lint-cli-back.js +35 -0
  52. package/dist/src/services/audit/enforcers/lint-output-style.d.ts +11 -0
  53. package/dist/src/services/audit/enforcers/lint-output-style.js +94 -0
  54. package/dist/src/services/audit/enforcers/lint-reference-integrity.d.ts +6 -0
  55. package/dist/src/services/audit/enforcers/lint-reference-integrity.js +83 -0
  56. package/dist/src/services/audit/enforcers/lint-reference-shape.d.ts +30 -0
  57. package/dist/src/services/audit/enforcers/lint-reference-shape.js +272 -0
  58. package/dist/src/services/audit/enforcers/lint-style.d.ts +49 -0
  59. package/dist/src/services/audit/enforcers/lint-style.js +173 -0
  60. package/dist/src/services/audit/enforcers/lint-workflow-shape.d.ts +5 -0
  61. package/dist/src/services/audit/enforcers/lint-workflow-shape.js +141 -0
  62. package/dist/src/services/audit/enforcers/login-gate.d.ts +23 -0
  63. package/dist/src/services/audit/enforcers/login-gate.js +40 -0
  64. package/dist/src/services/audit/enforcers/mock-placement.d.ts +25 -0
  65. package/dist/src/services/audit/enforcers/mock-placement.js +48 -0
  66. package/dist/src/services/audit/enforcers/no-root-pollution.d.ts +21 -0
  67. package/dist/src/services/audit/enforcers/no-root-pollution.js +56 -0
  68. package/dist/src/services/audit/enforcers/pre-rd-scan.d.ts +22 -0
  69. package/dist/src/services/audit/enforcers/pre-rd-scan.js +23 -0
  70. package/dist/src/services/audit/enforcers/prototype-fidelity.d.ts +25 -0
  71. package/dist/src/services/audit/enforcers/prototype-fidelity.js +75 -0
  72. package/dist/src/services/audit/enforcers/resume-detection.d.ts +21 -0
  73. package/dist/src/services/audit/enforcers/resume-detection.js +52 -0
  74. package/dist/src/services/audit/enforcers/solo-code-ban.d.ts +23 -0
  75. package/dist/src/services/audit/enforcers/solo-code-ban.js +27 -0
  76. package/dist/src/services/audit/enforcers/sub-agent-sid.d.ts +25 -0
  77. package/dist/src/services/audit/enforcers/sub-agent-sid.js +63 -0
  78. package/dist/src/services/audit/enforcers/tech-doc-presence.d.ts +28 -0
  79. package/dist/src/services/audit/enforcers/tech-doc-presence.js +35 -0
  80. package/dist/src/services/audit/red-line-catalog-p2-a.d.ts +21 -0
  81. package/dist/src/services/audit/red-line-catalog-p2-a.js +233 -0
  82. package/dist/src/services/audit/red-line-catalog-p2-b.d.ts +19 -0
  83. package/dist/src/services/audit/red-line-catalog-p2-b.js +225 -0
  84. package/dist/src/services/audit/red-line-catalog.d.ts +51 -0
  85. package/dist/src/services/audit/red-line-catalog.js +210 -0
  86. package/dist/src/services/audit/red-lines-service.d.ts +23 -0
  87. package/dist/src/services/audit/red-lines-service.js +486 -0
  88. package/dist/src/services/audit/scanners/openspec-scanner.d.ts +15 -0
  89. package/dist/src/services/audit/scanners/openspec-scanner.js +55 -0
  90. package/dist/src/services/audit/scanners/rules-tree-scanner.d.ts +16 -0
  91. package/dist/src/services/audit/scanners/rules-tree-scanner.js +56 -0
  92. package/dist/src/services/audit/scanners/skills-tree-scanner.d.ts +17 -0
  93. package/dist/src/services/audit/scanners/skills-tree-scanner.js +46 -0
  94. package/dist/src/services/audit/static-service.d.ts +57 -0
  95. package/dist/src/services/audit/static-service.js +125 -0
  96. package/dist/src/services/audit/types.d.ts +69 -0
  97. package/dist/src/services/audit/types.js +13 -0
  98. package/dist/src/services/classify/classify-service.d.ts +42 -0
  99. package/dist/src/services/classify/classify-service.js +122 -0
  100. package/dist/src/services/classify/classify-types.d.ts +79 -0
  101. package/dist/src/services/classify/classify-types.js +90 -0
  102. package/dist/src/services/code-review/ocr-service.d.ts +129 -0
  103. package/dist/src/services/code-review/ocr-service.js +362 -0
  104. package/dist/src/services/config/config-migration.d.ts +32 -0
  105. package/dist/src/services/config/config-migration.js +92 -0
  106. package/dist/src/services/config/config-restore.d.ts +10 -0
  107. package/dist/src/services/config/config-restore.js +47 -0
  108. package/dist/src/services/config/config-rollback.d.ts +13 -0
  109. package/dist/src/services/config/config-rollback.js +26 -0
  110. package/dist/src/services/config/config-service.d.ts +35 -2
  111. package/dist/src/services/config/config-service.js +81 -0
  112. package/dist/src/services/config/config-types.d.ts +58 -0
  113. package/dist/src/services/config/config-types.js +6 -0
  114. package/dist/src/services/doctor/doctor-service.js +96 -0
  115. package/dist/src/services/fuzzy-matching/fuzzy-match-service.d.ts +15 -0
  116. package/dist/src/services/fuzzy-matching/fuzzy-match-service.js +56 -0
  117. package/dist/src/services/fuzzy-matching/types.d.ts +20 -0
  118. package/dist/src/services/fuzzy-matching/types.js +1 -0
  119. package/dist/src/services/ide/adapters/hermes-adapter.d.ts +21 -0
  120. package/dist/src/services/ide/adapters/hermes-adapter.js +51 -0
  121. package/dist/src/services/ide/adapters/openclaw-adapter.d.ts +14 -0
  122. package/dist/src/services/ide/adapters/openclaw-adapter.js +42 -0
  123. package/dist/src/services/ide/ide-registry.js +7 -0
  124. package/dist/src/services/ide/ide-types.d.ts +1 -1
  125. package/dist/src/services/memory/memory-search-service.d.ts +61 -0
  126. package/dist/src/services/memory/memory-search-service.js +80 -0
  127. package/dist/src/services/openspec/openspec-propose-from-doctor-service.d.ts +31 -0
  128. package/dist/src/services/openspec/openspec-propose-from-doctor-service.js +95 -0
  129. package/dist/src/services/preferences/preferences-service.d.ts +6 -0
  130. package/dist/src/services/preferences/preferences-service.js +43 -0
  131. package/dist/src/services/preferences/preferences-types.d.ts +90 -0
  132. package/dist/src/services/preferences/preferences-types.js +38 -0
  133. package/dist/src/services/recommendations/capability-seed-items.js +0 -1
  134. package/dist/src/services/recommendations/capability-seed-mappings.js +0 -1
  135. package/dist/src/services/recommendations/capability-seed-sources.js +0 -1
  136. package/dist/src/services/retrospective/retrospective-search-service.d.ts +37 -0
  137. package/dist/src/services/retrospective/retrospective-search-service.js +75 -0
  138. package/dist/src/services/skills/skill-conformance-service.d.ts +40 -0
  139. package/dist/src/services/skills/skill-conformance-service.js +136 -0
  140. package/dist/src/services/skills/skill-runbook-service.js +44 -10
  141. package/dist/src/services/skills/sync-service.d.ts +43 -0
  142. package/dist/src/services/skills/sync-service.js +99 -0
  143. package/dist/src/services/slice/slice-check-service.js +166 -13
  144. package/dist/src/services/slice/slice-check-types.d.ts +1 -1
  145. package/dist/src/services/standards/migrate-claude-rules-service.d.ts +19 -0
  146. package/dist/src/services/standards/migrate-claude-rules-service.js +193 -0
  147. package/dist/src/services/standards/project-context.d.ts +1 -1
  148. package/dist/src/services/standards/project-context.js +0 -4
  149. package/dist/src/services/standards/project-standards-service.js +1 -3
  150. package/dist/src/services/understand/understand-scan-service.js +15 -2
  151. package/dist/src/services/understand/understand-types.d.ts +26 -0
  152. package/dist/src/services/upgrade/1x-detector-service.d.ts +7 -0
  153. package/dist/src/services/upgrade/1x-detector-service.js +94 -0
  154. package/dist/src/services/upgrade/gitignore-migrate-service.d.ts +56 -0
  155. package/dist/src/services/upgrade/gitignore-migrate-service.js +170 -0
  156. package/dist/src/services/upgrade/upgrade-service.d.ts +47 -0
  157. package/dist/src/services/upgrade/upgrade-service.js +381 -0
  158. package/dist/src/services/workspace/migrate-1-4-1-service.js +1 -1
  159. package/dist/src/services/workspace/sid-naming-guard.d.ts +14 -0
  160. package/dist/src/services/workspace/sid-naming-guard.js +31 -0
  161. package/dist/src/services/workspace/workspace-archive-service.d.ts +19 -0
  162. package/dist/src/services/workspace/workspace-archive-service.js +32 -0
  163. package/dist/src/services/workspace/workspace-clean-service.d.ts +41 -0
  164. package/dist/src/services/workspace/workspace-clean-service.js +86 -0
  165. package/dist/src/services/workspace/workspace-state-service.d.ts +7 -0
  166. package/dist/src/services/workspace/workspace-state-service.js +43 -0
  167. package/dist/src/shared/change-id.js +4 -1
  168. package/dist/src/shared/version.d.ts +1 -1
  169. package/dist/src/shared/version.js +1 -1
  170. package/package.json +10 -8
  171. package/schemas/doctor-report.schema.json +1 -1
  172. package/scripts/install-skills.mjs +296 -12
  173. package/skills/peaks-doctor/SKILL.md +59 -0
  174. package/skills/peaks-doctor/references/doctor-check-catalog.md +31 -0
  175. package/skills/peaks-doctor/references/from-doctor-flow.md +64 -0
  176. package/skills/peaks-doctor/test_prompts.json +17 -0
  177. package/skills/peaks-ide/SKILL.md +2 -0
  178. package/skills/peaks-qa/SKILL.md +9 -7
  179. package/skills/peaks-qa/references/artifact-per-request.md +19 -5
  180. package/skills/peaks-qa/references/qa-perf-test-plan.md +6 -6
  181. package/skills/peaks-qa/references/qa-runbook.md +1 -1
  182. package/skills/peaks-rd/SKILL.md +25 -10
  183. package/skills/peaks-rd/references/ocr-integration.md +214 -0
  184. package/skills/peaks-rd/references/rd-fanout-contracts.md +70 -0
  185. package/skills/peaks-rd/references/rd-runbook.md +1 -1
  186. package/skills/peaks-solo/SKILL.md +11 -5
  187. package/skills/peaks-solo/references/completion-handoff.md +3 -1
  188. package/skills/peaks-solo/references/step-0-55-1x-detection.md +82 -0
  189. package/skills/peaks-solo/references/workflow-gates-and-types.md +9 -0
  190. package/dist/src/cli/commands/shadcn-commands.d.ts +0 -3
  191. package/dist/src/cli/commands/shadcn-commands.js +0 -35
  192. package/dist/src/cli/commands/skill-context-stats-command.d.ts +0 -40
  193. package/dist/src/cli/commands/skill-context-stats-command.js +0 -96
  194. package/dist/src/cli/commands/skill-scope-commands.d.ts +0 -51
  195. package/dist/src/cli/commands/skill-scope-commands.js +0 -310
  196. package/dist/src/services/shadcn/shadcn-service.d.ts +0 -27
  197. package/dist/src/services/shadcn/shadcn-service.js +0 -128
  198. package/dist/src/services/skill-scope/adapters/_stub-helper.d.ts +0 -39
  199. package/dist/src/services/skill-scope/adapters/_stub-helper.js +0 -98
  200. package/dist/src/services/skill-scope/adapters/claude-code.d.ts +0 -59
  201. package/dist/src/services/skill-scope/adapters/claude-code.js +0 -304
  202. package/dist/src/services/skill-scope/adapters/codex.d.ts +0 -2
  203. package/dist/src/services/skill-scope/adapters/codex.js +0 -12
  204. package/dist/src/services/skill-scope/adapters/cursor.d.ts +0 -2
  205. package/dist/src/services/skill-scope/adapters/cursor.js +0 -13
  206. package/dist/src/services/skill-scope/adapters/qoder.d.ts +0 -2
  207. package/dist/src/services/skill-scope/adapters/qoder.js +0 -13
  208. package/dist/src/services/skill-scope/adapters/tongyi.d.ts +0 -2
  209. package/dist/src/services/skill-scope/adapters/tongyi.js +0 -13
  210. package/dist/src/services/skill-scope/adapters/trae.d.ts +0 -2
  211. package/dist/src/services/skill-scope/adapters/trae.js +0 -12
  212. package/dist/src/services/skill-scope/detect.d.ts +0 -81
  213. package/dist/src/services/skill-scope/detect.js +0 -513
  214. package/dist/src/services/skill-scope/registry.d.ts +0 -41
  215. package/dist/src/services/skill-scope/registry.js +0 -83
  216. package/dist/src/services/skill-scope/source-of-truth.d.ts +0 -44
  217. package/dist/src/services/skill-scope/source-of-truth.js +0 -118
  218. package/dist/src/services/skill-scope/types.d.ts +0 -195
  219. package/dist/src/services/skill-scope/types.js +0 -97
@@ -1,83 +0,0 @@
1
- /**
2
- * `peaks skill scope` — adapter registry.
3
- *
4
- * The registry owns the map from IdeId → SkillScopeAdapter. It exposes two
5
- * functions:
6
- * - `getScopeAdapter(ide)` — direct lookup. Throws on unknown ide.
7
- * - `resolveActiveAdapter(projectRoot)` — discover the best adapter by
8
- * probing every registered adapter's `detect(projectRoot)`. Falls back
9
- * to Claude Code with a synthetic score of 0.5 when no adapter scores
10
- * ≥ 0.5 (R3: "Claude Code shipped, Trae in progress" per package.json).
11
- *
12
- * See tech-doc-025 §7 for the discovery flow + fallback semantics.
13
- */
14
- import { CLAUDE_CODE_SKILL_SCOPE } from './adapters/claude-code.js';
15
- import { CODEX_SKILL_SCOPE } from './adapters/codex.js';
16
- import { CURSOR_SKILL_SCOPE } from './adapters/cursor.js';
17
- import { QODER_SKILL_SCOPE } from './adapters/qoder.js';
18
- import { TONGYI_SKILL_SCOPE } from './adapters/tongyi.js';
19
- import { TRAE_SKILL_SCOPE } from './adapters/trae.js';
20
- /**
21
- * Insertion order: Claude Code first (shipped), then Trae (in progress),
22
- * then the four roadmap IDEs. The CLI's `--ide <name>` overrides this map.
23
- */
24
- const SCOPE_ADAPTERS = new Map([
25
- ['claude-code', CLAUDE_CODE_SKILL_SCOPE],
26
- ['trae', TRAE_SKILL_SCOPE],
27
- ['codex', CODEX_SKILL_SCOPE],
28
- ['cursor', CURSOR_SKILL_SCOPE],
29
- ['qoder', QODER_SKILL_SCOPE],
30
- ['tongyi-lingma', TONGYI_SKILL_SCOPE],
31
- ]);
32
- /** Get the adapter for a given IDE id. Throws on unsupported IDE. */
33
- export function getScopeAdapter(ide) {
34
- const adapter = SCOPE_ADAPTERS.get(ide);
35
- if (adapter === undefined) {
36
- throw new Error(`No SkillScopeAdapter for IDE: ${ide}. Registered: ${listScopeAdapterIds().join(', ') || '(none)'}`);
37
- }
38
- return adapter;
39
- }
40
- /** All registered adapter ids (insertion order). */
41
- export function listScopeAdapterIds() {
42
- return Array.from(SCOPE_ADAPTERS.keys());
43
- }
44
- /** All registered adapters (insertion order). */
45
- export function listScopeAdapters() {
46
- return Array.from(SCOPE_ADAPTERS.values());
47
- }
48
- /**
49
- * Discover the active adapter for a project root. Returns the highest-
50
- * scoring adapter; if all adapters score < 0.5, falls back to the Claude
51
- * Code adapter with a synthetic score of 0.5 (R3). Stubs (Trae, Cursor,
52
- * Codex, Qoder, Tongyi) return 0.0 from `detect()` so they never win.
53
- */
54
- export async function resolveActiveAdapter(projectRoot) {
55
- let best = null;
56
- for (const adapter of SCOPE_ADAPTERS.values()) {
57
- const score = await adapter.detect(projectRoot);
58
- if (best === null || score > best.score) {
59
- best = { adapter, score };
60
- }
61
- }
62
- if (best === null || best.score < 0.5) {
63
- return { adapter: CLAUDE_CODE_SKILL_SCOPE, score: 0.5, isFallback: true };
64
- }
65
- return { adapter: best.adapter, score: best.score, isFallback: false };
66
- }
67
- /**
68
- * Test seam: replace the registry (used by stub-adapter tests to inject
69
- * a fresh adapter for an IDE without restarting the module).
70
- */
71
- export function _setScopeAdapterForTesting(ide, adapter) {
72
- SCOPE_ADAPTERS.set(ide, adapter);
73
- }
74
- /** Test seam: reset to built-in defaults. */
75
- export function _resetScopeAdaptersForTesting() {
76
- SCOPE_ADAPTERS.clear();
77
- SCOPE_ADAPTERS.set('claude-code', CLAUDE_CODE_SKILL_SCOPE);
78
- SCOPE_ADAPTERS.set('trae', TRAE_SKILL_SCOPE);
79
- SCOPE_ADAPTERS.set('codex', CODEX_SKILL_SCOPE);
80
- SCOPE_ADAPTERS.set('cursor', CURSOR_SKILL_SCOPE);
81
- SCOPE_ADAPTERS.set('qoder', QODER_SKILL_SCOPE);
82
- SCOPE_ADAPTERS.set('tongyi-lingma', TONGYI_SKILL_SCOPE);
83
- }
@@ -1,44 +0,0 @@
1
- /**
2
- * Source-of-truth helpers for `peaks skill scope`.
3
- *
4
- * The source-of-truth file `.peaks/scope/skills.json` is the canonical
5
- * record of the user's scope intent. Adapters translate it to their
6
- * IDE-native config; the CLI always reads back from this file on `--show`.
7
- *
8
- * Atomicity: every write goes through `.peaks-tmp` first, then `rename`
9
- * (POSIX-atomic; on Windows `rename` is atomic for files on the same volume).
10
- * See tech-doc-025 §3.1.
11
- */
12
- import type { ScopeConfig } from './types.js';
13
- /** File name for the canonical source-of-truth. */
14
- export declare const SCOPE_FILE_NAME = "skills.json";
15
- /** Resolve the canonical source-of-truth path for a project root. */
16
- export declare function scopeFilePath(projectRoot: string): string;
17
- /** Resolve the per-IDE companion file path (kebab-case). */
18
- export declare function ideCompanionFilePath(projectRoot: string, ide: string): string;
19
- /** Resolve the `.peaks/scope/` directory for a project root. */
20
- export declare function scopeDir(projectRoot: string): string;
21
- /**
22
- * Read the source-of-truth scope config, or null if it does not exist.
23
- * Returns null on parse error too — the caller decides whether to surface.
24
- */
25
- export declare function readSourceOfTruth(projectRoot: string): Promise<ScopeConfig | null>;
26
- /**
27
- * Read the per-IDE companion file (`.peaks/scope/<ide>-skills.json`), or
28
- * null if it does not exist or is unparseable.
29
- */
30
- export declare function readIdeCompanion(projectRoot: string, ide: string): Promise<unknown>;
31
- /**
32
- * Write the canonical source-of-truth atomically. The `.peaks-tmp` file
33
- * is cleaned up in a finally block on partial failure.
34
- */
35
- export declare function writeSourceOfTruth(projectRoot: string, config: ScopeConfig): Promise<string>;
36
- /**
37
- * Write a generic JSON document atomically. Used by stub adapters for
38
- * their `<ide>-skills.json` companion file (G3 §4.1).
39
- */
40
- export declare function writeJsonAtomic(file: string, data: unknown): Promise<void>;
41
- /**
42
- * Remove a file if it exists. Returns true if it was removed.
43
- */
44
- export declare function removeIfExists(file: string): Promise<boolean>;
@@ -1,118 +0,0 @@
1
- /**
2
- * Source-of-truth helpers for `peaks skill scope`.
3
- *
4
- * The source-of-truth file `.peaks/scope/skills.json` is the canonical
5
- * record of the user's scope intent. Adapters translate it to their
6
- * IDE-native config; the CLI always reads back from this file on `--show`.
7
- *
8
- * Atomicity: every write goes through `.peaks-tmp` first, then `rename`
9
- * (POSIX-atomic; on Windows `rename` is atomic for files on the same volume).
10
- * See tech-doc-025 §3.1.
11
- */
12
- import { existsSync } from 'node:fs';
13
- import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
14
- import { dirname, join } from 'node:path';
15
- /** File name for the canonical source-of-truth. */
16
- export const SCOPE_FILE_NAME = 'skills.json';
17
- /** Resolve the canonical source-of-truth path for a project root. */
18
- export function scopeFilePath(projectRoot) {
19
- return join(projectRoot, '.peaks', 'scope', SCOPE_FILE_NAME);
20
- }
21
- /** Resolve the per-IDE companion file path (kebab-case). */
22
- export function ideCompanionFilePath(projectRoot, ide) {
23
- return join(projectRoot, '.peaks', 'scope', `${ide}-skills.json`);
24
- }
25
- /** Resolve the `.peaks/scope/` directory for a project root. */
26
- export function scopeDir(projectRoot) {
27
- return join(projectRoot, '.peaks', 'scope');
28
- }
29
- /**
30
- * Read the source-of-truth scope config, or null if it does not exist.
31
- * Returns null on parse error too — the caller decides whether to surface.
32
- */
33
- export async function readSourceOfTruth(projectRoot) {
34
- const file = scopeFilePath(projectRoot);
35
- if (!existsSync(file))
36
- return null;
37
- try {
38
- const raw = await readFile(file, 'utf8');
39
- return JSON.parse(raw);
40
- }
41
- catch {
42
- return null;
43
- }
44
- }
45
- /**
46
- * Read the per-IDE companion file (`.peaks/scope/<ide>-skills.json`), or
47
- * null if it does not exist or is unparseable.
48
- */
49
- export async function readIdeCompanion(projectRoot, ide) {
50
- const file = ideCompanionFilePath(projectRoot, ide);
51
- if (!existsSync(file))
52
- return null;
53
- try {
54
- const raw = await readFile(file, 'utf8');
55
- return JSON.parse(raw);
56
- }
57
- catch {
58
- return null;
59
- }
60
- }
61
- /**
62
- * Write the canonical source-of-truth atomically. The `.peaks-tmp` file
63
- * is cleaned up in a finally block on partial failure.
64
- */
65
- export async function writeSourceOfTruth(projectRoot, config) {
66
- const file = scopeFilePath(projectRoot);
67
- await mkdir(scopeDir(projectRoot), { recursive: true });
68
- const tmp = `${file}.peaks-tmp`;
69
- try {
70
- await writeFile(tmp, JSON.stringify(config, null, 2) + '\n', 'utf8');
71
- await rename(tmp, file);
72
- return file;
73
- }
74
- catch (error) {
75
- if (existsSync(tmp)) {
76
- try {
77
- await rm(tmp, { force: true });
78
- }
79
- catch { /* best-effort */ }
80
- }
81
- throw error;
82
- }
83
- }
84
- /**
85
- * Write a generic JSON document atomically. Used by stub adapters for
86
- * their `<ide>-skills.json` companion file (G3 §4.1).
87
- */
88
- export async function writeJsonAtomic(file, data) {
89
- await mkdir(dirname(file), { recursive: true });
90
- const tmp = `${file}.peaks-tmp`;
91
- try {
92
- await writeFile(tmp, JSON.stringify(data, null, 2) + '\n', 'utf8');
93
- await rename(tmp, file);
94
- }
95
- catch (error) {
96
- if (existsSync(tmp)) {
97
- try {
98
- await rm(tmp, { force: true });
99
- }
100
- catch { /* best-effort */ }
101
- }
102
- throw error;
103
- }
104
- }
105
- /**
106
- * Remove a file if it exists. Returns true if it was removed.
107
- */
108
- export async function removeIfExists(file) {
109
- if (!existsSync(file))
110
- return false;
111
- try {
112
- await rm(file, { force: true });
113
- return true;
114
- }
115
- catch {
116
- return false;
117
- }
118
- }
@@ -1,195 +0,0 @@
1
- /**
2
- * `peaks skill scope` — slice 025 multi-IDE skill scoping types.
3
- *
4
- * This file is the single source of truth for the `SkillScopeAdapter`
5
- * interface (G1). It is consumed by every per-IDE adapter (Claude Code
6
- * full impl, 5 stub adapters) and by the detection algorithm + CLI.
7
- *
8
- * Design notes (see tech-doc-025 §2):
9
- * - The interface is deliberately small: only the four operations the CLI
10
- * actually needs (detect / apply / show / reset).
11
- * - `detect()` returns a confidence score in [0, 1] so the registry can
12
- * pick the best match when several adapters are partially active.
13
- * - Errors are typed (NotSupportedError / ScopeApplyError), not strings.
14
- * The CLI maps `ScopeApplyError.code` to exit codes (see tech-doc §6.3).
15
- */
16
- import type { IdeId } from '../ide/ide-types.js';
17
- /** Detection bucket for a single installed skill (G5). */
18
- export type SkillRelevance = 'relevant' | 'borderline' | 'irrelevant';
19
- /** Skill category — used for the JSON envelope's `kind` field (AC1). */
20
- export type SkillKind = 'peaks-family' | 'generic-ai' | 'language-specific' | 'other';
21
- /** Per-skill detail emitted by the detect algorithm. */
22
- export interface SkillScopeRecord {
23
- /** Skill directory name (e.g. "peaks-rd", "tdd-guide"). */
24
- readonly name: string;
25
- /** Category — peaks-family, generic-ai, language-specific, other. */
26
- readonly kind: SkillKind;
27
- /** Detection bucket. */
28
- readonly relevance: SkillRelevance;
29
- /** Human-readable reasons that produced the bucket; stable for fixtures. */
30
- readonly reasons: readonly string[];
31
- }
32
- /** Counts of skills per bucket, for the JSON envelope (AC1). */
33
- export interface SkillScopeCounts {
34
- readonly relevant: number;
35
- readonly borderline: number;
36
- readonly irrelevant: number;
37
- }
38
- /** Project signals extracted from package.json + tsconfig + file tree (G5). */
39
- export interface ProjectSignals {
40
- /** True when the project's root package.json exists. */
41
- readonly hasPackageJson: boolean;
42
- readonly isTypeScript: boolean;
43
- readonly isTypeScriptESM: boolean;
44
- readonly isReact: boolean;
45
- readonly isVue: boolean;
46
- readonly isSvelte: boolean;
47
- readonly isNext: boolean;
48
- readonly isNestJS: boolean;
49
- readonly isExpress: boolean;
50
- readonly isFastify: boolean;
51
- readonly isPostgres: boolean;
52
- readonly isMysql: boolean;
53
- readonly isMongo: boolean;
54
- readonly isRedis: boolean;
55
- readonly isDocker: boolean;
56
- readonly isK8s: boolean;
57
- readonly isCommander: boolean;
58
- readonly isCodegraph: boolean;
59
- readonly isHeadroom: boolean;
60
- /** True when the project is a Python project (no package.json / has pyproject). */
61
- readonly isPython: boolean;
62
- /** Major version of Node engine requirement, or null. */
63
- readonly nodeEngineMajor: number | null;
64
- /** Top file extensions under src/ (max 50, lexicographically sorted, unique). */
65
- readonly topExtensions: readonly string[];
66
- /** Per-extension presence flags derived from topExtensions. */
67
- readonly hasFileExtension: Readonly<Record<string, boolean>>;
68
- /**
69
- * Per-extension fractional share (file count / total files, in [0, 1]).
70
- * Slice 025 / R003.1: replaces the binary `hasFileExtension` for the
71
- * keyword-matching path. A language/framework skill becomes `relevant`
72
- * only when its corresponding share is >= the configured threshold
73
- * (default 0.05). Extensions with 0 files are absent.
74
- */
75
- readonly shareByExtension: Readonly<Record<string, number>>;
76
- }
77
- /**
78
- * Default threshold for the share-based relevance check (R003.1).
79
- * Override at runtime with `PEAKS_SCOPE_THRESHOLD=0.05` (env) or
80
- * `--threshold 0.05` (CLI).
81
- */
82
- export declare const SCOPE_THRESHOLD_DEFAULT = 0.05;
83
- /**
84
- * Read the threshold from `PEAKS_SCOPE_THRESHOLD` env var, clamped to
85
- * [0, 1]. Falls back to SCOPE_THRESHOLD_DEFAULT.
86
- */
87
- export declare function readScopeThreshold(): number;
88
- /** The shape of the always-written source-of-truth file. */
89
- export interface ScopeConfig {
90
- /** ISO-8601 UTC timestamp at which this scope was last applied. */
91
- readonly generatedAt: string;
92
- /** Detected or explicitly-selected IDE id. */
93
- readonly ide: IdeId;
94
- /** Strictness mode (drives borderline handling). */
95
- readonly strict: boolean;
96
- /** Skills the user wants available (LLM-invokable). Always includes all peaks-*. */
97
- readonly allowlist: readonly string[];
98
- /** Skills the user wants hidden. */
99
- readonly denylist: readonly string[];
100
- /** Per-skill reasons (mirrored from detect, for audit). */
101
- readonly skills: readonly SkillScopeRecord[];
102
- /** Project signals that drove the classification. */
103
- readonly signals: ProjectSignals;
104
- }
105
- /** Returned from `applyScope`. */
106
- export interface ApplyResult {
107
- /** Adapter id that handled the apply. */
108
- readonly ide: IdeId;
109
- /** Whether the apply succeeded (false = NOT_SUPPORTED or hard failure). */
110
- readonly ok: boolean;
111
- /** Absolute paths the adapter wrote or removed. */
112
- readonly writtenFiles: readonly string[];
113
- /** Whether shadow stubs were used (Claude Code fallback path). */
114
- readonly usedShadowStub: boolean;
115
- /** Whether the adapter returned NOT_SUPPORTED and only wrote the source-of-truth. */
116
- readonly notSupported: boolean;
117
- /** Peaks-* skills the adapter stripped from the denylist (G6 enforcement report). */
118
- readonly strippedFromDenylist?: readonly string[];
119
- /** Optional error code when ok=false. */
120
- readonly error?: {
121
- readonly code: string;
122
- readonly message: string;
123
- };
124
- }
125
- /** Returned from `showScope`. */
126
- export interface ShowScopeResult {
127
- /** The source-of-truth config, or null if no scope has been applied. */
128
- readonly source: ScopeConfig | null;
129
- /** Whatever the adapter can read back from its native config. Null if not supported. */
130
- readonly native: unknown;
131
- /** Adapter id. */
132
- readonly ide: IdeId;
133
- }
134
- /** Reset output mirrors apply but without the lists. */
135
- export interface ResetScopeResult {
136
- readonly ide: IdeId;
137
- readonly removedFiles: readonly string[];
138
- }
139
- /** Sentinel error type for stub adapters (G3). */
140
- export declare class NotSupportedError extends Error {
141
- readonly code: "NOT_SUPPORTED";
142
- readonly ide: IdeId;
143
- constructor(ide: IdeId, message: string);
144
- }
145
- /** Errors emitted by adapters (validated by runtime probe in claude-code §3.4). */
146
- export type ScopeApplyErrorCode = 'NOT_SUPPORTED' | 'IO_ERROR' | 'MALFORMED_CONFIG' | 'WRITE_FAILED' | 'PARTIAL_FAILURE';
147
- export declare class ScopeApplyError extends Error {
148
- readonly code: ScopeApplyErrorCode;
149
- readonly ide: IdeId;
150
- constructor(code: ScopeApplyErrorCode, message: string, ide: IdeId);
151
- }
152
- /** Input to `applyScope`. */
153
- export interface ApplyScopeInput {
154
- /** Final allowlist (the CLI guarantees peaks-* is in here before calling). */
155
- readonly allowlist: readonly string[];
156
- /** Final denylist. */
157
- readonly denylist: readonly string[];
158
- /** Strictness mode. */
159
- readonly strict: boolean;
160
- /** Project root for resolving relative paths. */
161
- readonly projectRoot: string;
162
- /** Source-of-truth config that the adapter MAY re-derive fields from. */
163
- readonly sourceConfig: ScopeConfig;
164
- /** When true, prefer shadow-stub fallback over the native config. */
165
- readonly shadowFallback: boolean;
166
- /** Test seam: simulate an adapter write failure (returns the partial path written before failure). */
167
- readonly simulateWriteFailure?: boolean;
168
- }
169
- /** Reset input mirrors apply but without the lists. */
170
- export interface ResetScopeInput {
171
- readonly projectRoot: string;
172
- }
173
- /** The interface every adapter implements. */
174
- export interface SkillScopeAdapter {
175
- /** Adapter id; matches the IdeId it pairs with. */
176
- readonly ide: IdeId;
177
- /** Whether this adapter supports a real (non-stub) implementation. */
178
- readonly supported: boolean;
179
- /** Detect this adapter's IDE is active in the given project root. Returns a confidence score in [0,1]. */
180
- detect(projectRoot: string): Promise<number>;
181
- /** Write the IDE-specific scope config. */
182
- applyScope(input: ApplyScopeInput): Promise<ApplyResult>;
183
- /** Read the current scope config. */
184
- showScope(projectRoot: string): Promise<ShowScopeResult>;
185
- /** Remove the IDE-specific scope config. */
186
- resetScope(input: ResetScopeInput): Promise<ResetScopeResult>;
187
- }
188
- /** Helper: build a NOT_SUPPORTED ApplyResult (for stub adapters that pre-write source-of-truth). */
189
- export declare function makeNotSupportedResult(ide: IdeId, message: string, writtenFiles?: readonly string[]): ApplyResult;
190
- /** Hard-coded allowlist of peaks-* skills (G6 + generic AI-engineering skills per AC2). */
191
- export declare const ALWAYS_RELEVANT_SKILLS: readonly string[];
192
- /** Hard-coded denylist prefixes: non-TS language families (G5 §5.4). */
193
- export declare const NON_TS_SKILL_PREFIXES: readonly string[];
194
- /** File extensions the file-tree walker looks for (top-50 limit per tech-doc §5.1). */
195
- export declare const TRACKED_EXTENSIONS: readonly string[];
@@ -1,97 +0,0 @@
1
- /**
2
- * `peaks skill scope` — slice 025 multi-IDE skill scoping types.
3
- *
4
- * This file is the single source of truth for the `SkillScopeAdapter`
5
- * interface (G1). It is consumed by every per-IDE adapter (Claude Code
6
- * full impl, 5 stub adapters) and by the detection algorithm + CLI.
7
- *
8
- * Design notes (see tech-doc-025 §2):
9
- * - The interface is deliberately small: only the four operations the CLI
10
- * actually needs (detect / apply / show / reset).
11
- * - `detect()` returns a confidence score in [0, 1] so the registry can
12
- * pick the best match when several adapters are partially active.
13
- * - Errors are typed (NotSupportedError / ScopeApplyError), not strings.
14
- * The CLI maps `ScopeApplyError.code` to exit codes (see tech-doc §6.3).
15
- */
16
- /**
17
- * Default threshold for the share-based relevance check (R003.1).
18
- * Override at runtime with `PEAKS_SCOPE_THRESHOLD=0.05` (env) or
19
- * `--threshold 0.05` (CLI).
20
- */
21
- export const SCOPE_THRESHOLD_DEFAULT = 0.05;
22
- /**
23
- * Read the threshold from `PEAKS_SCOPE_THRESHOLD` env var, clamped to
24
- * [0, 1]. Falls back to SCOPE_THRESHOLD_DEFAULT.
25
- */
26
- export function readScopeThreshold() {
27
- const raw = process.env['PEAKS_SCOPE_THRESHOLD'];
28
- if (raw === undefined || raw === '')
29
- return SCOPE_THRESHOLD_DEFAULT;
30
- const parsed = Number(raw);
31
- if (!Number.isFinite(parsed))
32
- return SCOPE_THRESHOLD_DEFAULT;
33
- if (parsed < 0)
34
- return 0;
35
- if (parsed > 1)
36
- return 1;
37
- return parsed;
38
- }
39
- /** Sentinel error type for stub adapters (G3). */
40
- export class NotSupportedError extends Error {
41
- code = 'NOT_SUPPORTED';
42
- ide;
43
- constructor(ide, message) {
44
- super(`${ide}: ${message}`);
45
- this.name = 'NotSupportedError';
46
- this.ide = ide;
47
- }
48
- }
49
- export class ScopeApplyError extends Error {
50
- code;
51
- ide;
52
- constructor(code, message, ide) {
53
- super(`${ide}: ${message}`);
54
- this.name = 'ScopeApplyError';
55
- this.code = code;
56
- this.ide = ide;
57
- }
58
- }
59
- /** Helper: build a NOT_SUPPORTED ApplyResult (for stub adapters that pre-write source-of-truth). */
60
- export function makeNotSupportedResult(ide, message, writtenFiles = []) {
61
- return {
62
- ide,
63
- ok: false,
64
- writtenFiles: [...writtenFiles],
65
- usedShadowStub: false,
66
- notSupported: true,
67
- error: { code: 'NOT_SUPPORTED', message },
68
- };
69
- }
70
- /** Hard-coded allowlist of peaks-* skills (G6 + generic AI-engineering skills per AC2). */
71
- export const ALWAYS_RELEVANT_SKILLS = [
72
- // peaks-* family (G6 hard constraint)
73
- 'peaks-rd', 'peaks-qa', 'peaks-solo', 'peaks-prd', 'peaks-sc',
74
- 'peaks-txt', 'peaks-sop', 'peaks-solo-resume', 'peaks-solo-status',
75
- 'peaks-solo-test', 'peaks-ui', 'peaks-ide',
76
- // generic AI-engineering skills (per AC2)
77
- 'tdd-guide', 'coding-standards', 'karpathy-guidelines',
78
- 'continuous-learning', 'code-tour', 'agent-harness-construction',
79
- 'security-review', 'code-review',
80
- ];
81
- /** Hard-coded denylist prefixes: non-TS language families (G5 §5.4). */
82
- export const NON_TS_SKILL_PREFIXES = [
83
- 'kotlin-', 'python-', 'java-', 'rust-', 'go-', 'ruby-',
84
- 'swift-', 'csharp-', 'cpp-',
85
- ];
86
- /** File extensions the file-tree walker looks for (top-50 limit per tech-doc §5.1). */
87
- export const TRACKED_EXTENSIONS = [
88
- '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
89
- '.swift', '.kt', '.kts', '.java', '.scala',
90
- '.py', '.pyx', '.go', '.rs',
91
- '.rb', '.php', '.cs', '.cpp', '.c', '.h', '.hpp',
92
- '.vue', '.svelte', '.html', '.css', '.scss',
93
- '.json', '.yaml', '.yml', '.toml', '.md',
94
- '.sql', '.sh', '.bash', '.ps1',
95
- '.dockerfile', '.dockerignore', '.lua', '.ex', '.exs', '.erl', '.hs',
96
- '.dart', '.r', '.jl', '.clj',
97
- ];