brainclaw 0.28.0 → 1.5.3

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 (198) hide show
  1. package/README.md +193 -170
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/cli.js +683 -23
  4. package/dist/commands/accept.js +3 -0
  5. package/dist/commands/add-step.js +11 -26
  6. package/dist/commands/agent-board.js +70 -3
  7. package/dist/commands/audit.js +19 -0
  8. package/dist/commands/check-policy.js +54 -0
  9. package/dist/commands/check-security-mcp.js +145 -0
  10. package/dist/commands/check-security.js +106 -0
  11. package/dist/commands/claim-resource.js +1 -0
  12. package/dist/commands/codev.js +672 -0
  13. package/dist/commands/compact.js +74 -0
  14. package/dist/commands/complete-step.js +16 -26
  15. package/dist/commands/constraint.js +8 -20
  16. package/dist/commands/decision.js +9 -20
  17. package/dist/commands/delete-plan.js +10 -12
  18. package/dist/commands/delete-step.js +16 -0
  19. package/dist/commands/dispatch.js +163 -0
  20. package/dist/commands/doctor.js +1122 -49
  21. package/dist/commands/enable-agent.js +1 -0
  22. package/dist/commands/export.js +280 -22
  23. package/dist/commands/handoff.js +33 -0
  24. package/dist/commands/harvest.js +189 -0
  25. package/dist/commands/hooks.js +82 -25
  26. package/dist/commands/inbox.js +169 -0
  27. package/dist/commands/init.js +38 -31
  28. package/dist/commands/install-hooks.js +71 -44
  29. package/dist/commands/link.js +89 -0
  30. package/dist/commands/list-claims.js +48 -3
  31. package/dist/commands/list-plans.js +129 -25
  32. package/dist/commands/loops-handlers.js +409 -0
  33. package/dist/commands/mcp-read-handlers.js +1628 -0
  34. package/dist/commands/mcp-schemas.generated.js +74 -0
  35. package/dist/commands/mcp.js +4244 -1475
  36. package/dist/commands/plan-resource.js +64 -0
  37. package/dist/commands/plan.js +12 -26
  38. package/dist/commands/prune.js +37 -2
  39. package/dist/commands/reflect.js +20 -7
  40. package/dist/commands/release-claim.js +11 -6
  41. package/dist/commands/release-notes.js +170 -0
  42. package/dist/commands/repair.js +210 -0
  43. package/dist/commands/run-profile.js +57 -0
  44. package/dist/commands/sequence.js +113 -0
  45. package/dist/commands/session-end.js +423 -14
  46. package/dist/commands/session-start.js +214 -41
  47. package/dist/commands/setup-security.js +103 -0
  48. package/dist/commands/setup.js +42 -4
  49. package/dist/commands/stale.js +109 -0
  50. package/dist/commands/switch.js +131 -10
  51. package/dist/commands/trap.js +14 -31
  52. package/dist/commands/update-handoff.js +63 -4
  53. package/dist/commands/update-plan.js +21 -28
  54. package/dist/commands/update-step.js +37 -0
  55. package/dist/commands/upgrade.js +313 -6
  56. package/dist/commands/usage.js +102 -0
  57. package/dist/commands/version.js +20 -0
  58. package/dist/commands/who.js +124 -0
  59. package/dist/commands/worktree.js +105 -0
  60. package/dist/core/actions.js +315 -0
  61. package/dist/core/agent-capability.js +610 -17
  62. package/dist/core/agent-context.js +7 -1
  63. package/dist/core/agent-files.js +1169 -85
  64. package/dist/core/agent-integrations.js +160 -5
  65. package/dist/core/agent-inventory.js +2 -0
  66. package/dist/core/agent-profiles.js +93 -0
  67. package/dist/core/agent-registry.js +162 -30
  68. package/dist/core/agentrun-reconciler.js +345 -0
  69. package/dist/core/agentruns.js +424 -0
  70. package/dist/core/ai-agent-detection.js +31 -10
  71. package/dist/core/archival.js +77 -0
  72. package/dist/core/assignment-sweeper.js +82 -0
  73. package/dist/core/assignments.js +367 -0
  74. package/dist/core/audit.js +30 -0
  75. package/dist/core/bootstrap.js +61 -10
  76. package/dist/core/brainclaw-version.js +94 -2
  77. package/dist/core/candidates.js +93 -2
  78. package/dist/core/claims.js +419 -0
  79. package/dist/core/codev-metrics.js +77 -0
  80. package/dist/core/codev-personas.js +31 -0
  81. package/dist/core/codev-plan-gen.js +35 -0
  82. package/dist/core/codev-prompts.js +74 -0
  83. package/dist/core/codev-responses.js +62 -0
  84. package/dist/core/codev-rounds.js +218 -0
  85. package/dist/core/config.js +4 -0
  86. package/dist/core/context.js +454 -34
  87. package/dist/core/coordination.js +201 -6
  88. package/dist/core/cross-project.js +230 -16
  89. package/dist/core/default-profiles/doctor.yaml +11 -0
  90. package/dist/core/default-profiles/janitor.yaml +11 -0
  91. package/dist/core/default-profiles/onboarder.yaml +11 -0
  92. package/dist/core/default-profiles/reviewer.yaml +13 -0
  93. package/dist/core/dispatcher.js +1189 -0
  94. package/dist/core/duplicates.js +2 -2
  95. package/dist/core/entity-operations.js +450 -0
  96. package/dist/core/entity-registry.js +344 -0
  97. package/dist/core/event-log.js +1 -0
  98. package/dist/core/events.js +106 -2
  99. package/dist/core/execution-adapters.js +154 -0
  100. package/dist/core/execution-context.js +63 -0
  101. package/dist/core/execution-profile.js +270 -0
  102. package/dist/core/execution.js +255 -0
  103. package/dist/core/facade-schema.js +81 -0
  104. package/dist/core/federation-cloud.js +99 -0
  105. package/dist/core/federation-message.js +52 -0
  106. package/dist/core/federation-transport.js +65 -0
  107. package/dist/core/gc-semantic.js +482 -0
  108. package/dist/core/governance.js +247 -0
  109. package/dist/core/guards.js +19 -0
  110. package/dist/core/ideation.js +72 -0
  111. package/dist/core/identity.js +252 -28
  112. package/dist/core/ids.js +6 -0
  113. package/dist/core/input-validation.js +2 -2
  114. package/dist/core/instruction-templates.js +344 -136
  115. package/dist/core/io.js +90 -11
  116. package/dist/core/lock.js +6 -2
  117. package/dist/core/loops/brief-assembly.js +213 -0
  118. package/dist/core/loops/facade-schema.js +148 -0
  119. package/dist/core/loops/index.js +7 -0
  120. package/dist/core/loops/iteration-engine.js +139 -0
  121. package/dist/core/loops/lock.js +385 -0
  122. package/dist/core/loops/store.js +201 -0
  123. package/dist/core/loops/types.js +403 -0
  124. package/dist/core/loops/verbs.js +534 -0
  125. package/dist/core/markdown.js +15 -3
  126. package/dist/core/memory-compactor.js +432 -0
  127. package/dist/core/memory-git.js +152 -8
  128. package/dist/core/messaging.js +278 -0
  129. package/dist/core/migration.js +32 -1
  130. package/dist/core/mutation-pipeline.js +4 -2
  131. package/dist/core/operations/memory-mutation.js +129 -0
  132. package/dist/core/operations/memory-write.js +78 -0
  133. package/dist/core/operations/plan.js +190 -0
  134. package/dist/core/policy.js +169 -0
  135. package/dist/core/repo-analysis.js +67 -0
  136. package/dist/core/reputation.js +9 -3
  137. package/dist/core/schema.js +546 -21
  138. package/dist/core/search.js +21 -2
  139. package/dist/core/security-cache.js +71 -0
  140. package/dist/core/security-guard.js +152 -0
  141. package/dist/core/security-scoring.js +86 -0
  142. package/dist/core/sequence.js +130 -0
  143. package/dist/core/socket-client.js +113 -0
  144. package/dist/core/staleness.js +246 -0
  145. package/dist/core/state.js +98 -22
  146. package/dist/core/store-resolution.js +54 -12
  147. package/dist/core/toml-writer.js +76 -0
  148. package/dist/core/upgrades/backup.js +232 -0
  149. package/dist/core/upgrades/health-check.js +169 -0
  150. package/dist/core/upgrades/patches/candidate-archive.js +145 -0
  151. package/dist/core/upgrades/patches/handoff-review-strip.js +128 -0
  152. package/dist/core/upgrades/patches/provenance-rollout.js +136 -0
  153. package/dist/core/upgrades/schema-version.js +97 -0
  154. package/dist/core/worktree.js +606 -0
  155. package/dist/facts.js +114 -0
  156. package/dist/facts.json +111 -0
  157. package/docs/architecture/project-refs.md +5 -1
  158. package/docs/cli.md +690 -43
  159. package/docs/concepts/ideation-loop.md +317 -0
  160. package/docs/concepts/loop-engine.md +456 -0
  161. package/docs/concepts/mcp-governance.md +268 -0
  162. package/docs/concepts/memory-staleness.md +122 -0
  163. package/docs/concepts/multi-agent-workflows.md +166 -0
  164. package/docs/concepts/plans-and-claims.md +31 -6
  165. package/docs/concepts/project-md-convention.md +35 -0
  166. package/docs/concepts/troubleshooting.md +220 -0
  167. package/docs/concepts/upgrade-cli.md +202 -0
  168. package/docs/concepts/upgrade-dogfood-procedure.md +114 -0
  169. package/docs/context-format-changelog.md +2 -2
  170. package/docs/context-format.md +2 -2
  171. package/docs/index.md +68 -0
  172. package/docs/integrations/agents.md +15 -16
  173. package/docs/integrations/cline.md +88 -0
  174. package/docs/integrations/codex.md +75 -23
  175. package/docs/integrations/continue.md +60 -0
  176. package/docs/integrations/copilot.md +67 -9
  177. package/docs/integrations/kilocode.md +72 -0
  178. package/docs/integrations/mcp.md +304 -21
  179. package/docs/integrations/mistral-vibe.md +122 -0
  180. package/docs/integrations/opencode.md +84 -0
  181. package/docs/integrations/overview.md +23 -8
  182. package/docs/integrations/roo.md +74 -0
  183. package/docs/integrations/windsurf.md +83 -0
  184. package/docs/mcp-schema-changelog.md +191 -1
  185. package/docs/playbooks/integration/index.md +121 -0
  186. package/docs/playbooks/productivity/index.md +102 -0
  187. package/docs/playbooks/team/index.md +122 -0
  188. package/docs/product/agent-first-model.md +184 -0
  189. package/docs/product/entity-model-audit.md +462 -0
  190. package/docs/quickstart-existing-project.md +135 -0
  191. package/docs/quickstart.md +124 -37
  192. package/docs/release-maintenance.md +79 -0
  193. package/docs/review.md +2 -0
  194. package/docs/server-operations.md +118 -0
  195. package/package.json +20 -12
  196. package/dist/commands/claude-desktop-extension.js +0 -18
  197. package/dist/commands/diff.js +0 -99
  198. package/dist/core/claude-desktop-extension.js +0 -224
@@ -3,7 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { spawnSync } from 'node:child_process';
5
5
  import { fileURLToPath } from 'node:url';
6
- import { BrainclawLocalReleaseManifestSchema, } from './schema.js';
6
+ import { AgentReleaseNotesSchema, BrainclawLocalReleaseManifestSchema, } from './schema.js';
7
7
  export const DEFAULT_LOCAL_RELEASES_DIR = '.releases';
8
8
  export const DEFAULT_LOCAL_RELEASE_MANIFEST_PATH = `${DEFAULT_LOCAL_RELEASES_DIR}/brainclaw-local.json`;
9
9
  export const DEFAULT_NPM_UPDATE_PACKAGE = 'brainclaw';
@@ -15,7 +15,75 @@ const DEFAULT_NPM_UPDATE_SOURCE = {
15
15
  package_name: DEFAULT_NPM_UPDATE_PACKAGE,
16
16
  dist_tag: DEFAULT_NPM_UPDATE_DIST_TAG,
17
17
  };
18
+ /**
19
+ * Scan PATH for all brainclaw installations and their versions.
20
+ * Detects when multiple versions are installed (e.g. global + user-local)
21
+ * which causes confusion about which version is actually running.
22
+ */
23
+ export function detectConcurrentInstallations() {
24
+ const currentVersion = getInstalledBrainclawVersion();
25
+ const installations = [];
26
+ const seen = new Set();
27
+ // On Windows, `where` returns all matches. On Unix, `which -a` does.
28
+ const isWindows = os.platform() === 'win32';
29
+ const result = isWindows
30
+ ? spawnSync('where', ['brainclaw'], { encoding: 'utf-8', timeout: 5000 })
31
+ : spawnSync('which', ['-a', 'brainclaw'], { encoding: 'utf-8', timeout: 5000 });
32
+ if (result.status !== 0)
33
+ return [];
34
+ const paths = result.stdout.split(/\r?\n/).map(l => l.trim()).filter(Boolean);
35
+ for (const binPath of paths) {
36
+ // Normalize to avoid duplicates from symlinks
37
+ let realPath;
38
+ try {
39
+ realPath = isWindows ? binPath : fs.realpathSync(binPath);
40
+ }
41
+ catch {
42
+ realPath = binPath;
43
+ }
44
+ if (seen.has(realPath))
45
+ continue;
46
+ seen.add(realPath);
47
+ // Get version by running the binary
48
+ let version = 'unknown';
49
+ try {
50
+ const vResult = spawnSync(binPath, ['--version'], { encoding: 'utf-8', timeout: 5000 });
51
+ if (vResult.status === 0) {
52
+ version = vResult.stdout.trim().split(/\r?\n/)[0]?.trim() ?? 'unknown';
53
+ }
54
+ }
55
+ catch { /* ignore */ }
56
+ installations.push({
57
+ path: binPath,
58
+ version,
59
+ isCurrent: version === currentVersion,
60
+ });
61
+ }
62
+ return installations;
63
+ }
18
64
  let cachedCliVersion;
65
+ let cachedPackageJsonPath;
66
+ /**
67
+ * Read the brainclaw version from disk (package.json), bypassing the in-memory cache.
68
+ * Used by the MCP server to detect when a new version has been installed while the
69
+ * long-running MCP process is still running with old code.
70
+ */
71
+ export function readDiskBrainclawVersion() {
72
+ if (cachedPackageJsonPath === undefined) {
73
+ cachedPackageJsonPath = findOwnPackageJson() ?? '';
74
+ }
75
+ if (!cachedPackageJsonPath)
76
+ return '0.0.0';
77
+ try {
78
+ const parsed = JSON.parse(fs.readFileSync(cachedPackageJsonPath, 'utf-8'));
79
+ return typeof parsed.version === 'string' && parsed.version.trim().length > 0
80
+ ? parsed.version.trim()
81
+ : '0.0.0';
82
+ }
83
+ catch {
84
+ return '0.0.0';
85
+ }
86
+ }
19
87
  export function getInstalledBrainclawVersion() {
20
88
  if (cachedCliVersion) {
21
89
  return cachedCliVersion;
@@ -126,7 +194,23 @@ export function renderBrainclawInstallableUpdateNotice(updateCheck) {
126
194
  if (updateCheck.install_command) {
127
195
  lines.push(`Install: ${updateCheck.install_command}`);
128
196
  }
129
- if (updateCheck.release_notes) {
197
+ const arn = updateCheck.agent_release_notes;
198
+ if (arn) {
199
+ lines.push(`Summary: ${arn.summary}`);
200
+ if (arn.breaking_risk && arn.breaking_risk !== 'none') {
201
+ lines.push(`Breaking risk: ${arn.breaking_risk}`);
202
+ }
203
+ if (arn.highlights && arn.highlights.length > 0) {
204
+ lines.push('Highlights:');
205
+ for (const h of arn.highlights) {
206
+ lines.push(` • ${h}`);
207
+ }
208
+ }
209
+ if (arn.action_recommendation) {
210
+ lines.push(`Action: ${arn.action_recommendation}`);
211
+ }
212
+ }
213
+ else if (updateCheck.release_notes) {
130
214
  lines.push(`Why update: ${updateCheck.release_notes}`);
131
215
  }
132
216
  return lines.join('\n');
@@ -161,6 +245,9 @@ export function publishLocalBrainclawRelease(cwd, options = {}) {
161
245
  const projectManifestPath = toPortablePath(path.relative(cwd, manifestPath));
162
246
  const installCommand = `npm install -g "${projectArtifactPath}"`;
163
247
  const releaseNotes = options.releaseNotes?.trim() || null;
248
+ const agentReleaseNotes = options.agentReleaseNotes
249
+ ? AgentReleaseNotesSchema.parse(options.agentReleaseNotes)
250
+ : null;
164
251
  const manifest = BrainclawLocalReleaseManifestSchema.parse({
165
252
  version: 1,
166
253
  channel: 'local-pack',
@@ -170,6 +257,7 @@ export function publishLocalBrainclawRelease(cwd, options = {}) {
170
257
  artifact_path: manifestArtifactPath,
171
258
  install_command: installCommand,
172
259
  release_notes: releaseNotes ?? undefined,
260
+ agent_release_notes: agentReleaseNotes ?? undefined,
173
261
  });
174
262
  fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf-8');
175
263
  return {
@@ -179,6 +267,7 @@ export function publishLocalBrainclawRelease(cwd, options = {}) {
179
267
  artifact_path: projectArtifactPath,
180
268
  install_command: installCommand,
181
269
  release_notes: releaseNotes,
270
+ agent_release_notes: agentReleaseNotes,
182
271
  };
183
272
  }
184
273
  function checkNpmInstallableUpdate(source, config, cwd, options, defaultSource) {
@@ -343,6 +432,7 @@ function checkLocalPackInstallableUpdate(manifestPath, config, cwd) {
343
432
  const installCommand = manifest.install_command?.trim()
344
433
  || (artifactPath ? `npm install -g "${artifactPath}"` : config?.brainclaw_upgrade_command?.trim() || null);
345
434
  const releaseNotes = manifest.release_notes?.trim() || config?.brainclaw_upgrade_message?.trim() || null;
435
+ const agentReleaseNotes = manifest.agent_release_notes ?? null;
346
436
  const installedVersion = getInstalledBrainclawVersion();
347
437
  if (compareVersions(installedVersion, latestVersion) < 0) {
348
438
  return {
@@ -353,6 +443,7 @@ function checkLocalPackInstallableUpdate(manifestPath, config, cwd) {
353
443
  artifact_path: artifactPath,
354
444
  install_command: installCommand,
355
445
  release_notes: releaseNotes,
446
+ agent_release_notes: agentReleaseNotes,
356
447
  status: 'update_available',
357
448
  message: `A newer installable brainclaw build is available: ${latestVersion} (installed ${installedVersion}).`,
358
449
  default_source: false,
@@ -366,6 +457,7 @@ function checkLocalPackInstallableUpdate(manifestPath, config, cwd) {
366
457
  artifact_path: artifactPath,
367
458
  install_command: installCommand,
368
459
  release_notes: releaseNotes,
460
+ agent_release_notes: agentReleaseNotes,
369
461
  status: 'up_to_date',
370
462
  message: `Installed brainclaw ${installedVersion} is up to date for the configured local-pack channel.`,
371
463
  default_source: false,
@@ -6,6 +6,39 @@ import { resolveEntityDir } from './io.js';
6
6
  import { mutate } from './mutation-pipeline.js';
7
7
  import { nowISO, getNextShortLabel } from './ids.js';
8
8
  import { JsonStore } from './json-store.js';
9
+ import { refreshLiveCompanions } from '../commands/export.js';
10
+ /**
11
+ * Return the effective source for a candidate.
12
+ *
13
+ * Resolution order:
14
+ * 1. Explicit `source` field if set to a valid enum value ('auto'|'agent'|'human').
15
+ * 2. Inferred from `origin` free-text pattern (e.g. 'runtime-note:...' → 'agent',
16
+ * 'session-end:...' → 'auto', 'mcp:...' / 'cross-project:...' → 'agent').
17
+ * 3. Default 'human' for legacy items without any provenance.
18
+ *
19
+ * This default is only applied in memory — no files are rewritten.
20
+ */
21
+ export function resolvedSource(candidate) {
22
+ if (candidate.source)
23
+ return candidate.source;
24
+ return inferSourceFromOrigin(candidate.origin);
25
+ }
26
+ /** Infer the enum `source` from a free-text `origin` pattern. */
27
+ export function inferSourceFromOrigin(origin) {
28
+ if (!origin)
29
+ return 'human';
30
+ if (origin.startsWith('session-end:'))
31
+ return 'auto';
32
+ if (origin.startsWith('runtime-note:'))
33
+ return 'agent';
34
+ if (origin.startsWith('mcp:'))
35
+ return 'agent';
36
+ if (origin.startsWith('cross-project:'))
37
+ return 'agent';
38
+ // Unknown origin pattern — treat as agent since something explicit was set,
39
+ // but not matching an auto pattern. Human sources typically have no origin.
40
+ return 'agent';
41
+ }
9
42
  function inboxDir(cwd, mode = 'read') {
10
43
  return resolveEntityDir('inbox', cwd ?? process.cwd(), mode);
11
44
  }
@@ -39,6 +72,11 @@ export function saveCandidate(candidate, cwd) {
39
72
  mutate({ cwd }, () => {
40
73
  ensureInboxDirs(cwd);
41
74
  candidateStore('pending', cwd).save(CandidateSchema.parse(candidate));
75
+ // Auto-refresh live companions after candidate changes (non-fatal)
76
+ try {
77
+ refreshLiveCompanions(cwd);
78
+ }
79
+ catch { /* best-effort */ }
42
80
  });
43
81
  }
44
82
  export function loadCandidate(id, cwd) {
@@ -47,15 +85,36 @@ export function loadCandidate(id, cwd) {
47
85
  export function updateCandidate(candidate, cwd) {
48
86
  saveCandidate(candidate, cwd);
49
87
  }
50
- export function listCandidates(status, cwd) {
88
+ export function listCandidates(status, cwd, filter) {
51
89
  const candidates = candidateStore('pending', cwd).list();
52
- return status ? candidates.filter((candidate) => candidate.status === status) : candidates;
90
+ const byStatus = status ? candidates.filter((candidate) => candidate.status === status) : candidates;
91
+ return applySourceFilter(byStatus, filter);
92
+ }
93
+ function applySourceFilter(candidates, filter) {
94
+ if (!filter)
95
+ return candidates;
96
+ let result = candidates;
97
+ if (filter.source !== undefined) {
98
+ result = result.filter((c) => resolvedSource(c) === filter.source);
99
+ }
100
+ if (filter.auto_generated === false) {
101
+ result = result.filter((c) => resolvedSource(c) !== 'auto');
102
+ }
103
+ else if (filter.auto_generated === true) {
104
+ result = result.filter((c) => resolvedSource(c) === 'auto');
105
+ }
106
+ return result;
53
107
  }
54
108
  export function archiveCandidate(candidate, dest, cwd) {
55
109
  mutate({ cwd }, () => {
56
110
  ensureInboxDirs(cwd);
57
111
  candidateStore(dest, cwd).save(CandidateSchema.parse(candidate));
58
112
  candidateStore('pending', cwd).delete(candidate.id);
113
+ // Auto-refresh live companions after candidate archive (non-fatal)
114
+ try {
115
+ refreshLiveCompanions(cwd);
116
+ }
117
+ catch { /* best-effort */ }
59
118
  });
60
119
  }
61
120
  export function listArchivedCandidates(dest, cwd) {
@@ -70,6 +129,38 @@ export function deleteArchivedCandidate(id, dest, cwd) {
70
129
  }
71
130
  return false;
72
131
  }
132
+ export function cleanupStaleCandidates(options = {}) {
133
+ const maxAgeDays = options.maxAgeDays ?? 30;
134
+ const source = options.source ?? 'auto';
135
+ const cutoffMs = Date.now() - maxAgeDays * 86_400_000;
136
+ const candidates = listCandidates('pending', options.cwd).filter((candidate) => {
137
+ if (resolvedSource(candidate) !== source)
138
+ return false;
139
+ return Date.parse(candidate.created_at) <= cutoffMs;
140
+ });
141
+ if (options.dryRun || candidates.length === 0) {
142
+ return {
143
+ matched: candidates.length,
144
+ deleted: 0,
145
+ candidates,
146
+ };
147
+ }
148
+ mutate({ cwd: options.cwd }, () => {
149
+ const store = candidateStore('pending', options.cwd);
150
+ for (const candidate of candidates) {
151
+ store.delete(candidate.id);
152
+ }
153
+ try {
154
+ refreshLiveCompanions(options.cwd);
155
+ }
156
+ catch { /* best-effort */ }
157
+ });
158
+ return {
159
+ matched: candidates.length,
160
+ deleted: candidates.length,
161
+ candidates,
162
+ };
163
+ }
73
164
  export function addCandidateStar(id, by, cwd) {
74
165
  const candidate = loadCandidate(id, cwd);
75
166
  if (candidate.status !== 'pending') {