@soleri/core 9.15.0 → 9.16.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/flows/deliver.flow.yaml +11 -0
- package/data/flows/design.flow.yaml +4 -14
- package/data/flows/enhance.flow.yaml +10 -0
- package/data/flows/explore.flow.yaml +16 -0
- package/data/flows/fix.flow.yaml +1 -1
- package/data/flows/review.flow.yaml +13 -4
- package/dist/capabilities/chain-mapping.d.ts.map +1 -1
- package/dist/capabilities/chain-mapping.js +5 -4
- package/dist/capabilities/chain-mapping.js.map +1 -1
- package/dist/capabilities/registry.d.ts +6 -0
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js +3 -2
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/context/context-engine.js +1 -1
- package/dist/context/context-engine.js.map +1 -1
- package/dist/engine/core-ops.d.ts.map +1 -1
- package/dist/engine/core-ops.js +38 -1
- package/dist/engine/core-ops.js.map +1 -1
- package/dist/flows/epilogue.d.ts +5 -1
- package/dist/flows/epilogue.d.ts.map +1 -1
- package/dist/flows/epilogue.js +11 -3
- package/dist/flows/epilogue.js.map +1 -1
- package/dist/flows/executor.d.ts.map +1 -1
- package/dist/flows/executor.js +13 -5
- package/dist/flows/executor.js.map +1 -1
- package/dist/flows/index.d.ts +1 -2
- package/dist/flows/index.d.ts.map +1 -1
- package/dist/flows/index.js +1 -0
- package/dist/flows/index.js.map +1 -1
- package/dist/flows/plan-builder.d.ts +17 -1
- package/dist/flows/plan-builder.d.ts.map +1 -1
- package/dist/flows/plan-builder.js +67 -6
- package/dist/flows/plan-builder.js.map +1 -1
- package/dist/flows/probes.d.ts +1 -1
- package/dist/flows/probes.d.ts.map +1 -1
- package/dist/flows/probes.js +15 -3
- package/dist/flows/probes.js.map +1 -1
- package/dist/flows/types.d.ts +31 -4
- package/dist/flows/types.d.ts.map +1 -1
- package/dist/flows/types.js +6 -1
- package/dist/flows/types.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/packs/pack-installer.d.ts.map +1 -1
- package/dist/packs/pack-installer.js +28 -2
- package/dist/packs/pack-installer.js.map +1 -1
- package/dist/planning/planner-types.d.ts +2 -0
- package/dist/planning/planner-types.d.ts.map +1 -1
- package/dist/planning/planner.d.ts +1 -0
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +7 -0
- package/dist/planning/planner.js.map +1 -1
- package/dist/playbooks/playbook-executor.d.ts +10 -1
- package/dist/playbooks/playbook-executor.d.ts.map +1 -1
- package/dist/playbooks/playbook-executor.js +8 -2
- package/dist/playbooks/playbook-executor.js.map +1 -1
- package/dist/playbooks/playbook-types.d.ts +8 -0
- package/dist/playbooks/playbook-types.d.ts.map +1 -1
- package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
- package/dist/runtime/admin-extra-ops.js +30 -0
- package/dist/runtime/admin-extra-ops.js.map +1 -1
- package/dist/runtime/admin-ops.d.ts.map +1 -1
- package/dist/runtime/admin-ops.js +60 -21
- package/dist/runtime/admin-ops.js.map +1 -1
- package/dist/runtime/admin-setup-ops.d.ts +11 -0
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
- package/dist/runtime/admin-setup-ops.js +87 -17
- package/dist/runtime/admin-setup-ops.js.map +1 -1
- package/dist/runtime/capture-ops.d.ts.map +1 -1
- package/dist/runtime/capture-ops.js +38 -12
- package/dist/runtime/capture-ops.js.map +1 -1
- package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
- package/dist/runtime/facades/brain-facade.js +16 -4
- package/dist/runtime/facades/brain-facade.js.map +1 -1
- package/dist/runtime/facades/context-facade.d.ts.map +1 -1
- package/dist/runtime/facades/context-facade.js +9 -3
- package/dist/runtime/facades/context-facade.js.map +1 -1
- package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
- package/dist/runtime/facades/memory-facade.js +20 -7
- package/dist/runtime/facades/memory-facade.js.map +1 -1
- package/dist/runtime/facades/orchestrate-facade.d.ts.map +1 -1
- package/dist/runtime/facades/orchestrate-facade.js +12 -0
- package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +113 -4
- package/dist/runtime/facades/plan-facade.js.map +1 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +24 -3
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/orchestrate-ops.d.ts +21 -0
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
- package/dist/runtime/orchestrate-ops.js +132 -38
- package/dist/runtime/orchestrate-ops.js.map +1 -1
- package/dist/runtime/schema-helpers.d.ts.map +1 -1
- package/dist/runtime/schema-helpers.js +4 -0
- package/dist/runtime/schema-helpers.js.map +1 -1
- package/dist/runtime/vault-linking-ops.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.js +16 -3
- package/dist/runtime/vault-linking-ops.js.map +1 -1
- package/dist/scheduler/cron-validator.d.ts +15 -0
- package/dist/scheduler/cron-validator.d.ts.map +1 -0
- package/dist/scheduler/cron-validator.js +93 -0
- package/dist/scheduler/cron-validator.js.map +1 -0
- package/dist/scheduler/platform-linux.d.ts +14 -0
- package/dist/scheduler/platform-linux.d.ts.map +1 -0
- package/dist/scheduler/platform-linux.js +107 -0
- package/dist/scheduler/platform-linux.js.map +1 -0
- package/dist/scheduler/platform-macos.d.ts +15 -0
- package/dist/scheduler/platform-macos.d.ts.map +1 -0
- package/dist/scheduler/platform-macos.js +131 -0
- package/dist/scheduler/platform-macos.js.map +1 -0
- package/dist/scheduler/scheduler-ops.d.ts +14 -0
- package/dist/scheduler/scheduler-ops.d.ts.map +1 -0
- package/dist/scheduler/scheduler-ops.js +77 -0
- package/dist/scheduler/scheduler-ops.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +55 -0
- package/dist/scheduler/scheduler.d.ts.map +1 -0
- package/dist/scheduler/scheduler.js +144 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/types.d.ts +48 -0
- package/dist/scheduler/types.d.ts.map +1 -0
- package/dist/scheduler/types.js +6 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/skills/sync-skills.d.ts +11 -0
- package/dist/skills/sync-skills.d.ts.map +1 -1
- package/dist/skills/sync-skills.js +132 -38
- package/dist/skills/sync-skills.js.map +1 -1
- package/dist/utils/worktree-reaper.d.ts +38 -0
- package/dist/utils/worktree-reaper.d.ts.map +1 -0
- package/dist/utils/worktree-reaper.js +85 -0
- package/dist/utils/worktree-reaper.js.map +1 -0
- package/dist/vault/scope-detector.d.ts.map +1 -1
- package/dist/vault/scope-detector.js +37 -4
- package/dist/vault/scope-detector.js.map +1 -1
- package/dist/vault/vault-entries.d.ts.map +1 -1
- package/dist/vault/vault-entries.js +3 -1
- package/dist/vault/vault-entries.js.map +1 -1
- package/package.json +1 -1
- package/src/agency/agency-manager.test.ts +4 -4
- package/src/agency/default-rules.test.ts +0 -13
- package/src/brain/brain-intelligence.test.ts +0 -5
- package/src/brain/second-brain-features.test.ts +2 -14
- package/src/capabilities/chain-mapping.test.ts +1 -6
- package/src/capabilities/chain-mapping.ts +6 -4
- package/src/capabilities/registry.test.ts +1 -1
- package/src/capabilities/registry.ts +9 -2
- package/src/chat/agent-loop.test.ts +1 -1
- package/src/chat/chat-enhanced.test.ts +0 -8
- package/src/claudemd/compose.test.ts +0 -5
- package/src/context/context-engine.test.ts +0 -1
- package/src/context/context-engine.ts +1 -1
- package/src/control/intent-router.test.ts +2 -2
- package/src/curator/tag-manager.test.ts +0 -4
- package/src/domain-packs/types.test.ts +0 -5
- package/src/dream/dream.test.ts +0 -7
- package/src/enforcement/registry.test.ts +2 -2
- package/src/engine/core-ops.test.ts +4 -22
- package/src/engine/core-ops.ts +36 -1
- package/src/engine/module-manifest.test.ts +1 -31
- package/src/engine/register-engine.test.ts +3 -33
- package/src/errors/retry.test.ts +3 -1
- package/src/flows/chain-runner.test.ts +0 -6
- package/src/flows/context-router.test.ts +3 -3
- package/src/flows/epilogue.test.ts +40 -2
- package/src/flows/epilogue.ts +11 -2
- package/src/flows/executor.test.ts +48 -2
- package/src/flows/executor.ts +15 -5
- package/src/flows/index.ts +1 -3
- package/src/flows/plan-builder.test.ts +201 -0
- package/src/flows/plan-builder.ts +81 -5
- package/src/flows/probes.ts +17 -3
- package/src/flows/types.ts +31 -2
- package/src/health/health-registry.test.ts +3 -1
- package/src/index.ts +17 -0
- package/src/intake/dedup-gate.test.ts +2 -6
- package/src/intake/text-ingester.test.ts +3 -4
- package/src/llm/llm-client.test.ts +1 -1
- package/src/llm/utils.test.ts +1 -1
- package/src/migrations/migration-runner.test.ts +0 -1
- package/src/operator/operator-context-store.test.ts +0 -13
- package/src/operator/operator-profile.test.ts +2 -20
- package/src/packs/pack-installer.ts +28 -2
- package/src/packs/pack-system.test.ts +2 -2
- package/src/persona/defaults.test.ts +19 -19
- package/src/planning/gap-passes.test.ts +0 -46
- package/src/planning/gap-patterns.test.ts +0 -42
- package/src/planning/goal-ancestry.test.ts +3 -1
- package/src/planning/plan-lifecycle.test.ts +15 -7
- package/src/planning/planner-types.ts +2 -0
- package/src/planning/planner.ts +8 -0
- package/src/planning/reconciliation-engine.test.ts +3 -10
- package/src/planning/task-complexity-assessor.test.ts +0 -5
- package/src/planning/task-verifier.test.ts +3 -1
- package/src/playbooks/generic/generic-playbooks.test.ts +0 -28
- package/src/playbooks/index.test.ts +0 -55
- package/src/playbooks/playbook-executor.test.ts +76 -0
- package/src/playbooks/playbook-executor.ts +24 -3
- package/src/playbooks/playbook-types.ts +8 -0
- package/src/plugins/plugin-registry.test.ts +6 -2
- package/src/project/project-registry.test.ts +2 -0
- package/src/queue/async-infrastructure.test.ts +6 -4
- package/src/queue/job-queue.test.ts +13 -7
- package/src/runtime/admin-extra-ops.test.ts +35 -30
- package/src/runtime/admin-extra-ops.ts +30 -0
- package/src/runtime/admin-ops.test.ts +0 -4
- package/src/runtime/admin-ops.ts +63 -21
- package/src/runtime/admin-setup-ops.test.ts +185 -13
- package/src/runtime/admin-setup-ops.ts +86 -16
- package/src/runtime/archive-ops.test.ts +0 -28
- package/src/runtime/branching-ops.test.ts +0 -17
- package/src/runtime/capture-ops.test.ts +41 -16
- package/src/runtime/capture-ops.ts +78 -46
- package/src/runtime/chain-ops.test.ts +0 -21
- package/src/runtime/facades/admin-facade.test.ts +0 -34
- package/src/runtime/facades/agency-facade.test.ts +0 -39
- package/src/runtime/facades/archive-facade.test.ts +0 -43
- package/src/runtime/facades/brain-facade.test.ts +8 -99
- package/src/runtime/facades/brain-facade.ts +29 -12
- package/src/runtime/facades/branching-facade.test.ts +30 -17
- package/src/runtime/facades/chat-facade.test.ts +0 -91
- package/src/runtime/facades/chat-service-ops.test.ts +0 -24
- package/src/runtime/facades/chat-session-ops.test.ts +0 -12
- package/src/runtime/facades/chat-transport-ops.test.ts +0 -23
- package/src/runtime/facades/context-facade.test.ts +0 -17
- package/src/runtime/facades/context-facade.ts +11 -4
- package/src/runtime/facades/control-facade.test.ts +0 -30
- package/src/runtime/facades/curator-facade.test.ts +0 -33
- package/src/runtime/facades/intake-facade.test.ts +0 -33
- package/src/runtime/facades/links-facade.test.ts +0 -37
- package/src/runtime/facades/loop-facade.test.ts +0 -26
- package/src/runtime/facades/memory-facade.test.ts +0 -18
- package/src/runtime/facades/memory-facade.ts +27 -11
- package/src/runtime/facades/operator-facade.test.ts +0 -31
- package/src/runtime/facades/orchestrate-facade.test.ts +0 -21
- package/src/runtime/facades/orchestrate-facade.ts +12 -0
- package/src/runtime/facades/plan-facade.test.ts +7 -32
- package/src/runtime/facades/plan-facade.ts +137 -4
- package/src/runtime/facades/review-facade.test.ts +1 -49
- package/src/runtime/facades/sync-facade.test.ts +24 -41
- package/src/runtime/facades/tier-facade.test.ts +30 -22
- package/src/runtime/facades/vault-facade.test.ts +0 -41
- package/src/runtime/facades/vault-facade.ts +26 -3
- package/src/runtime/grading-ops.test.ts +0 -27
- package/src/runtime/intake-ops.test.ts +0 -19
- package/src/runtime/loop-ops.test.ts +0 -48
- package/src/runtime/memory-cross-project-ops.test.ts +0 -14
- package/src/runtime/memory-extra-ops.test.ts +4 -8
- package/src/runtime/orchestrate-ops.test.ts +238 -19
- package/src/runtime/orchestrate-ops.ts +166 -41
- package/src/runtime/pack-ops.test.ts +0 -26
- package/src/runtime/planning-extra-ops.test.ts +2 -14
- package/src/runtime/playbook-ops-execution.test.ts +9 -20
- package/src/runtime/playbook-ops.test.ts +4 -67
- package/src/runtime/review-ops.test.ts +0 -15
- package/src/runtime/schema-helpers.ts +4 -0
- package/src/runtime/sync-ops.test.ts +0 -18
- package/src/runtime/tier-ops.test.ts +0 -21
- package/src/runtime/vault-extra-ops.test.ts +0 -12
- package/src/runtime/vault-linking-ops.test.ts +0 -4
- package/src/runtime/vault-linking-ops.ts +26 -8
- package/src/runtime/vault-sharing-ops.test.ts +0 -9
- package/src/scheduler/cron-validator.ts +101 -0
- package/src/scheduler/platform-linux.ts +122 -0
- package/src/scheduler/platform-macos.ts +150 -0
- package/src/scheduler/scheduler-ops.ts +77 -0
- package/src/scheduler/scheduler.test.ts +247 -0
- package/src/scheduler/scheduler.ts +174 -0
- package/src/scheduler/types.ts +52 -0
- package/src/skills/__tests__/sync-skills.test.ts +6 -17
- package/src/skills/global-claude-md.test.ts +113 -0
- package/src/skills/sync-skills.ts +143 -35
- package/src/skills/validate-skills.test.ts +12 -11
- package/src/telemetry/telemetry.test.ts +1 -0
- package/src/transport/http-server.test.ts +3 -0
- package/src/transport/session-manager.test.ts +3 -1
- package/src/transport/token-auth.test.ts +6 -9
- package/src/transport/ws-server.test.ts +10 -2
- package/src/utils/worktree-reaper.ts +113 -0
- package/src/vault/__tests__/vault-characterization.test.ts +0 -108
- package/src/vault/linking.test.ts +0 -2
- package/src/vault/playbook.test.ts +4 -1
- package/src/vault/scope-detector.test.ts +3 -1
- package/src/vault/scope-detector.ts +42 -4
- package/src/vault/vault-connect.test.ts +1 -1
- package/src/vault/vault-entries.ts +3 -1
- package/src/vault/vault.test.ts +23 -8
|
@@ -294,9 +294,4 @@ describe('assessTaskComplexity — reasoning', () => {
|
|
|
294
294
|
const result = assess({ prompt: 'fix typo' });
|
|
295
295
|
expect(result.reasoning).toContain('No complexity signals detected');
|
|
296
296
|
});
|
|
297
|
-
|
|
298
|
-
it('always returns 6 signals', () => {
|
|
299
|
-
const result = assess({ prompt: 'anything' });
|
|
300
|
-
expect(result.signals).toHaveLength(6);
|
|
301
|
-
});
|
|
302
297
|
});
|
|
@@ -25,6 +25,7 @@ describe('task-verifier', () => {
|
|
|
25
25
|
const existing: TaskEvidence[] = [
|
|
26
26
|
{ criterion: 'cr1', content: 'result', type: 'description', submittedAt: 100 },
|
|
27
27
|
];
|
|
28
|
+
const before = Date.now();
|
|
28
29
|
const result = createEvidence(existing, {
|
|
29
30
|
criterion: 'cr2',
|
|
30
31
|
content: 'output',
|
|
@@ -32,7 +33,8 @@ describe('task-verifier', () => {
|
|
|
32
33
|
});
|
|
33
34
|
expect(result).toHaveLength(2);
|
|
34
35
|
expect(result[1].criterion).toBe('cr2');
|
|
35
|
-
expect(result[1].submittedAt).
|
|
36
|
+
expect(result[1].submittedAt).toBeGreaterThanOrEqual(before);
|
|
37
|
+
expect(result[1].submittedAt).toBeLessThanOrEqual(Date.now());
|
|
36
38
|
});
|
|
37
39
|
it('does not mutate original array', () => {
|
|
38
40
|
const existing: TaskEvidence[] = [];
|
|
@@ -181,10 +181,6 @@ describe('All generic playbooks', () => {
|
|
|
181
181
|
// ─── Individual playbook tests ────────────────────────────────────
|
|
182
182
|
|
|
183
183
|
describe('brainstormingPlaybook', () => {
|
|
184
|
-
it('should have correct id', () => {
|
|
185
|
-
expect(brainstormingPlaybook.id).toBe('generic-brainstorming');
|
|
186
|
-
});
|
|
187
|
-
|
|
188
184
|
it('should match BUILD and PLAN intents', () => {
|
|
189
185
|
expect(brainstormingPlaybook.matchIntents).toContain('BUILD');
|
|
190
186
|
expect(brainstormingPlaybook.matchIntents).toContain('PLAN');
|
|
@@ -221,10 +217,6 @@ describe('brainstormingPlaybook', () => {
|
|
|
221
217
|
});
|
|
222
218
|
|
|
223
219
|
describe('codeReviewPlaybook', () => {
|
|
224
|
-
it('should have correct id', () => {
|
|
225
|
-
expect(codeReviewPlaybook.id).toBe('generic-code-review');
|
|
226
|
-
});
|
|
227
|
-
|
|
228
220
|
it('should match REVIEW intent only', () => {
|
|
229
221
|
expect(codeReviewPlaybook.matchIntents).toEqual(['REVIEW']);
|
|
230
222
|
});
|
|
@@ -260,10 +252,6 @@ describe('codeReviewPlaybook', () => {
|
|
|
260
252
|
});
|
|
261
253
|
|
|
262
254
|
describe('onboardingPlaybook', () => {
|
|
263
|
-
it('should have correct id', () => {
|
|
264
|
-
expect(onboardingPlaybook.id).toBe('generic-onboarding');
|
|
265
|
-
});
|
|
266
|
-
|
|
267
255
|
it('should match PLAN intent', () => {
|
|
268
256
|
expect(onboardingPlaybook.matchIntents).toContain('PLAN');
|
|
269
257
|
});
|
|
@@ -288,10 +276,6 @@ describe('onboardingPlaybook', () => {
|
|
|
288
276
|
});
|
|
289
277
|
|
|
290
278
|
describe('subagentExecutionPlaybook', () => {
|
|
291
|
-
it('should have correct id', () => {
|
|
292
|
-
expect(subagentExecutionPlaybook.id).toBe('generic-subagent-execution');
|
|
293
|
-
});
|
|
294
|
-
|
|
295
279
|
it('should match BUILD and IMPROVE intents', () => {
|
|
296
280
|
expect(subagentExecutionPlaybook.matchIntents).toContain('BUILD');
|
|
297
281
|
expect(subagentExecutionPlaybook.matchIntents).toContain('IMPROVE');
|
|
@@ -314,10 +298,6 @@ describe('subagentExecutionPlaybook', () => {
|
|
|
314
298
|
});
|
|
315
299
|
|
|
316
300
|
describe('systematicDebuggingPlaybook', () => {
|
|
317
|
-
it('should have correct id', () => {
|
|
318
|
-
expect(systematicDebuggingPlaybook.id).toBe('generic-systematic-debugging');
|
|
319
|
-
});
|
|
320
|
-
|
|
321
301
|
it('should match FIX intent only', () => {
|
|
322
302
|
expect(systematicDebuggingPlaybook.matchIntents).toEqual(['FIX']);
|
|
323
303
|
});
|
|
@@ -361,10 +341,6 @@ describe('systematicDebuggingPlaybook', () => {
|
|
|
361
341
|
});
|
|
362
342
|
|
|
363
343
|
describe('tddPlaybook', () => {
|
|
364
|
-
it('should have correct id', () => {
|
|
365
|
-
expect(tddPlaybook.id).toBe('generic-tdd');
|
|
366
|
-
});
|
|
367
|
-
|
|
368
344
|
it('should match BUILD and FIX intents', () => {
|
|
369
345
|
expect(tddPlaybook.matchIntents).toContain('BUILD');
|
|
370
346
|
expect(tddPlaybook.matchIntents).toContain('FIX');
|
|
@@ -399,10 +375,6 @@ describe('tddPlaybook', () => {
|
|
|
399
375
|
});
|
|
400
376
|
|
|
401
377
|
describe('verificationPlaybook', () => {
|
|
402
|
-
it('should have correct id', () => {
|
|
403
|
-
expect(verificationPlaybook.id).toBe('generic-verification');
|
|
404
|
-
});
|
|
405
|
-
|
|
406
378
|
it('should match BUILD, FIX, IMPROVE, and DELIVER intents', () => {
|
|
407
379
|
expect(verificationPlaybook.matchIntents).toContain('BUILD');
|
|
408
380
|
expect(verificationPlaybook.matchIntents).toContain('FIX');
|
|
@@ -9,61 +9,6 @@ import { describe, it, expect } from 'vitest';
|
|
|
9
9
|
import * as playbooksModule from './index.js';
|
|
10
10
|
|
|
11
11
|
describe('playbooks barrel export', () => {
|
|
12
|
-
it('should export getBuiltinPlaybook function', () => {
|
|
13
|
-
expect(typeof playbooksModule.getBuiltinPlaybook).toBe('function');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should export getAllBuiltinPlaybooks function', () => {
|
|
17
|
-
expect(typeof playbooksModule.getAllBuiltinPlaybooks).toBe('function');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('should export scorePlaybook function', () => {
|
|
21
|
-
expect(typeof playbooksModule.scorePlaybook).toBe('function');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should export mergePlaybooks function', () => {
|
|
25
|
-
expect(typeof playbooksModule.mergePlaybooks).toBe('function');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should export matchPlaybooks function', () => {
|
|
29
|
-
expect(typeof playbooksModule.matchPlaybooks).toBe('function');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should export playbookDefinitionToEntry function', () => {
|
|
33
|
-
expect(typeof playbooksModule.playbookDefinitionToEntry).toBe('function');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should export entryToPlaybookDefinition function', () => {
|
|
37
|
-
expect(typeof playbooksModule.entryToPlaybookDefinition).toBe('function');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should export seedDefaultPlaybooks function', () => {
|
|
41
|
-
expect(typeof playbooksModule.seedDefaultPlaybooks).toBe('function');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should export PlaybookExecutor class', () => {
|
|
45
|
-
expect(typeof playbooksModule.PlaybookExecutor).toBe('function');
|
|
46
|
-
const executor = new playbooksModule.PlaybookExecutor();
|
|
47
|
-
expect(executor).toBeInstanceOf(playbooksModule.PlaybookExecutor);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should not export unexpected runtime values', () => {
|
|
51
|
-
const expectedExports = [
|
|
52
|
-
'getBuiltinPlaybook',
|
|
53
|
-
'getAllBuiltinPlaybooks',
|
|
54
|
-
'scorePlaybook',
|
|
55
|
-
'mergePlaybooks',
|
|
56
|
-
'matchPlaybooks',
|
|
57
|
-
'playbookDefinitionToEntry',
|
|
58
|
-
'entryToPlaybookDefinition',
|
|
59
|
-
'seedDefaultPlaybooks',
|
|
60
|
-
'PlaybookExecutor',
|
|
61
|
-
];
|
|
62
|
-
|
|
63
|
-
const actualExports = Object.keys(playbooksModule);
|
|
64
|
-
expect(actualExports.sort()).toEqual(expectedExports.sort());
|
|
65
|
-
});
|
|
66
|
-
|
|
67
12
|
it('should return playbooks from getAllBuiltinPlaybooks via barrel', () => {
|
|
68
13
|
const playbooks = playbooksModule.getAllBuiltinPlaybooks();
|
|
69
14
|
expect(playbooks.length).toBeGreaterThanOrEqual(6);
|
|
@@ -217,6 +217,82 @@ describe('PlaybookExecutor', () => {
|
|
|
217
217
|
const result = executor.complete(sessionId);
|
|
218
218
|
expect('error' in result).toBe(true);
|
|
219
219
|
});
|
|
220
|
+
|
|
221
|
+
// ── evidence source ──────────────────────────────────────────────
|
|
222
|
+
|
|
223
|
+
describe('evidence source', () => {
|
|
224
|
+
function makePlaybookWithUserGate(): PlaybookDefinition {
|
|
225
|
+
return makePlaybook({
|
|
226
|
+
gates: [
|
|
227
|
+
{
|
|
228
|
+
phase: 'completion',
|
|
229
|
+
requirement: 'User confirmed result',
|
|
230
|
+
checkType: 'user-confirm',
|
|
231
|
+
requiresUserEvidence: true,
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
it('agent-source evidence fails a requiresUserEvidence gate', () => {
|
|
238
|
+
const { sessionId, totalSteps } = executor.start(makePlaybookWithUserGate());
|
|
239
|
+
for (let i = 0; i < totalSteps; i++) executor.step(sessionId);
|
|
240
|
+
|
|
241
|
+
const result = executor.complete(sessionId, {
|
|
242
|
+
gateResults: { 'user-confirm': { satisfied: true, source: 'agent' } },
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
expect('error' in result).toBe(false);
|
|
246
|
+
if ('error' in result) return;
|
|
247
|
+
|
|
248
|
+
expect(result.gatesPassed).toBe(false);
|
|
249
|
+
expect(result.unsatisfiedGates[0]).toContain('user-confirm');
|
|
250
|
+
expect(result.unsatisfiedGates[0]).toContain('requires user confirmation');
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('user-source evidence satisfies a requiresUserEvidence gate', () => {
|
|
254
|
+
const { sessionId, totalSteps } = executor.start(makePlaybookWithUserGate());
|
|
255
|
+
for (let i = 0; i < totalSteps; i++) executor.step(sessionId);
|
|
256
|
+
|
|
257
|
+
const result = executor.complete(sessionId, {
|
|
258
|
+
gateResults: { 'user-confirm': { satisfied: true, source: 'user' } },
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
expect('error' in result).toBe(false);
|
|
262
|
+
if ('error' in result) return;
|
|
263
|
+
|
|
264
|
+
expect(result.gatesPassed).toBe(true);
|
|
265
|
+
expect(result.unsatisfiedGates).toHaveLength(0);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('plain boolean true satisfies a gate without requiresUserEvidence', () => {
|
|
269
|
+
const { sessionId, totalSteps } = executor.start(makePlaybook());
|
|
270
|
+
for (let i = 0; i < totalSteps; i++) executor.step(sessionId);
|
|
271
|
+
|
|
272
|
+
const result = executor.complete(sessionId, {
|
|
273
|
+
gateResults: { 'test-pass': true },
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
expect('error' in result).toBe(false);
|
|
277
|
+
if ('error' in result) return;
|
|
278
|
+
expect(result.gatesPassed).toBe(true);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('plain boolean true does not satisfy a requiresUserEvidence gate', () => {
|
|
282
|
+
const { sessionId, totalSteps } = executor.start(makePlaybookWithUserGate());
|
|
283
|
+
for (let i = 0; i < totalSteps; i++) executor.step(sessionId);
|
|
284
|
+
|
|
285
|
+
// bare true = no source = treated as agent
|
|
286
|
+
const result = executor.complete(sessionId, {
|
|
287
|
+
gateResults: { 'user-confirm': true },
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
expect('error' in result).toBe(false);
|
|
291
|
+
if ('error' in result) return;
|
|
292
|
+
expect(result.gatesPassed).toBe(false);
|
|
293
|
+
expect(result.unsatisfiedGates[0]).toContain('requires user confirmation');
|
|
294
|
+
});
|
|
295
|
+
});
|
|
220
296
|
});
|
|
221
297
|
|
|
222
298
|
// ─── getSession / listSessions ──────────────────────────────────
|
|
@@ -72,6 +72,16 @@ export interface CompleteResult {
|
|
|
72
72
|
duration: number;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Evidence record for a gate result.
|
|
77
|
+
* `source` distinguishes agent-collected evidence from explicit user confirmation.
|
|
78
|
+
*/
|
|
79
|
+
export interface GateEvidence {
|
|
80
|
+
satisfied: boolean;
|
|
81
|
+
/** Who produced the evidence. Defaults to 'agent' when omitted. */
|
|
82
|
+
source?: 'agent' | 'user';
|
|
83
|
+
}
|
|
84
|
+
|
|
75
85
|
// =============================================================================
|
|
76
86
|
// STEP PARSER
|
|
77
87
|
// =============================================================================
|
|
@@ -227,7 +237,7 @@ export class PlaybookExecutor {
|
|
|
227
237
|
*/
|
|
228
238
|
complete(
|
|
229
239
|
sessionId: string,
|
|
230
|
-
options?: { abort?: boolean; gateResults?: Record<string, boolean> },
|
|
240
|
+
options?: { abort?: boolean; gateResults?: Record<string, boolean | GateEvidence> },
|
|
231
241
|
): CompleteResult | { error: string } {
|
|
232
242
|
const session = this.sessions.get(sessionId);
|
|
233
243
|
if (!session) return { error: `Session not found: ${sessionId}` };
|
|
@@ -251,8 +261,19 @@ export class PlaybookExecutor {
|
|
|
251
261
|
const completionGates = session.gates.filter((g) => g.phase === 'completion');
|
|
252
262
|
const unsatisfiedGates: string[] = [];
|
|
253
263
|
for (const gate of completionGates) {
|
|
254
|
-
|
|
255
|
-
|
|
264
|
+
const raw = gateResults[gate.checkType];
|
|
265
|
+
const evidence: GateEvidence =
|
|
266
|
+
typeof raw === 'object' && raw !== null ? raw : { satisfied: !!raw, source: 'agent' };
|
|
267
|
+
|
|
268
|
+
const satisfied =
|
|
269
|
+
evidence.satisfied && !(gate.requiresUserEvidence && evidence.source !== 'user');
|
|
270
|
+
|
|
271
|
+
if (!satisfied) {
|
|
272
|
+
const reason =
|
|
273
|
+
gate.requiresUserEvidence && evidence.satisfied && evidence.source !== 'user'
|
|
274
|
+
? `${gate.checkType}: ${gate.requirement} (requires user confirmation)`
|
|
275
|
+
: `${gate.checkType}: ${gate.requirement}`;
|
|
276
|
+
unsatisfiedGates.push(reason);
|
|
256
277
|
}
|
|
257
278
|
}
|
|
258
279
|
|
|
@@ -48,6 +48,14 @@ export interface PlaybookGate {
|
|
|
48
48
|
requirement: string;
|
|
49
49
|
/** Check type to create/validate */
|
|
50
50
|
checkType: string;
|
|
51
|
+
/** Whether this gate blocks progression (blocking) or is advisory only (advisory). Defaults to 'blocking'. */
|
|
52
|
+
severity?: 'blocking' | 'advisory';
|
|
53
|
+
/**
|
|
54
|
+
* When true, only user-sourced evidence satisfies this gate.
|
|
55
|
+
* Agent-collected evidence (e.g. automated test runs) does not count.
|
|
56
|
+
* Defaults to false.
|
|
57
|
+
*/
|
|
58
|
+
requiresUserEvidence?: boolean;
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
// =============================================================================
|
|
@@ -47,13 +47,15 @@ describe('PluginRegistry — colocated', () => {
|
|
|
47
47
|
|
|
48
48
|
describe('register', () => {
|
|
49
49
|
it('registers a plugin and sets initial status to registered', () => {
|
|
50
|
+
const before = Date.now();
|
|
50
51
|
const loaded = makeLoaded();
|
|
51
52
|
const registered = registry.register(loaded);
|
|
52
53
|
|
|
53
54
|
expect(registered.id).toBe('test-plugin');
|
|
54
55
|
expect(registered.status).toBe('registered');
|
|
55
56
|
expect(registered.facades).toEqual([]);
|
|
56
|
-
expect(registered.registeredAt).
|
|
57
|
+
expect(registered.registeredAt).toBeGreaterThanOrEqual(before);
|
|
58
|
+
expect(registered.registeredAt).toBeLessThanOrEqual(Date.now());
|
|
57
59
|
});
|
|
58
60
|
|
|
59
61
|
it('throws when registering duplicate id', () => {
|
|
@@ -86,11 +88,13 @@ describe('PluginRegistry — colocated', () => {
|
|
|
86
88
|
}),
|
|
87
89
|
});
|
|
88
90
|
|
|
91
|
+
const before = Date.now();
|
|
89
92
|
registry.register(loaded);
|
|
90
93
|
const result = await registry.activate('test-plugin', makeContext(loaded));
|
|
91
94
|
|
|
92
95
|
expect(result.status).toBe('active');
|
|
93
|
-
expect(result.activatedAt).
|
|
96
|
+
expect(result.activatedAt).toBeGreaterThanOrEqual(before);
|
|
97
|
+
expect(result.activatedAt).toBeLessThanOrEqual(Date.now());
|
|
94
98
|
expect(result.facades).toHaveLength(1);
|
|
95
99
|
expect(result.facades[0].name).toBe('my_facade');
|
|
96
100
|
expect(result.facades[0].ops).toHaveLength(2);
|
|
@@ -214,10 +214,12 @@ describe('ProjectRegistry', () => {
|
|
|
214
214
|
|
|
215
215
|
describe('register', () => {
|
|
216
216
|
it('creates a new project and returns it', () => {
|
|
217
|
+
const before = Date.now();
|
|
217
218
|
const proj = registry.register('/tmp/myproj', 'My Project');
|
|
218
219
|
expect(proj.path).toBe('/tmp/myproj');
|
|
219
220
|
expect(proj.name).toBe('My Project');
|
|
220
221
|
expect(proj.id).toBeTruthy();
|
|
222
|
+
expect(proj.registeredAt).toBeGreaterThanOrEqual(before);
|
|
221
223
|
expect(proj.registeredAt).toBeLessThanOrEqual(Date.now());
|
|
222
224
|
});
|
|
223
225
|
|
|
@@ -104,8 +104,7 @@ describe('JobQueue', () => {
|
|
|
104
104
|
|
|
105
105
|
it('enqueue creates a job and returns ID', () => {
|
|
106
106
|
const id = queue.enqueue('tag-normalize', { entryId: 'e1' });
|
|
107
|
-
expect(id).
|
|
108
|
-
expect(id.length).toBeGreaterThan(0);
|
|
107
|
+
expect(id).toHaveLength(12);
|
|
109
108
|
});
|
|
110
109
|
|
|
111
110
|
it('dequeue returns oldest pending job', () => {
|
|
@@ -200,16 +199,18 @@ describe('JobQueue', () => {
|
|
|
200
199
|
|
|
201
200
|
it('getStats returns correct counts', () => {
|
|
202
201
|
const stats = queue.getStats();
|
|
203
|
-
expect(stats.total).
|
|
202
|
+
expect(typeof stats.total).toBe('number');
|
|
204
203
|
expect(typeof stats.pending).toBe('number');
|
|
205
204
|
expect(typeof stats.running).toBe('number');
|
|
206
205
|
expect(typeof stats.completed).toBe('number');
|
|
207
206
|
expect(typeof stats.failed).toBe('number');
|
|
207
|
+
expect(stats.total).toBe(stats.pending + stats.running + stats.completed + stats.failed);
|
|
208
208
|
});
|
|
209
209
|
|
|
210
210
|
it('purge removes old completed/failed jobs', () => {
|
|
211
211
|
// purge with 0 days should remove all completed/failed
|
|
212
212
|
const purged = queue.purge(0);
|
|
213
|
+
expect(typeof purged).toBe('number');
|
|
213
214
|
expect(purged).toBeGreaterThanOrEqual(0);
|
|
214
215
|
});
|
|
215
216
|
});
|
|
@@ -275,7 +276,8 @@ describe('PipelineRunner', () => {
|
|
|
275
276
|
const status = runner.getStatus();
|
|
276
277
|
expect(status.running).toBe(false); // Not started yet
|
|
277
278
|
expect(status.pollIntervalMs).toBe(100);
|
|
278
|
-
|
|
279
|
+
// At this point: process-test succeeded = 1 processed; flaky-type threw so it's retried, not counted
|
|
280
|
+
expect(status.jobsProcessed).toBe(1);
|
|
279
281
|
});
|
|
280
282
|
|
|
281
283
|
it('start/stop controls background polling', async () => {
|
|
@@ -131,11 +131,14 @@ describe('JobQueue', () => {
|
|
|
131
131
|
queue = new JobQueue(provider);
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
-
it('initializes the table on construction', () => {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
134
|
+
it('initializes the job_queue table on construction', () => {
|
|
135
|
+
// Verify the correct DDL was executed — not just that something was called
|
|
136
|
+
const ddl = (provider.execSql as ReturnType<typeof vi.fn>).mock.calls[0]?.[0] as
|
|
137
|
+
| string
|
|
138
|
+
| undefined;
|
|
139
|
+
expect(ddl).toContain('CREATE TABLE IF NOT EXISTS job_queue');
|
|
140
|
+
expect(ddl).toContain('status');
|
|
141
|
+
expect(ddl).toContain('retry_count');
|
|
139
142
|
});
|
|
140
143
|
|
|
141
144
|
describe('enqueue', () => {
|
|
@@ -281,7 +284,8 @@ describe('JobQueue', () => {
|
|
|
281
284
|
queue.dequeue();
|
|
282
285
|
queue.complete(id);
|
|
283
286
|
const stats = queue.getStats();
|
|
284
|
-
expect(stats.total).
|
|
287
|
+
expect(stats.total).toBe(stats.pending + stats.running + stats.completed + stats.failed);
|
|
288
|
+
expect(stats.completed).toBeGreaterThanOrEqual(1);
|
|
285
289
|
});
|
|
286
290
|
});
|
|
287
291
|
|
|
@@ -321,7 +325,9 @@ describe('JobQueue', () => {
|
|
|
321
325
|
queue.complete(id1);
|
|
322
326
|
queue.fail(id2, 'err');
|
|
323
327
|
const deleted = queue.purge(30);
|
|
324
|
-
|
|
328
|
+
// The mock purges all completed/failed — 2 were just created
|
|
329
|
+
expect(typeof deleted).toBe('number');
|
|
330
|
+
expect(deleted).toBeGreaterThanOrEqual(2);
|
|
325
331
|
});
|
|
326
332
|
});
|
|
327
333
|
});
|
|
@@ -95,19 +95,6 @@ describe('createAdminExtraOps', () => {
|
|
|
95
95
|
ops = createAdminExtraOps(runtime);
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
it('returns at least 24 ops', () => {
|
|
99
|
-
expect(ops.length).toBeGreaterThanOrEqual(24);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('all ops have name, description, auth, and handler', () => {
|
|
103
|
-
for (const op of ops) {
|
|
104
|
-
expect(op.name).toBeTruthy();
|
|
105
|
-
expect(op.description).toBeTruthy();
|
|
106
|
-
expect(['read', 'write', 'admin']).toContain(op.auth);
|
|
107
|
-
expect(typeof op.handler).toBe('function');
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
98
|
describe('admin_telemetry', () => {
|
|
112
99
|
it('returns telemetry stats', async () => {
|
|
113
100
|
const result = await findOp(ops, 'admin_telemetry').handler({});
|
|
@@ -441,7 +428,7 @@ describe('createAdminExtraOps', () => {
|
|
|
441
428
|
subsystem: 'nonexistent',
|
|
442
429
|
})) as Record<string, unknown>;
|
|
443
430
|
expect(result.error).toContain('Unknown subsystem');
|
|
444
|
-
expect(result.available).
|
|
431
|
+
expect(result.available).toEqual(['vault', 'brain']); // keys from mock snapshot.subsystems
|
|
445
432
|
});
|
|
446
433
|
});
|
|
447
434
|
|
|
@@ -481,33 +468,51 @@ describe('createAdminExtraOps', () => {
|
|
|
481
468
|
});
|
|
482
469
|
|
|
483
470
|
describe('admin_persistence_info', () => {
|
|
484
|
-
it('returns backend and table counts', async () => {
|
|
485
|
-
const result = (await findOp(ops, 'admin_persistence_info').handler({})) as
|
|
486
|
-
string
|
|
487
|
-
|
|
488
|
-
|
|
471
|
+
it('returns backend and table counts for each known table', async () => {
|
|
472
|
+
const result = (await findOp(ops, 'admin_persistence_info').handler({})) as {
|
|
473
|
+
backend: string;
|
|
474
|
+
tables: Record<string, number>;
|
|
475
|
+
};
|
|
489
476
|
expect(result.backend).toBe('sqlite');
|
|
490
|
-
|
|
477
|
+
// Mock provider.get returns { count: 42 } for every table
|
|
478
|
+
expect(result.tables).toEqual({
|
|
479
|
+
entries: 42,
|
|
480
|
+
entries_archive: 42,
|
|
481
|
+
memories: 42,
|
|
482
|
+
projects: 42,
|
|
483
|
+
brain_vocabulary: 42,
|
|
484
|
+
brain_feedback: 42,
|
|
485
|
+
});
|
|
491
486
|
});
|
|
492
487
|
});
|
|
493
488
|
|
|
494
489
|
describe('admin_setup_check', () => {
|
|
495
|
-
it('returns
|
|
496
|
-
const result = (await findOp(ops, 'admin_setup_check').handler({})) as
|
|
497
|
-
string
|
|
498
|
-
|
|
499
|
-
|
|
490
|
+
it('returns ready: true with vault, brain, llm, and health checks all passing', async () => {
|
|
491
|
+
const result = (await findOp(ops, 'admin_setup_check').handler({})) as {
|
|
492
|
+
agentId: string;
|
|
493
|
+
ready: boolean;
|
|
494
|
+
checks: Record<string, { ok: boolean }>;
|
|
495
|
+
};
|
|
500
496
|
expect(result.agentId).toBe('test-agent');
|
|
501
|
-
expect(result.
|
|
502
|
-
expect(
|
|
497
|
+
expect(result.ready).toBe(true);
|
|
498
|
+
expect(result.checks.vault.ok).toBe(true);
|
|
499
|
+
expect(result.checks.brain.ok).toBe(true);
|
|
500
|
+
expect(result.checks.llm.ok).toBe(true);
|
|
503
501
|
});
|
|
504
502
|
});
|
|
505
503
|
|
|
506
504
|
describe('admin_setup_run', () => {
|
|
507
|
-
it('runs setup actions', async () => {
|
|
508
|
-
const result = (await findOp(ops, 'admin_setup_run').handler({})) as
|
|
505
|
+
it('runs all three setup actions and returns their names', async () => {
|
|
506
|
+
const result = (await findOp(ops, 'admin_setup_run').handler({})) as {
|
|
507
|
+
setup: boolean;
|
|
508
|
+
actions: string[];
|
|
509
|
+
};
|
|
509
510
|
expect(result.setup).toBe(true);
|
|
510
|
-
expect(
|
|
511
|
+
expect(result.actions).toEqual([
|
|
512
|
+
'brain_vocabulary_rebuilt',
|
|
513
|
+
'fts_index_rebuilt',
|
|
514
|
+
'templates_reloaded',
|
|
515
|
+
]);
|
|
511
516
|
});
|
|
512
517
|
});
|
|
513
518
|
});
|
|
@@ -849,5 +849,35 @@ export function createAdminExtraOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
849
849
|
};
|
|
850
850
|
},
|
|
851
851
|
},
|
|
852
|
+
{
|
|
853
|
+
name: 'worktree_status',
|
|
854
|
+
description: 'List stale .claude/worktrees/ entries without removing them.',
|
|
855
|
+
auth: 'read' as const,
|
|
856
|
+
schema: z.object({
|
|
857
|
+
projectPath: z.string().optional().default('.'),
|
|
858
|
+
}),
|
|
859
|
+
handler: async (params) => {
|
|
860
|
+
const { worktreeStatus } = await import('../utils/worktree-reaper.js');
|
|
861
|
+
const { resolve } = await import('node:path');
|
|
862
|
+
const projectPath = resolve((params.projectPath as string) ?? '.');
|
|
863
|
+
const status = worktreeStatus(projectPath);
|
|
864
|
+
return { ...status, projectPath };
|
|
865
|
+
},
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
name: 'worktree_reap',
|
|
869
|
+
description: 'Remove stale .claude/worktrees/ entries and prune git worktree refs.',
|
|
870
|
+
auth: 'write' as const,
|
|
871
|
+
schema: z.object({
|
|
872
|
+
projectPath: z.string().optional().default('.'),
|
|
873
|
+
}),
|
|
874
|
+
handler: async (params) => {
|
|
875
|
+
const { worktreeReap } = await import('../utils/worktree-reaper.js');
|
|
876
|
+
const { resolve } = await import('node:path');
|
|
877
|
+
const projectPath = resolve((params.projectPath as string) ?? '.');
|
|
878
|
+
const report = worktreeReap(projectPath);
|
|
879
|
+
return { ...report, projectPath };
|
|
880
|
+
},
|
|
881
|
+
},
|
|
852
882
|
];
|
|
853
883
|
}
|
|
@@ -70,10 +70,6 @@ describe('createAdminOps', () => {
|
|
|
70
70
|
ops = createAdminOps(rt);
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
it('returns ops array', () => {
|
|
74
|
-
expect(ops.length).toBeGreaterThan(0);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
73
|
// ─── admin_health ─────────────────────────────────────────────
|
|
78
74
|
|
|
79
75
|
describe('admin_health', () => {
|