peaks-cli 1.3.4 → 1.3.6

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 (69) hide show
  1. package/dist/src/cli/commands/hook-handle.d.ts +2 -2
  2. package/dist/src/cli/commands/hook-handle.js +5 -10
  3. package/dist/src/cli/commands/hooks-commands.js +44 -29
  4. package/dist/src/cli/commands/project-commands.js +7 -1
  5. package/dist/src/cli/commands/workspace-commands.js +1 -2
  6. package/dist/src/cli/program.js +3 -4
  7. package/dist/src/services/dashboard/project-dashboard-service.d.ts +0 -7
  8. package/dist/src/services/dashboard/project-dashboard-service.js +1 -8
  9. package/dist/src/services/dispatch/sub-agent-dispatcher.d.ts +45 -40
  10. package/dist/src/services/dispatch/sub-agent-dispatcher.js +25 -20
  11. package/dist/src/services/ide/adapters/claude-code-adapter.js +0 -3
  12. package/dist/src/services/ide/adapters/trae-adapter.js +2 -17
  13. package/dist/src/services/ide/ide-types.d.ts +1 -18
  14. package/dist/src/services/progress/progress-service.d.ts +23 -103
  15. package/dist/src/services/progress/progress-service.js +24 -137
  16. package/dist/src/services/scan/file-size-scan.d.ts +4 -0
  17. package/dist/src/services/scan/file-size-scan.js +32 -3
  18. package/dist/src/services/skills/hooks-settings-service.d.ts +57 -5
  19. package/dist/src/services/skills/hooks-settings-service.js +153 -28
  20. package/dist/src/shared/incrementing-number.d.ts +0 -8
  21. package/dist/src/shared/incrementing-number.js +11 -1
  22. package/dist/src/shared/version.d.ts +1 -1
  23. package/dist/src/shared/version.js +1 -1
  24. package/package.json +1 -1
  25. package/skills/peaks-prd/SKILL.md +16 -16
  26. package/skills/peaks-prd/references/workflow.md +4 -4
  27. package/skills/peaks-qa/SKILL.md +25 -32
  28. package/skills/peaks-qa/references/qa-fanout-contract.md +6 -6
  29. package/skills/peaks-qa/references/regression-gates.md +1 -1
  30. package/skills/peaks-rd/SKILL.md +8 -21
  31. package/skills/peaks-rd/references/{openspec-mcp-cli.md → openspec-cli.md} +11 -14
  32. package/skills/peaks-solo/SKILL.md +1 -1
  33. package/skills/peaks-solo/references/a2a-artifact-mapping.md +1 -1
  34. package/skills/peaks-solo/references/browser-workflow.md +49 -38
  35. package/skills/peaks-solo/references/external-skill-invocation.md +9 -7
  36. package/skills/peaks-solo/references/{openspec-mcp-workflow.md → openspec-workflow.md} +5 -20
  37. package/skills/peaks-solo/references/runbook.md +21 -21
  38. package/skills/peaks-solo/references/sub-agent-dispatch.md +16 -35
  39. package/skills/peaks-solo/references/swarm-dispatch-contract.md +9 -9
  40. package/skills/peaks-ui/SKILL.md +22 -24
  41. package/skills/peaks-ui/references/workflow.md +2 -2
  42. package/dist/src/cli/commands/mcp-commands.d.ts +0 -3
  43. package/dist/src/cli/commands/mcp-commands.js +0 -144
  44. package/dist/src/cli/commands/progress-close-kill.d.ts +0 -51
  45. package/dist/src/cli/commands/progress-close-kill.js +0 -152
  46. package/dist/src/cli/commands/progress-commands.d.ts +0 -3
  47. package/dist/src/cli/commands/progress-commands.js +0 -379
  48. package/dist/src/cli/commands/progress-start-spawn.d.ts +0 -59
  49. package/dist/src/cli/commands/progress-start-spawn.js +0 -140
  50. package/dist/src/cli/commands/progress-watch-render.d.ts +0 -80
  51. package/dist/src/cli/commands/progress-watch-render.js +0 -308
  52. package/dist/src/services/mcp/mcp-apply-service.d.ts +0 -31
  53. package/dist/src/services/mcp/mcp-apply-service.js +0 -112
  54. package/dist/src/services/mcp/mcp-call-service.d.ts +0 -17
  55. package/dist/src/services/mcp/mcp-call-service.js +0 -34
  56. package/dist/src/services/mcp/mcp-client-service.d.ts +0 -14
  57. package/dist/src/services/mcp/mcp-client-service.js +0 -49
  58. package/dist/src/services/mcp/mcp-install-registry.d.ts +0 -11
  59. package/dist/src/services/mcp/mcp-install-registry.js +0 -38
  60. package/dist/src/services/mcp/mcp-plan-service.d.ts +0 -29
  61. package/dist/src/services/mcp/mcp-plan-service.js +0 -109
  62. package/dist/src/services/mcp/mcp-protocol.d.ts +0 -24
  63. package/dist/src/services/mcp/mcp-protocol.js +0 -41
  64. package/dist/src/services/mcp/mcp-scan-service.d.ts +0 -8
  65. package/dist/src/services/mcp/mcp-scan-service.js +0 -214
  66. package/dist/src/services/mcp/mcp-stdio-transport.d.ts +0 -10
  67. package/dist/src/services/mcp/mcp-stdio-transport.js +0 -50
  68. package/dist/src/services/mcp/mcp-types.d.ts +0 -31
  69. package/dist/src/services/mcp/mcp-types.js +0 -1
@@ -7,10 +7,10 @@ import { type ProgramIO } from '../cli-helpers.js';
7
7
  * 1. 读 stdin
8
8
  * 2. auto-detect 来源 IDE(env / stdin shape / cwd)
9
9
  * 3. 归一化到 peaks canonical schema
10
- * 4. dispatch 到内部 peaks 逻辑(目前:gate enforce 或 progress start)
10
+ * 4. dispatch 到内部 peaks 逻辑(目前:gate enforce)
11
11
  * 5. 用 IDE 期望的格式发回决策
12
12
  *
13
- * Slice #1 阶段:peaks hook handle 与 peaks gate enforce / peaks progress start
13
+ * Slice #1 阶段:peaks hook handle 与 peaks gate enforce
14
14
  * 并存(后者内部走 hook-translator)。Slice #2 把 IDE settings 改成调用
15
15
  * peaks hook handle 即可。Slice #3 删除旧命令。
16
16
  */
@@ -30,18 +30,18 @@ async function readStdin() {
30
30
  * 1. 读 stdin
31
31
  * 2. auto-detect 来源 IDE(env / stdin shape / cwd)
32
32
  * 3. 归一化到 peaks canonical schema
33
- * 4. dispatch 到内部 peaks 逻辑(目前:gate enforce 或 progress start)
33
+ * 4. dispatch 到内部 peaks 逻辑(目前:gate enforce)
34
34
  * 5. 用 IDE 期望的格式发回决策
35
35
  *
36
- * Slice #1 阶段:peaks hook handle 与 peaks gate enforce / peaks progress start
36
+ * Slice #1 阶段:peaks hook handle 与 peaks gate enforce
37
37
  * 并存(后者内部走 hook-translator)。Slice #2 把 IDE settings 改成调用
38
38
  * peaks hook handle 即可。Slice #3 删除旧命令。
39
39
  */
40
40
  export function registerHookHandleCommand(program, io) {
41
- const hook = program.command('hook').description('Peaks 自有 hook 协议单一入口(slice #1 新增;后续 slice 将逐步替代 gate enforce / progress start)');
41
+ const hook = program.command('hook').description('Peaks 自有 hook 协议单一入口(slice #1 新增;后续 slice 将逐步替代 gate enforce)');
42
42
  addJsonOption(hook
43
43
  .command('handle')
44
- .description('Read stdin hook payload, auto-detect IDE, dispatch to peaks gate/progress logic, output IDE-formatted decision')
44
+ .description('Read stdin hook payload, auto-detect IDE, dispatch to peaks gate-enforce logic, output IDE-formatted decision')
45
45
  .option('--project <path>', 'project the gates evaluate against (default: current directory)', '.')).action(async (options) => {
46
46
  try {
47
47
  const raw = await readStdin();
@@ -74,7 +74,7 @@ export function registerHookHandleCommand(program, io) {
74
74
  rawIdeFormat: ide,
75
75
  rawPayload: parsed
76
76
  });
77
- // Dispatch by toolName. For slice #1, we only handle Bash and Task.
77
+ // Dispatch by toolName. For slice #1+, we only handle Bash. Task tool sub-agent dispatch goes through `peaks sub-agent dispatch` (slice #009) and does not need a hook entry.
78
78
  // Other tools: allow (no-op; future events will be added here).
79
79
  if (hook.toolName === 'Bash' && typeof fallbackCommand === 'string' && fallbackCommand.trim().length > 0) {
80
80
  // Lazy import to avoid circular: peaks gate enforce logic
@@ -89,11 +89,6 @@ export function registerHookHandleCommand(program, io) {
89
89
  return;
90
90
  }
91
91
  }
92
- else if (hook.toolName === 'Task') {
93
- // peaks progress start is a fire-and-forget; do not block hook.handle.
94
- // Slice #1: simply acknowledge (no terminal spawn from hook handle itself;
95
- // the legacy `peaks progress start` command still does that).
96
- }
97
92
  const allow = formatDecisionResponse(ide, 'allow');
98
93
  io.stdout(allow.stdout);
99
94
  if (options.json === true) {
@@ -1,7 +1,9 @@
1
+ import { existsSync } from 'node:fs';
1
2
  import { fail, ok } from '../../shared/result.js';
2
3
  import { addJsonOption, printResult, getErrorMessage } from '../cli-helpers.js';
3
4
  import { findProjectRoot } from '../../services/config/config-safety.js';
4
- import { applyHookInstall, planHookInstall, readHookStatus, removeHookInstall } from '../../services/skills/hooks-settings-service.js';
5
+ import { applyHookInstall, planHookInstall, readHookStatus, readInstalledEntriesFromSettings, removeHookInstall } from '../../services/skills/hooks-settings-service.js';
6
+ import { readJsonObjectFile } from '../../services/ide/shared/atomic-json.js';
5
7
  import { detectIdeFromContext } from '../../services/ide/hook-translator.js';
6
8
  import { getAdapter } from '../../services/ide/ide-registry.js';
7
9
  function resolveScope(options) {
@@ -23,60 +25,63 @@ function resolveIdeForCommand(options, projectRoot) {
23
25
  }
24
26
  return detectIdeFromContext({ env: process.env, cwd: projectRoot ?? process.cwd(), parsedStdin: null });
25
27
  }
26
- // Slice #3: compute the per-IDE peaks hook entries for the CLI response
27
- // summary. Replaces the slice #1 PEAKS_HOOK_ENTRIES constant which was
28
- // hardcoded to claude-code values. Slice 2026-06-06-sub-agent-spawn-bug-
29
- // and-decouple: the sub-agent progress matcher now reads from
30
- // `adapter.subAgentToolMatcher` instead of being hardcoded to 'Task', so
31
- // every IDE self-reports its sub-agent tool name (claude-code: 'Task',
32
- // future adapters: whatever the adapter declares).
33
- function listInstalledEntriesForIde(ide) {
28
+ /**
29
+ * Slice #014: compute the per-IDE peaks hook entries for the install /
30
+ * dry-run RESPONSE SUMMARY. This is the *desired* shape (what the install
31
+ * WOULD write), not what is on disk. The status command uses a different
32
+ * helper (`readInstalledEntriesFromSettings`) that reads the actual
33
+ * settings.json.
34
+ *
35
+ * After slice #014 only the gate-enforce entry is ever installed
36
+ * (the legacy progress-start surface is gone). The summary mirrors
37
+ * the install shape so the JSON envelope doesn't claim a hook the
38
+ * service did not write.
39
+ */
40
+ function listExpectedEntriesForIde(ide, _skipProgress = false) {
34
41
  const adapter = getAdapter(ide);
35
42
  if (ide === 'trae') {
36
- return [
37
- { matcher: adapter.toolMatcher, sentinel: 'peaks hook handle' },
38
- { matcher: adapter.subAgentToolMatcher, sentinel: 'peaks progress start' }
39
- ];
43
+ return [{ matcher: adapter.toolMatcher, sentinel: 'peaks hook handle' }];
40
44
  }
41
- // Default (claude-code) and any future registered adapters.
42
- return [
43
- { matcher: adapter.toolMatcher, sentinel: 'peaks gate enforce' },
44
- { matcher: adapter.subAgentToolMatcher, sentinel: 'peaks progress start' }
45
- ];
45
+ return [{ matcher: adapter.toolMatcher, sentinel: 'peaks gate enforce' }];
46
46
  }
47
47
  export function registerHooksCommands(program, io) {
48
48
  const hooks = program
49
49
  .command('hooks')
50
- .description("Manage the Peaks-managed hook entries in the adapter's settings.json (default: .claude/settings.json for Claude, .trae/settings.json for Trae): (1) gate-enforce hook (SOP gate), (2) progress-start hook (auto-spawn sub-agent progress terminal). Both are installed / removed together. The IDE is auto-detected from env / cwd; override with --ide <id>.");
50
+ .description("Manage the Peaks-managed hook entry in the adapter's settings.json (default: .claude/settings.json for Claude, .trae/settings.json for Trae). Slice #014: the only installed entry is the gate-enforce hook (SOP gate). The legacy progress-start hook (auto-spawn sub-agent progress terminal) is no longer installed — sub-agent progress is now surfaced via the dispatch + heartbeat flow (`peaks sub-agent dispatch` / `peaks sub-agent heartbeat`). The IDE is auto-detected from env / cwd; override with --ide <id>.");
51
51
  addJsonOption(hooks
52
52
  .command('install')
53
- .description(`Install all peaks-managed hook entries into the adapter's settings.json. Idempotent: re-runs are no-ops. Project scope by default.`)
53
+ .description(`Install the peaks-managed gate-enforce hook entry into the adapter's settings.json. Slice #014: only the gate-enforce entry is installed; the legacy progress-start entry is no longer installed. Idempotent: re-runs are no-ops. Project scope by default.`)
54
54
  .option('--global', 'install into the user-level ~/.claude/settings.json instead of the project')
55
55
  .option('--project <path>', 'project root path (auto-detected from cwd when omitted)')
56
56
  .option('--ide <id>', "target adapter id (claude-code | trae); default: auto-detect from env/cwd")
57
- .option('--dry-run', 'show what would change without writing')).action((options) => {
57
+ .option('--dry-run', 'show what would change without writing')
58
+ .option('--no-progress', 'skip the progress-start PreToolUse hook entry; install ONLY the gate-enforce entry')).action((options) => {
58
59
  const scope = resolveScope(options);
59
60
  const projectRoot = resolveProjectRoot(scope, options.project);
60
61
  const ide = resolveIdeForCommand(options, projectRoot);
62
+ const skipProgress = options.progress === false;
61
63
  try {
62
64
  if (options.dryRun === true) {
63
- const plan = planHookInstall(scope, projectRoot, { ide });
64
- const dryRunEntries = listInstalledEntriesForIde(ide);
65
+ const plan = planHookInstall(scope, projectRoot, { ide, skipProgress });
66
+ const dryRunEntries = listExpectedEntriesForIde(ide, skipProgress);
65
67
  printResult(io, ok('hooks.install', {
66
68
  ...plan,
67
69
  ide,
68
70
  applied: false,
69
71
  dryRun: true,
72
+ skipProgress,
70
73
  entries: dryRunEntries
71
74
  }, [], [`would install ${dryRunEntries.length} peaks-managed hook entries`]), options.json);
72
75
  return;
73
76
  }
74
- const result = applyHookInstall(scope, projectRoot, { ide });
77
+ const result = applyHookInstall(scope, projectRoot, { ide, skipProgress });
75
78
  // Slice #3: build the per-IDE entries summary from the actual installed
76
79
  // entries, not the slice #1 PEAKS_HOOK_ENTRIES constant (which is the
77
80
  // claude-code default). The user's JSON envelope must reflect the IDE
78
- // they targeted.
79
- const installedEntries = listInstalledEntriesForIde(ide);
81
+ // they targeted. Slice #014: the install only emits the gate-enforce
82
+ // entry; the summary mirrors the install shape, NOT a hardcoded
83
+ // expected list.
84
+ const installedEntries = listExpectedEntriesForIde(ide, skipProgress);
80
85
  const nextActions = result.applied
81
86
  ? [
82
87
  'Restart the IDE (or reload the workspace) so the hook entries take effect',
@@ -87,18 +92,19 @@ export function registerHooksCommands(program, io) {
87
92
  ...result,
88
93
  ide,
89
94
  dryRun: false,
95
+ skipProgress,
90
96
  entries: installedEntries.map((e) => ({ matcher: e.matcher, sentinel: e.sentinel }))
91
97
  }, [], nextActions), options.json);
92
98
  }
93
99
  catch (error) {
94
100
  const message = getErrorMessage(error);
95
- printResult(io, fail('hooks.install', 'HOOKS_INSTALL_FAILED', message, { scope, ide, applied: false }, [message]), options.json);
101
+ printResult(io, fail('hooks.install', 'HOOKS_INSTALL_FAILED', message, { scope, ide, applied: false, skipProgress }, [message]), options.json);
96
102
  process.exitCode = 1;
97
103
  }
98
104
  });
99
105
  addJsonOption(hooks
100
106
  .command('uninstall')
101
- .description("Remove all peaks-managed hook entries (gate-enforce + progress-start) from the target settings.json. Third-party hooks are preserved.")
107
+ .description("Remove the peaks-managed gate-enforce hook entry from the target settings.json. Any legacy progress-start entry that a pre-#014 install left behind is also removed (sentinel-based scan). Third-party hooks are preserved.")
102
108
  .option('--global', 'remove from the user-level ~/.claude/settings.json instead of the project')
103
109
  .option('--project <path>', 'project root path (auto-detected from cwd when omitted)')
104
110
  .option('--ide <id>', 'target adapter id (claude-code | trae); default: auto-detect from env/cwd')).action((options) => {
@@ -126,10 +132,19 @@ export function registerHooksCommands(program, io) {
126
132
  const ide = resolveIdeForCommand(options, projectRoot);
127
133
  try {
128
134
  const status = readHookStatus(scope, projectRoot, { ide });
135
+ // Slice #014: read the ACTUAL on-disk entries (post-install shape),
136
+ // not the IDE-EXPECTED list. Pre-#014 `listInstalledEntriesForIde`
137
+ // returned the expected list and reported `entries: [Bash, Task]`
138
+ // even when the file only had `Bash`. The new helper reads the
139
+ // file and reports whatever peaks-managed entries are present,
140
+ // including any legacy progress-start entry that a pre-#014
141
+ // install left behind.
142
+ const settingsPath = status.settingsPath;
143
+ const settings = existsSync(settingsPath) ? readJsonObjectFile(settingsPath) : {};
129
144
  printResult(io, ok('hooks.status', {
130
145
  ...status,
131
146
  ide,
132
- entries: listInstalledEntriesForIde(ide)
147
+ entries: readInstalledEntriesFromSettings(settings, ide)
133
148
  }), options.json);
134
149
  }
135
150
  catch (error) {
@@ -78,7 +78,13 @@ export function registerProjectCommands(program, io) {
78
78
  .description('Scan a session artifact directory and extract <!-- peaks-memory:start --> blocks into .peaks/memory/')
79
79
  .requiredOption('--session-id <id>', 'session id (e.g. 2026-05-29-session-89ff35)')
80
80
  .requiredOption('--project <path>', 'target project root')
81
- .option('--dry-run', 'preview writes without changing files', true)
81
+ // Slice #015: drop the `--dry-run true` default. With the default
82
+ // set to true, `options.dryRun === true && options.apply === true`
83
+ // fired on every `--apply` call (because dryRun was true by
84
+ // default), permanently breaking `--apply`. `--dry-run` is now
85
+ // opt-in; the mutual-exclusion check below is correct without a
86
+ // special-case.
87
+ .option('--dry-run', 'preview writes without changing files')
82
88
  .option('--apply', 'write extracted memories into .peaks/memory/')).action((options) => {
83
89
  if (options.dryRun === true && options.apply === true) {
84
90
  printResult(io, fail('project.memories:extract', 'INVALID_MEMORY_EXTRACT_FLAGS', 'Use either --dry-run or --apply, not both', { sessionId: options.sessionId, projectRoot: options.project }, ['Run without --apply to preview writes, or pass --apply to write memories']), options.json);
@@ -449,8 +449,7 @@ export async function resolveFirstTimeHooksInstall(options) {
449
449
  // effectiveMode === 'ask' AND TTY: prompt once.
450
450
  process.stderr.write('\nPeaks-Cli: install the PreToolUse hooks for this project now?\n' +
451
451
  ' → Bash matcher: `peaks gate enforce` (SOP gate enforcement)\n' +
452
- ' Task matcher: `peaks progress start` (auto-spawn sub-agent progress terminal)\n' +
453
- 'Both run on every Claude Code tool call without further prompting. The decision is sticky\n' +
452
+ 'The gate-enforce hook runs on every Claude Code tool call without further prompting. The decision is sticky\n' +
454
453
  '(recorded in .peaks/.peaks-init-hooks-decision.json) and re-runs of `workspace init` will\n' +
455
454
  'honour it. Re-run with --install-hooks=skip or --install-hooks=auto to override.\n\n' +
456
455
  'Install now? [Y/n]: ');
@@ -7,10 +7,11 @@ import { registerCoreAndArtifactCommands } from './commands/core-artifact-comman
7
7
  import { registerWorkflowCommands } from './commands/workflow-commands.js';
8
8
  import { registerCapabilityWorkerConfigAndSCCommands } from './commands/capability-worker-config-sc-commands.js';
9
9
  import { registerCodegraphCommands } from './commands/codegraph-commands.js';
10
- import { registerMcpCommands } from './commands/mcp-commands.js';
11
10
  import { registerOpenSpecCommands } from './commands/openspec-commands.js';
12
11
  import { registerPerfCommands } from './commands/perf-commands.js';
13
- import { registerProgressCommands } from './commands/progress-commands.js';
12
+ // Slice #014: peaks progress * CLI surface deleted (replaced by sub-agent
13
+ // dispatch + heartbeat, slice #009 + #010). Sub-agent progress is
14
+ // surfaced via `peaks sub-agent dispatch|heartbeat|share`.
14
15
  import { registerProjectCommands } from './commands/project-commands.js';
15
16
  import { registerRequestCommands } from './commands/request-commands.js';
16
17
  import { registerScanCommands } from './commands/scan-commands.js';
@@ -85,10 +86,8 @@ Run peaks (no arguments) for a quickstart. You likely want one of:
85
86
  registerWorkflowCommands(program, io);
86
87
  registerCapabilityWorkerConfigAndSCCommands(program, io);
87
88
  registerCodegraphCommands(program, io);
88
- registerMcpCommands(program, io);
89
89
  registerOpenSpecCommands(program, io);
90
90
  registerPerfCommands(program, io);
91
- registerProgressCommands(program, io);
92
91
  registerProjectCommands(program, io);
93
92
  registerRequestCommands(program, io);
94
93
  registerScanCommands(program, io);
@@ -1,6 +1,5 @@
1
1
  import { type RequestArtifactRole, type RequestArtifactSummary } from '../artifacts/request-artifact-service.js';
2
2
  import type { OpenSpecChangeSummary } from '../openspec/openspec-types.js';
3
- import type { McpScanReport } from '../mcp/mcp-types.js';
4
3
  import type { CapabilityItem } from '../recommendations/recommendation-types.js';
5
4
  import { type SkillPresence } from '../skills/skill-presence-service.js';
6
5
  export type ProjectDashboardRequests = {
@@ -19,10 +18,6 @@ export type ProjectDashboardUnderstand = {
19
18
  graphPath: string;
20
19
  parseError?: string;
21
20
  };
22
- export type ProjectDashboardMcp = {
23
- servers: McpScanReport['servers'];
24
- scopes: McpScanReport['scopes'];
25
- };
26
21
  export type ProjectDashboardDoctor = {
27
22
  ok: boolean;
28
23
  passed: number;
@@ -57,7 +52,6 @@ export type ProjectDashboardRunbookHealth = {
57
52
  };
58
53
  export type ProjectDashboardCapabilities = {
59
54
  count: number;
60
- mcpCount: number;
61
55
  sample: Array<Pick<CapabilityItem, 'capabilityId' | 'name' | 'itemType' | 'category'>>;
62
56
  };
63
57
  export type ProjectDashboardSkillPresence = {
@@ -76,7 +70,6 @@ export type ProjectDashboard = {
76
70
  requests: ProjectDashboardRequests;
77
71
  openspec: ProjectDashboardOpenSpec;
78
72
  understand: ProjectDashboardUnderstand;
79
- mcp: ProjectDashboardMcp;
80
73
  doctor: ProjectDashboardDoctor;
81
74
  runbookHealth: ProjectDashboardRunbookHealth;
82
75
  capabilities: ProjectDashboardCapabilities;
@@ -1,6 +1,5 @@
1
1
  import { listRequestArtifacts } from '../artifacts/request-artifact-service.js';
2
2
  import { scanOpenSpec } from '../openspec/openspec-scan-service.js';
3
- import { scanMcpServers } from '../mcp/mcp-scan-service.js';
4
3
  import { scanUnderstandAnything } from '../understand/understand-scan-service.js';
5
4
  import { seedCapabilityItems } from '../recommendations/capability-seed-items.js';
6
5
  import { requiredSkillNames } from '../../shared/paths.js';
@@ -78,7 +77,6 @@ function buildCapabilitiesSummary(sampleSize) {
78
77
  const items = seedCapabilityItems;
79
78
  return {
80
79
  count: items.length,
81
- mcpCount: items.filter((item) => item.itemType === 'mcp').length,
82
80
  sample: items.slice(0, sampleSize).map((item) => ({
83
81
  capabilityId: item.capabilityId,
84
82
  name: item.name,
@@ -109,10 +107,9 @@ export async function loadProjectDashboard(options) {
109
107
  const clock = options.clock ?? defaultClock;
110
108
  const sampleSize = options.sampleCapabilities ?? 8;
111
109
  const okPolicy = options.okPolicy ?? 'workspace-only';
112
- const [items, openspecReport, mcpReport, understandReport, doctorAndRunbook] = await Promise.all([
110
+ const [items, openspecReport, understandReport, doctorAndRunbook] = await Promise.all([
113
111
  listRequestArtifacts({ projectRoot: options.projectRoot }),
114
112
  scanOpenSpec({ openspecRoot: `${options.projectRoot}/openspec` }),
115
- scanMcpServers({ projectRoot: options.projectRoot }),
116
113
  scanUnderstandAnything({ projectRoot: options.projectRoot }),
117
114
  loadDoctorAndRunbookHealth(options.doctorReport, options.runbookHealth)
118
115
  ]);
@@ -142,10 +139,6 @@ export async function loadProjectDashboard(options) {
142
139
  graphPath: understandReport.graph.path,
143
140
  ...(understandReport.graph.parseError !== undefined ? { parseError: understandReport.graph.parseError } : {})
144
141
  },
145
- mcp: {
146
- servers: mcpReport.servers,
147
- scopes: mcpReport.scopes
148
- },
149
142
  doctor: doctorAndRunbook.doctor,
150
143
  runbookHealth: doctorAndRunbook.runbookHealth,
151
144
  capabilities: buildCapabilitiesSummary(sampleSize),
@@ -8,29 +8,29 @@
8
8
  * here, never leaked to SKILL.md.
9
9
  *
10
10
  * Why this exists:
11
- * - Prior SKILL.md hardcoded `Task(subagent_type="general-purpose", ...)`
12
- * which made peaks-cli depend on Claude Code's specific sub-agent
13
- * tool name. Adding a new IDE (Trae, future Cursor, etc.) required
14
- * editing every SKILL.md that mentioned sub-agent dispatch.
15
- * - This file (plus the per-IDE adapter wiring) collapses all
16
- * per-IDE sub-agent specifics to a single `SubAgentDispatcher`
17
- * instance per adapter. SKILL.md now only references
18
- * `peaks sub-agent dispatch <role>`, and the IDE-private tool
19
- * name flows through the returned `data.toolCall` at runtime.
11
+ * - Prior SKILL.md hardcoded `Task(subagent_type="general-purpose", ...)`
12
+ * which made peaks-cli depend on Claude Code's specific sub-agent
13
+ * tool name. Adding a new IDE (Trae, future Cursor, etc.) required
14
+ * editing every SKILL.md that mentioned sub-agent dispatch.
15
+ * - This file (plus the per-IDE adapter wiring) collapses all
16
+ * per-IDE sub-agent specifics to a single `SubAgentDispatcher`
17
+ * instance per adapter. SKILL.md now only references
18
+ * `peaks sub-agent dispatch <role>`, and the IDE-private tool
19
+ * name flows through the returned `data.toolCall` at runtime.
20
20
  *
21
21
  * Cross-reference: PRD #002 G1 (AC-1..AC-5); RD tech-doc-002 §2.
22
22
  */
23
23
  /**
24
24
  * Role string namespace. Soft whitelist — the CLI does NOT hard-validate
25
- * specific role names. Empirically observed (peaks-qa SKILL.md): 3 top
26
- * roles + 3 sub-roles + arbitrary business subdivisions:
25
+ * specific role names. Empirically observed (peaks-qa SKILL.md):3 top
26
+ * roles +3 sub-roles + arbitrary business subdivisions:
27
27
  *
28
- * - top: rd | qa | ui | txt | general-purpose
29
- * - qa sub-roles: qa-business | qa-perf | qa-security
30
- * - business细分: qa-business-regression | qa-business-api
31
- * | qa-business-frontend | ...
32
- * - promotable: prd-business | prd-technical | prd-ux |
33
- * ui-visual | ui-flow | ui-component | ...
28
+ * - top: rd | qa | ui | txt | general-purpose
29
+ * - qa sub-roles: qa-business | qa-perf | qa-security
30
+ * - business细分: qa-business-regression | qa-business-api
31
+ * | qa-business-frontend | ...
32
+ * - promotable: prd-business | prd-technical | prd-ux |
33
+ * ui-visual | ui-flow | ui-component | ...
34
34
  *
35
35
  * Any non-empty string is a valid role. CLI emits a "soft whitelist"
36
36
  * hint in --help but does not reject unknown values.
@@ -64,43 +64,48 @@ export interface SubAgentDispatchInput {
64
64
  */
65
65
  export interface SubAgentDispatcher {
66
66
  /**
67
- * Short label used in envelope `ide` field and CLI help text.
68
- * e.g. "claude-code" / "trae" / "null".
69
- */
67
+ * Short label used in envelope `ide` field and CLI help text.
68
+ * e.g. "claude-code" / "trae" / "null".
69
+ */
70
70
  readonly label: string;
71
71
  /**
72
- * Whether this dispatcher supports dispatching a given role.
73
- * claude-code returns true for all non-empty strings; trae is
74
- * byte-identical (UNVERIFIED pending real Trae dogfood);
75
- * null-dispatcher always returns false.
76
- */
72
+ * Whether this dispatcher supports dispatching a given role.
73
+ * claude-code returns true for all non-empty strings; trae is
74
+ * byte-identical (UNVERIFIED pending real Trae dogfood);
75
+ * null-dispatcher always returns false.
76
+ */
77
77
  supportsRole(role: SubAgentRole): boolean;
78
78
  /**
79
- * Build the IDE-specific tool call descriptor for a dispatch.
80
- * Must be pure: no I/O, no side effects. The CLI wraps the
81
- * returned descriptor in its JSON envelope.
82
- */
79
+ * Build the IDE-specific tool call descriptor for a dispatch.
80
+ * Must be pure: no I/O, no side effects. The CLI wraps the
81
+ * returned descriptor in its JSON envelope.
82
+ */
83
83
  buildToolCall(input: SubAgentDispatchInput): SubAgentToolCall;
84
84
  }
85
85
  /**
86
86
  * Claude Code dispatcher. Real, byte-level implementation.
87
87
  *
88
- * - `supportsRole`: any non-empty string (Claude Code's
89
- * `general-purpose` sub-agent accepts any prompt).
90
- * - `buildToolCall`: returns `{name: 'Task', args: {subagent_type,
91
- * description, prompt}}` — the exact shape the `Task` tool
92
- * in Claude Code expects.
88
+ * - `supportsRole`: any non-empty string (Claude Code's
89
+ * `general-purpose` sub-agent accepts any prompt).
90
+ * - `buildToolCall`: returns `{name: 'Task', args: {subagent_type,
91
+ * description, prompt}}` — the exact shape the `Task` tool
92
+ * in Claude Code expects.
93
93
  */
94
94
  export declare const claudeCodeSubAgentDispatcher: SubAgentDispatcher;
95
95
  /**
96
96
  * Trae dispatcher. UNVERIFIED — Trae sub-agent tool name TBD on real
97
97
  * dogfood. Byte-level identical to claude-code by design so:
98
- * 1. The slice #008 `subAgentToolMatcher: 'Task'` install entry
99
- * stays byte-stable (the generated `.trae/settings.json` does
100
- * not change).
101
- * 2. The dispatcher's return shape is uniform across both
102
- * adapters a single byte-equality test can verify the
103
- * placeholder contract.
98
+ * - The dispatcher's return shape is uniform across both adapters
99
+ * — a single byte-equality test can verify the placeholder
100
+ * contract.
101
+ * - Future real Trae dogfood can replace the body of
102
+ * `buildToolCall` without breaking the adapter contract.
103
+ *
104
+ * Slice #014: the legacy `subAgentToolMatcher: 'Task'` install entry
105
+ * is gone — the field is removed from `IdeAdapter`. Slice #009+
106
+ * dispatched sub-agents directly, not via a PreToolUse hook. The Trae
107
+ * dispatcher remains a placeholder so the dispatch surface is uniform
108
+ * across adapters.
104
109
  *
105
110
  * When real Trae dogfood lands, replace the body of `buildToolCall`
106
111
  * with Trae's actual sub-agent tool name + args shape. The interface
@@ -8,26 +8,26 @@
8
8
  * here, never leaked to SKILL.md.
9
9
  *
10
10
  * Why this exists:
11
- * - Prior SKILL.md hardcoded `Task(subagent_type="general-purpose", ...)`
12
- * which made peaks-cli depend on Claude Code's specific sub-agent
13
- * tool name. Adding a new IDE (Trae, future Cursor, etc.) required
14
- * editing every SKILL.md that mentioned sub-agent dispatch.
15
- * - This file (plus the per-IDE adapter wiring) collapses all
16
- * per-IDE sub-agent specifics to a single `SubAgentDispatcher`
17
- * instance per adapter. SKILL.md now only references
18
- * `peaks sub-agent dispatch <role>`, and the IDE-private tool
19
- * name flows through the returned `data.toolCall` at runtime.
11
+ * - Prior SKILL.md hardcoded `Task(subagent_type="general-purpose", ...)`
12
+ * which made peaks-cli depend on Claude Code's specific sub-agent
13
+ * tool name. Adding a new IDE (Trae, future Cursor, etc.) required
14
+ * editing every SKILL.md that mentioned sub-agent dispatch.
15
+ * - This file (plus the per-IDE adapter wiring) collapses all
16
+ * per-IDE sub-agent specifics to a single `SubAgentDispatcher`
17
+ * instance per adapter. SKILL.md now only references
18
+ * `peaks sub-agent dispatch <role>`, and the IDE-private tool
19
+ * name flows through the returned `data.toolCall` at runtime.
20
20
  *
21
21
  * Cross-reference: PRD #002 G1 (AC-1..AC-5); RD tech-doc-002 §2.
22
22
  */
23
23
  /**
24
24
  * Claude Code dispatcher. Real, byte-level implementation.
25
25
  *
26
- * - `supportsRole`: any non-empty string (Claude Code's
27
- * `general-purpose` sub-agent accepts any prompt).
28
- * - `buildToolCall`: returns `{name: 'Task', args: {subagent_type,
29
- * description, prompt}}` — the exact shape the `Task` tool
30
- * in Claude Code expects.
26
+ * - `supportsRole`: any non-empty string (Claude Code's
27
+ * `general-purpose` sub-agent accepts any prompt).
28
+ * - `buildToolCall`: returns `{name: 'Task', args: {subagent_type,
29
+ * description, prompt}}` — the exact shape the `Task` tool
30
+ * in Claude Code expects.
31
31
  */
32
32
  export const claudeCodeSubAgentDispatcher = {
33
33
  label: 'claude-code',
@@ -44,12 +44,17 @@ export const claudeCodeSubAgentDispatcher = {
44
44
  /**
45
45
  * Trae dispatcher. UNVERIFIED — Trae sub-agent tool name TBD on real
46
46
  * dogfood. Byte-level identical to claude-code by design so:
47
- * 1. The slice #008 `subAgentToolMatcher: 'Task'` install entry
48
- * stays byte-stable (the generated `.trae/settings.json` does
49
- * not change).
50
- * 2. The dispatcher's return shape is uniform across both
51
- * adapters a single byte-equality test can verify the
52
- * placeholder contract.
47
+ * - The dispatcher's return shape is uniform across both adapters
48
+ * — a single byte-equality test can verify the placeholder
49
+ * contract.
50
+ * - Future real Trae dogfood can replace the body of
51
+ * `buildToolCall` without breaking the adapter contract.
52
+ *
53
+ * Slice #014: the legacy `subAgentToolMatcher: 'Task'` install entry
54
+ * is gone — the field is removed from `IdeAdapter`. Slice #009+
55
+ * dispatched sub-agents directly, not via a PreToolUse hook. The Trae
56
+ * dispatcher remains a placeholder so the dispatch surface is uniform
57
+ * across adapters.
53
58
  *
54
59
  * When real Trae dogfood lands, replace the body of `buildToolCall`
55
60
  * with Trae's actual sub-agent tool name + args shape. The interface
@@ -32,7 +32,6 @@ export const CLAUDE_CODE_ADAPTER = {
32
32
  envVar: 'CLAUDE_PROJECT_DIR',
33
33
  hookEvent: 'PreToolUse',
34
34
  toolMatcher: 'Bash',
35
- subAgentToolMatcher: 'Task',
36
35
  // Slice #009: Claude Code uses the `Task` tool for sub-agent dispatch.
37
36
  // The CLI calls `claudeCodeSubAgentDispatcher.buildToolCall` to construct
38
37
  // the exact args shape the `Task` tool expects.
@@ -46,9 +45,7 @@ export const CLAUDE_CODE_ADAPTER = {
46
45
  ],
47
46
  capabilities: {
48
47
  gateEnforce: true,
49
- progressStart: true,
50
48
  statusline: true,
51
- mcpInstall: true,
52
49
  },
53
50
  // Slice #011: standards profile. Claude Code reads its constitution at
54
51
  // CLAUDE.md + module-level rules under .claude/rules/**. The values mirror
@@ -56,11 +56,10 @@ export const TRAE_ADAPTER = {
56
56
  envVar: 'TRAE_PROJECT_DIR',
57
57
  hookEvent: 'beforeToolCall', // VERIFIED against Trae 1.x fixture — slice 009-009-2026-06-07-trae-dogfood (2026-06-07); fixture at tests/fixtures/trae/trae-1x-payload.json
58
58
  toolMatcher: 'terminal', // VERIFIED against Trae 1.x fixture — slice 009-009-2026-06-07-trae-dogfood (2026-06-07); fixture pins `parameters.tool: 'terminal'`
59
- subAgentToolMatcher: 'Task', // UNVERIFIED — Trae's sub-agent tool name is unknown; matches the prior hardcoded 'Task' literal so byte-level install output is unchanged. Will be dogfooded when a real Trae 1.x install dispatches a sub-agent.
60
59
  // Slice #009: Trae's sub-agent dispatcher is UNVERIFIED — Trae sub-agent
61
60
  // tool name TBD on real dogfood; byte-level identical to claude-code by
62
- // design so the slice #008 `subAgentToolMatcher: 'Task'` install entry
63
- // stays byte-stable. Awaiting real Trae 1.x dogfood to confirm/replace.
61
+ // design so the dispatcher shape is uniform across both adapters. Awaiting
62
+ // real Trae 1.x dogfood to confirm/replace.
64
63
  subAgentDispatcher: traeSubAgentDispatcher,
65
64
  // Slice #010 G9: Trae supports `beforeToolCall` which can wrap
66
65
  // `peaks sub-agent-dispatch-guard`. Opt in (matches the byte-stable
@@ -71,21 +70,7 @@ export const TRAE_ADAPTER = {
71
70
  ],
72
71
  capabilities: {
73
72
  gateEnforce: true,
74
- progressStart: true,
75
73
  statusline: true,
76
- // Slice #007-007-2026-06-07-mcp-decouple: mcpInstall is LOAD-BEARING.
77
- // The 4 MCP capabilities (playwright, chrome-devtools, figma, context7)
78
- // are installed via `peaks mcp plan/apply` which writes to the global
79
- // `~/.claude/settings.json` file. Trae 1.x's MCP integration is
80
- // UNVERIFIED (the Trae fixture did not dogfood the MCP install path),
81
- // so the 6 SKILL.md files must surface a Trae-specific path (manual
82
- // install + manual tool invocation) rather than promising `peaks mcp
83
- // apply` will work on Trae. Skill bodies consume this flag through
84
- // the IDE adapter's `capabilities.mcpInstall`; setting it to true
85
- // without a real Trae MCP install dogfood would be a regression.
86
- // Cross-reference: .peaks/memory/trae-adapter-sets-mcpinstall-false-trae-mcp-integration-is-unverified.md
87
- // and the 4 per-capability memos under .peaks/memory/mcp-decouple-*.md.
88
- mcpInstall: false
89
74
  }
90
75
  // Standards: UNVERIFIED — see slice #012+ (Trae real-install dogfood for
91
76
  // the `standardsProfile` and `skillInstall` fields). The slice #011
@@ -16,12 +16,8 @@ export type IdeId = 'claude-code' | 'trae' | 'codex' | 'cursor' | 'qoder' | 'ton
16
16
  export interface IdeCapabilities {
17
17
  /** peaks gate enforce 是否适用该 IDE(必备) */
18
18
  readonly gateEnforce: true;
19
- /** peaks progress start(sub-agent 派发)是否适用 */
20
- readonly progressStart: boolean;
21
19
  /** peaks statusline 状态栏是否适用 */
22
20
  readonly statusline: boolean;
23
- /** peaks mcp install 是否适用 */
24
- readonly mcpInstall: boolean;
25
21
  }
26
22
  export interface IdeSettingsLocation {
27
23
  /** 项目根下的 settings 目录名,例如 '.claude' / '.trae' / '.cursor' */
@@ -48,23 +44,10 @@ export interface IdeAdapter {
48
44
  readonly hookEvent: string;
49
45
  /** hook 数组元素的 matcher 字段(工具名匹配),例如 'Bash' / 'Task' / 'terminal' */
50
46
  readonly toolMatcher: string;
51
- /**
52
- * The tool name used by this IDE to invoke a sub-agent (e.g. Claude Code
53
- * uses 'Task' to dispatch a sub-agent, Trae may use a different name).
54
- * Consumed by the `peaks progress start` hook entry so each IDE self-
55
- * reports its sub-agent tool name. Additive on `toolMatcher`: the
56
- * `toolMatcher` field still drives the gate-enforce hook entry, this
57
- * one drives the sub-agent-progress hook entry.
58
- *
59
- * Added in slice 2026-06-06-sub-agent-spawn-bug-and-decouple.
60
- */
61
- readonly subAgentToolMatcher: string;
62
47
  /**
63
48
  * Per-IDE sub-agent dispatcher. The `peaks sub-agent dispatch` CLI reads
64
49
  * this field, calls `supportsRole` + `buildToolCall`, and returns the
65
- * resulting tool-call descriptor in the JSON envelope. Additive on
66
- * `subAgentToolMatcher`: the matcher still drives the gate-enforce hook
67
- * entry; this field drives the runtime sub-agent dispatch surface.
50
+ * resulting tool-call descriptor in the JSON envelope. Encapsulates the per-IDE sub-agent dispatch surface (slice #009). The dispatcher's `buildToolCall` returns the IDE-native tool-call descriptor at runtime.
68
51
  *
69
52
  * Added in slice 2026-06-07-sub-agent-dispatch-decouple. See PRD #002
70
53
  * G1 (AC-1, AC-2) + [[slim-ideadapter-shape-is-the-contract]].