@soleri/core 2.1.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/brain/brain.d.ts +10 -1
- package/dist/brain/brain.d.ts.map +1 -1
- package/dist/brain/brain.js +116 -13
- package/dist/brain/brain.js.map +1 -1
- package/dist/brain/intelligence.d.ts +36 -1
- package/dist/brain/intelligence.d.ts.map +1 -1
- package/dist/brain/intelligence.js +119 -14
- package/dist/brain/intelligence.js.map +1 -1
- package/dist/brain/types.d.ts +34 -2
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/cognee/client.d.ts +3 -0
- package/dist/cognee/client.d.ts.map +1 -1
- package/dist/cognee/client.js +17 -0
- package/dist/cognee/client.js.map +1 -1
- package/dist/cognee/sync-manager.d.ts +94 -0
- package/dist/cognee/sync-manager.d.ts.map +1 -0
- package/dist/cognee/sync-manager.js +293 -0
- package/dist/cognee/sync-manager.js.map +1 -0
- package/dist/control/identity-manager.d.ts +22 -0
- package/dist/control/identity-manager.d.ts.map +1 -0
- package/dist/control/identity-manager.js +233 -0
- package/dist/control/identity-manager.js.map +1 -0
- package/dist/control/intent-router.d.ts +32 -0
- package/dist/control/intent-router.d.ts.map +1 -0
- package/dist/control/intent-router.js +242 -0
- package/dist/control/intent-router.js.map +1 -0
- package/dist/control/types.d.ts +68 -0
- package/dist/control/types.d.ts.map +1 -0
- package/dist/control/types.js +9 -0
- package/dist/control/types.js.map +1 -0
- package/dist/curator/curator.d.ts +37 -1
- package/dist/curator/curator.d.ts.map +1 -1
- package/dist/curator/curator.js +199 -1
- package/dist/curator/curator.js.map +1 -1
- package/dist/errors/classify.d.ts +13 -0
- package/dist/errors/classify.d.ts.map +1 -0
- package/dist/errors/classify.js +97 -0
- package/dist/errors/classify.js.map +1 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +4 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/retry.d.ts +40 -0
- package/dist/errors/retry.d.ts.map +1 -0
- package/dist/errors/retry.js +97 -0
- package/dist/errors/retry.js.map +1 -0
- package/dist/errors/types.d.ts +48 -0
- package/dist/errors/types.d.ts.map +1 -0
- package/dist/errors/types.js +59 -0
- package/dist/errors/types.js.map +1 -0
- package/dist/facades/types.d.ts +1 -1
- package/dist/governance/governance.d.ts +42 -0
- package/dist/governance/governance.d.ts.map +1 -0
- package/dist/governance/governance.js +488 -0
- package/dist/governance/governance.js.map +1 -0
- package/dist/governance/index.d.ts +3 -0
- package/dist/governance/index.d.ts.map +1 -0
- package/dist/governance/index.js +2 -0
- package/dist/governance/index.js.map +1 -0
- package/dist/governance/types.d.ts +102 -0
- package/dist/governance/types.d.ts.map +1 -0
- package/dist/governance/types.js +3 -0
- package/dist/governance/types.js.map +1 -0
- package/dist/index.d.ts +52 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -1
- package/dist/index.js.map +1 -1
- package/dist/intake/content-classifier.d.ts +14 -0
- package/dist/intake/content-classifier.d.ts.map +1 -0
- package/dist/intake/content-classifier.js +125 -0
- package/dist/intake/content-classifier.js.map +1 -0
- package/dist/intake/dedup-gate.d.ts +17 -0
- package/dist/intake/dedup-gate.d.ts.map +1 -0
- package/dist/intake/dedup-gate.js +66 -0
- package/dist/intake/dedup-gate.js.map +1 -0
- package/dist/intake/intake-pipeline.d.ts +63 -0
- package/dist/intake/intake-pipeline.d.ts.map +1 -0
- package/dist/intake/intake-pipeline.js +373 -0
- package/dist/intake/intake-pipeline.js.map +1 -0
- package/dist/intake/types.d.ts +65 -0
- package/dist/intake/types.d.ts.map +1 -0
- package/dist/intake/types.js +3 -0
- package/dist/intake/types.js.map +1 -0
- package/dist/intelligence/loader.js +1 -1
- package/dist/intelligence/loader.js.map +1 -1
- package/dist/intelligence/types.d.ts +3 -1
- package/dist/intelligence/types.d.ts.map +1 -1
- package/dist/logging/logger.d.ts +37 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +145 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/logging/types.d.ts +19 -0
- package/dist/logging/types.d.ts.map +1 -0
- package/dist/logging/types.js +2 -0
- package/dist/logging/types.js.map +1 -0
- package/dist/loop/loop-manager.d.ts +100 -0
- package/dist/loop/loop-manager.d.ts.map +1 -0
- package/dist/loop/loop-manager.js +379 -0
- package/dist/loop/loop-manager.js.map +1 -0
- package/dist/loop/types.d.ts +103 -0
- package/dist/loop/types.d.ts.map +1 -0
- package/dist/loop/types.js +11 -0
- package/dist/loop/types.js.map +1 -0
- package/dist/persistence/index.d.ts +3 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +2 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/sqlite-provider.d.ts +25 -0
- package/dist/persistence/sqlite-provider.d.ts.map +1 -0
- package/dist/persistence/sqlite-provider.js +59 -0
- package/dist/persistence/sqlite-provider.js.map +1 -0
- package/dist/persistence/types.d.ts +36 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/persistence/types.js +8 -0
- package/dist/persistence/types.js.map +1 -0
- package/dist/planning/gap-analysis.d.ts +72 -0
- package/dist/planning/gap-analysis.d.ts.map +1 -0
- package/dist/planning/gap-analysis.js +442 -0
- package/dist/planning/gap-analysis.js.map +1 -0
- package/dist/planning/gap-types.d.ts +29 -0
- package/dist/planning/gap-types.d.ts.map +1 -0
- package/dist/planning/gap-types.js +28 -0
- package/dist/planning/gap-types.js.map +1 -0
- package/dist/planning/planner.d.ts +421 -4
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +949 -21
- package/dist/planning/planner.js.map +1 -1
- package/dist/playbooks/generic/brainstorming.d.ts +9 -0
- package/dist/playbooks/generic/brainstorming.d.ts.map +1 -0
- package/dist/playbooks/generic/brainstorming.js +105 -0
- package/dist/playbooks/generic/brainstorming.js.map +1 -0
- package/dist/playbooks/generic/code-review.d.ts +11 -0
- package/dist/playbooks/generic/code-review.d.ts.map +1 -0
- package/dist/playbooks/generic/code-review.js +176 -0
- package/dist/playbooks/generic/code-review.js.map +1 -0
- package/dist/playbooks/generic/subagent-execution.d.ts +9 -0
- package/dist/playbooks/generic/subagent-execution.d.ts.map +1 -0
- package/dist/playbooks/generic/subagent-execution.js +68 -0
- package/dist/playbooks/generic/subagent-execution.js.map +1 -0
- package/dist/playbooks/generic/systematic-debugging.d.ts +9 -0
- package/dist/playbooks/generic/systematic-debugging.d.ts.map +1 -0
- package/dist/playbooks/generic/systematic-debugging.js +87 -0
- package/dist/playbooks/generic/systematic-debugging.js.map +1 -0
- package/dist/playbooks/generic/tdd.d.ts +9 -0
- package/dist/playbooks/generic/tdd.d.ts.map +1 -0
- package/dist/playbooks/generic/tdd.js +70 -0
- package/dist/playbooks/generic/tdd.js.map +1 -0
- package/dist/playbooks/generic/verification.d.ts +9 -0
- package/dist/playbooks/generic/verification.d.ts.map +1 -0
- package/dist/playbooks/generic/verification.js +74 -0
- package/dist/playbooks/generic/verification.js.map +1 -0
- package/dist/playbooks/index.d.ts +4 -0
- package/dist/playbooks/index.d.ts.map +1 -0
- package/dist/playbooks/index.js +5 -0
- package/dist/playbooks/index.js.map +1 -0
- package/dist/playbooks/playbook-registry.d.ts +42 -0
- package/dist/playbooks/playbook-registry.d.ts.map +1 -0
- package/dist/playbooks/playbook-registry.js +227 -0
- package/dist/playbooks/playbook-registry.js.map +1 -0
- package/dist/playbooks/playbook-seeder.d.ts +47 -0
- package/dist/playbooks/playbook-seeder.d.ts.map +1 -0
- package/dist/playbooks/playbook-seeder.js +104 -0
- package/dist/playbooks/playbook-seeder.js.map +1 -0
- package/dist/playbooks/playbook-types.d.ts +132 -0
- package/dist/playbooks/playbook-types.d.ts.map +1 -0
- package/dist/playbooks/playbook-types.js +12 -0
- package/dist/playbooks/playbook-types.js.map +1 -0
- package/dist/project/project-registry.d.ts +79 -0
- package/dist/project/project-registry.d.ts.map +1 -0
- package/dist/project/project-registry.js +274 -0
- package/dist/project/project-registry.js.map +1 -0
- package/dist/project/types.d.ts +28 -0
- package/dist/project/types.d.ts.map +1 -0
- package/dist/project/types.js +5 -0
- package/dist/project/types.js.map +1 -0
- package/dist/prompts/index.d.ts +4 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +3 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/parser.d.ts +17 -0
- package/dist/prompts/parser.d.ts.map +1 -0
- package/dist/prompts/parser.js +47 -0
- package/dist/prompts/parser.js.map +1 -0
- package/dist/prompts/template-manager.d.ts +25 -0
- package/dist/prompts/template-manager.d.ts.map +1 -0
- package/dist/prompts/template-manager.js +71 -0
- package/dist/prompts/template-manager.js.map +1 -0
- package/dist/prompts/types.d.ts +26 -0
- package/dist/prompts/types.d.ts.map +1 -0
- package/dist/prompts/types.js +5 -0
- package/dist/prompts/types.js.map +1 -0
- package/dist/runtime/admin-extra-ops.d.ts +15 -0
- package/dist/runtime/admin-extra-ops.d.ts.map +1 -0
- package/dist/runtime/admin-extra-ops.js +595 -0
- package/dist/runtime/admin-extra-ops.js.map +1 -0
- package/dist/runtime/admin-ops.d.ts +15 -0
- package/dist/runtime/admin-ops.d.ts.map +1 -0
- package/dist/runtime/admin-ops.js +329 -0
- package/dist/runtime/admin-ops.js.map +1 -0
- package/dist/runtime/capture-ops.d.ts +15 -0
- package/dist/runtime/capture-ops.d.ts.map +1 -0
- package/dist/runtime/capture-ops.js +363 -0
- package/dist/runtime/capture-ops.js.map +1 -0
- package/dist/runtime/cognee-sync-ops.d.ts +12 -0
- package/dist/runtime/cognee-sync-ops.d.ts.map +1 -0
- package/dist/runtime/cognee-sync-ops.js +55 -0
- package/dist/runtime/cognee-sync-ops.js.map +1 -0
- package/dist/runtime/core-ops.d.ts +9 -3
- package/dist/runtime/core-ops.d.ts.map +1 -1
- package/dist/runtime/core-ops.js +693 -10
- package/dist/runtime/core-ops.js.map +1 -1
- package/dist/runtime/curator-extra-ops.d.ts +9 -0
- package/dist/runtime/curator-extra-ops.d.ts.map +1 -0
- package/dist/runtime/curator-extra-ops.js +71 -0
- package/dist/runtime/curator-extra-ops.js.map +1 -0
- package/dist/runtime/domain-ops.d.ts.map +1 -1
- package/dist/runtime/domain-ops.js +61 -15
- package/dist/runtime/domain-ops.js.map +1 -1
- package/dist/runtime/grading-ops.d.ts +14 -0
- package/dist/runtime/grading-ops.d.ts.map +1 -0
- package/dist/runtime/grading-ops.js +105 -0
- package/dist/runtime/grading-ops.js.map +1 -0
- package/dist/runtime/intake-ops.d.ts +14 -0
- package/dist/runtime/intake-ops.d.ts.map +1 -0
- package/dist/runtime/intake-ops.js +110 -0
- package/dist/runtime/intake-ops.js.map +1 -0
- package/dist/runtime/loop-ops.d.ts +14 -0
- package/dist/runtime/loop-ops.d.ts.map +1 -0
- package/dist/runtime/loop-ops.js +251 -0
- package/dist/runtime/loop-ops.js.map +1 -0
- package/dist/runtime/memory-cross-project-ops.d.ts +12 -0
- package/dist/runtime/memory-cross-project-ops.d.ts.map +1 -0
- package/dist/runtime/memory-cross-project-ops.js +165 -0
- package/dist/runtime/memory-cross-project-ops.js.map +1 -0
- package/dist/runtime/memory-extra-ops.d.ts +13 -0
- package/dist/runtime/memory-extra-ops.d.ts.map +1 -0
- package/dist/runtime/memory-extra-ops.js +173 -0
- package/dist/runtime/memory-extra-ops.js.map +1 -0
- package/dist/runtime/orchestrate-ops.d.ts +17 -0
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -0
- package/dist/runtime/orchestrate-ops.js +246 -0
- package/dist/runtime/orchestrate-ops.js.map +1 -0
- package/dist/runtime/planning-extra-ops.d.ts +25 -0
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -0
- package/dist/runtime/planning-extra-ops.js +663 -0
- package/dist/runtime/planning-extra-ops.js.map +1 -0
- package/dist/runtime/playbook-ops.d.ts +14 -0
- package/dist/runtime/playbook-ops.d.ts.map +1 -0
- package/dist/runtime/playbook-ops.js +141 -0
- package/dist/runtime/playbook-ops.js.map +1 -0
- package/dist/runtime/project-ops.d.ts +15 -0
- package/dist/runtime/project-ops.d.ts.map +1 -0
- package/dist/runtime/project-ops.js +186 -0
- package/dist/runtime/project-ops.js.map +1 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +65 -3
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +29 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/vault-extra-ops.d.ts +10 -0
- package/dist/runtime/vault-extra-ops.d.ts.map +1 -0
- package/dist/runtime/vault-extra-ops.js +536 -0
- package/dist/runtime/vault-extra-ops.js.map +1 -0
- package/dist/telemetry/telemetry.d.ts +48 -0
- package/dist/telemetry/telemetry.d.ts.map +1 -0
- package/dist/telemetry/telemetry.js +87 -0
- package/dist/telemetry/telemetry.js.map +1 -0
- package/dist/vault/playbook.d.ts +34 -0
- package/dist/vault/playbook.d.ts.map +1 -0
- package/dist/vault/playbook.js +60 -0
- package/dist/vault/playbook.js.map +1 -0
- package/dist/vault/vault.d.ts +97 -4
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +424 -65
- package/dist/vault/vault.js.map +1 -1
- package/package.json +7 -3
- package/src/__tests__/admin-extra-ops.test.ts +467 -0
- package/src/__tests__/admin-ops.test.ts +271 -0
- package/src/__tests__/brain-intelligence.test.ts +205 -0
- package/src/__tests__/brain.test.ts +134 -3
- package/src/__tests__/capture-ops.test.ts +509 -0
- package/src/__tests__/cognee-integration.test.ts +80 -0
- package/src/__tests__/cognee-sync-manager.test.ts +103 -0
- package/src/__tests__/core-ops.test.ts +292 -2
- package/src/__tests__/curator-extra-ops.test.ts +381 -0
- package/src/__tests__/domain-ops.test.ts +66 -0
- package/src/__tests__/errors.test.ts +388 -0
- package/src/__tests__/governance.test.ts +522 -0
- package/src/__tests__/grading-ops.test.ts +361 -0
- package/src/__tests__/identity-manager.test.ts +243 -0
- package/src/__tests__/intake-pipeline.test.ts +162 -0
- package/src/__tests__/intent-router.test.ts +222 -0
- package/src/__tests__/logger.test.ts +200 -0
- package/src/__tests__/loop-ops.test.ts +469 -0
- package/src/__tests__/memory-cross-project-ops.test.ts +248 -0
- package/src/__tests__/memory-extra-ops.test.ts +352 -0
- package/src/__tests__/orchestrate-ops.test.ts +289 -0
- package/src/__tests__/persistence.test.ts +225 -0
- package/src/__tests__/planner.test.ts +416 -7
- package/src/__tests__/planning-extra-ops.test.ts +706 -0
- package/src/__tests__/playbook-registry.test.ts +326 -0
- package/src/__tests__/playbook-seeder.test.ts +163 -0
- package/src/__tests__/playbook.test.ts +389 -0
- package/src/__tests__/project-ops.test.ts +381 -0
- package/src/__tests__/template-manager.test.ts +222 -0
- package/src/__tests__/vault-extra-ops.test.ts +482 -0
- package/src/brain/brain.ts +185 -16
- package/src/brain/intelligence.ts +179 -10
- package/src/brain/types.ts +40 -2
- package/src/cognee/client.ts +18 -0
- package/src/cognee/sync-manager.ts +389 -0
- package/src/control/identity-manager.ts +354 -0
- package/src/control/intent-router.ts +326 -0
- package/src/control/types.ts +102 -0
- package/src/curator/curator.ts +295 -1
- package/src/errors/classify.ts +102 -0
- package/src/errors/index.ts +5 -0
- package/src/errors/retry.ts +132 -0
- package/src/errors/types.ts +81 -0
- package/src/governance/governance.ts +698 -0
- package/src/governance/index.ts +18 -0
- package/src/governance/types.ts +111 -0
- package/src/index.ts +213 -2
- package/src/intake/content-classifier.ts +146 -0
- package/src/intake/dedup-gate.ts +92 -0
- package/src/intake/intake-pipeline.ts +503 -0
- package/src/intake/types.ts +69 -0
- package/src/intelligence/loader.ts +1 -1
- package/src/intelligence/types.ts +3 -1
- package/src/logging/logger.ts +154 -0
- package/src/logging/types.ts +21 -0
- package/src/loop/loop-manager.ts +448 -0
- package/src/loop/types.ts +115 -0
- package/src/persistence/index.ts +7 -0
- package/src/persistence/sqlite-provider.ts +62 -0
- package/src/persistence/types.ts +44 -0
- package/src/planning/gap-analysis.ts +775 -0
- package/src/planning/gap-types.ts +61 -0
- package/src/planning/planner.ts +1273 -24
- package/src/playbooks/generic/brainstorming.ts +110 -0
- package/src/playbooks/generic/code-review.ts +181 -0
- package/src/playbooks/generic/subagent-execution.ts +74 -0
- package/src/playbooks/generic/systematic-debugging.ts +92 -0
- package/src/playbooks/generic/tdd.ts +75 -0
- package/src/playbooks/generic/verification.ts +79 -0
- package/src/playbooks/index.ts +27 -0
- package/src/playbooks/playbook-registry.ts +284 -0
- package/src/playbooks/playbook-seeder.ts +119 -0
- package/src/playbooks/playbook-types.ts +162 -0
- package/src/project/project-registry.ts +370 -0
- package/src/project/types.ts +31 -0
- package/src/prompts/index.ts +3 -0
- package/src/prompts/parser.ts +59 -0
- package/src/prompts/template-manager.ts +77 -0
- package/src/prompts/types.ts +28 -0
- package/src/runtime/admin-extra-ops.ts +652 -0
- package/src/runtime/admin-ops.ts +340 -0
- package/src/runtime/capture-ops.ts +404 -0
- package/src/runtime/cognee-sync-ops.ts +63 -0
- package/src/runtime/core-ops.ts +787 -9
- package/src/runtime/curator-extra-ops.ts +85 -0
- package/src/runtime/domain-ops.ts +67 -15
- package/src/runtime/grading-ops.ts +130 -0
- package/src/runtime/intake-ops.ts +126 -0
- package/src/runtime/loop-ops.ts +277 -0
- package/src/runtime/memory-cross-project-ops.ts +191 -0
- package/src/runtime/memory-extra-ops.ts +186 -0
- package/src/runtime/orchestrate-ops.ts +278 -0
- package/src/runtime/planning-extra-ops.ts +718 -0
- package/src/runtime/playbook-ops.ts +169 -0
- package/src/runtime/project-ops.ts +202 -0
- package/src/runtime/runtime.ts +77 -3
- package/src/runtime/types.ts +29 -0
- package/src/runtime/vault-extra-ops.ts +606 -0
- package/src/telemetry/telemetry.ts +118 -0
- package/src/vault/playbook.ts +87 -0
- package/src/vault/vault.ts +575 -98
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
2
|
import { Planner } from '../planning/planner.js';
|
|
3
|
+
import type { PlanGap } from '../planning/gap-types.js';
|
|
4
|
+
import { generateGapId } from '../planning/gap-types.js';
|
|
3
5
|
import { mkdirSync, rmSync } from 'node:fs';
|
|
4
6
|
import { join } from 'node:path';
|
|
5
7
|
import { tmpdir } from 'node:os';
|
|
@@ -93,7 +95,7 @@ describe('Planner', () => {
|
|
|
93
95
|
it('should throw when approving non-draft plan', () => {
|
|
94
96
|
const plan = planner.create({ objective: 'Already approved', scope: 'test' });
|
|
95
97
|
planner.approve(plan.id);
|
|
96
|
-
expect(() => planner.approve(plan.id)).toThrow('
|
|
98
|
+
expect(() => planner.approve(plan.id)).toThrow('Invalid transition');
|
|
97
99
|
});
|
|
98
100
|
|
|
99
101
|
it('should throw for unknown plan', () => {
|
|
@@ -111,7 +113,7 @@ describe('Planner', () => {
|
|
|
111
113
|
|
|
112
114
|
it('should throw when executing non-approved plan', () => {
|
|
113
115
|
const plan = planner.create({ objective: 'Not approved', scope: 'test' });
|
|
114
|
-
expect(() => planner.startExecution(plan.id)).toThrow('
|
|
116
|
+
expect(() => planner.startExecution(plan.id)).toThrow('Invalid transition');
|
|
115
117
|
});
|
|
116
118
|
});
|
|
117
119
|
|
|
@@ -176,17 +178,25 @@ describe('Planner', () => {
|
|
|
176
178
|
});
|
|
177
179
|
|
|
178
180
|
describe('complete', () => {
|
|
179
|
-
it('should transition
|
|
181
|
+
it('should transition reconciling to completed', () => {
|
|
180
182
|
const plan = planner.create({ objective: 'Complete me', scope: 'test' });
|
|
181
183
|
planner.approve(plan.id);
|
|
182
184
|
planner.startExecution(plan.id);
|
|
185
|
+
planner.startReconciliation(plan.id);
|
|
183
186
|
const completed = planner.complete(plan.id);
|
|
184
187
|
expect(completed.status).toBe('completed');
|
|
185
188
|
});
|
|
186
189
|
|
|
187
|
-
it('should throw when completing
|
|
190
|
+
it('should throw when completing from executing (must go through reconciling)', () => {
|
|
191
|
+
const plan = planner.create({ objective: 'Not reconciling', scope: 'test' });
|
|
192
|
+
planner.approve(plan.id);
|
|
193
|
+
planner.startExecution(plan.id);
|
|
194
|
+
expect(() => planner.complete(plan.id)).toThrow('Invalid transition');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should throw when completing from draft', () => {
|
|
188
198
|
const plan = planner.create({ objective: 'Not executing', scope: 'test' });
|
|
189
|
-
expect(() => planner.complete(plan.id)).toThrow('
|
|
199
|
+
expect(() => planner.complete(plan.id)).toThrow('Invalid transition');
|
|
190
200
|
});
|
|
191
201
|
});
|
|
192
202
|
|
|
@@ -208,7 +218,7 @@ describe('Planner', () => {
|
|
|
208
218
|
});
|
|
209
219
|
|
|
210
220
|
describe('getActive', () => {
|
|
211
|
-
it('should return draft, approved, and
|
|
221
|
+
it('should return brainstorming, draft, approved, executing, validating, and reconciling plans', () => {
|
|
212
222
|
planner.create({ objective: 'Draft', scope: 'a' });
|
|
213
223
|
const p2 = planner.create({ objective: 'Approved', scope: 'b' });
|
|
214
224
|
const p3 = planner.create({ objective: 'Executing', scope: 'c' });
|
|
@@ -218,6 +228,7 @@ describe('Planner', () => {
|
|
|
218
228
|
planner.startExecution(p3.id);
|
|
219
229
|
planner.approve(p4.id);
|
|
220
230
|
planner.startExecution(p4.id);
|
|
231
|
+
planner.startReconciliation(p4.id);
|
|
221
232
|
planner.complete(p4.id);
|
|
222
233
|
const active = planner.getActive();
|
|
223
234
|
expect(active).toHaveLength(3);
|
|
@@ -225,8 +236,357 @@ describe('Planner', () => {
|
|
|
225
236
|
});
|
|
226
237
|
});
|
|
227
238
|
|
|
239
|
+
describe('grade', () => {
|
|
240
|
+
it('should grade a well-formed plan highly on first iteration', () => {
|
|
241
|
+
const plan = planner.create({
|
|
242
|
+
objective: 'Implement a Redis caching layer for the API to reduce DB load by 50%',
|
|
243
|
+
scope: 'Backend API services only. Does not include frontend caching or CDN.',
|
|
244
|
+
decisions: [
|
|
245
|
+
'Use Redis because it provides sub-millisecond latency and supports TTL natively',
|
|
246
|
+
'Set TTL to 5 minutes since average data freshness requirement is 10 minutes',
|
|
247
|
+
],
|
|
248
|
+
tasks: [
|
|
249
|
+
{
|
|
250
|
+
title: 'Set up Redis client',
|
|
251
|
+
description: 'Install and configure Redis connection pool',
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
title: 'Add cache middleware',
|
|
255
|
+
description: 'Express middleware for transparent caching',
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
title: 'Add invalidation logic',
|
|
259
|
+
description: 'Purge cache on write operations to ensure consistency',
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
title: 'Write integration tests',
|
|
263
|
+
description: 'Test cache hit/miss scenarios with Redis',
|
|
264
|
+
},
|
|
265
|
+
{ title: 'Add monitoring', description: 'Track and verify cache hit rate metrics' },
|
|
266
|
+
],
|
|
267
|
+
});
|
|
268
|
+
const check = planner.grade(plan.id);
|
|
269
|
+
// Iteration 1: minor gaps are free, so well-formed plan scores very high
|
|
270
|
+
expect(check.score).toBeGreaterThanOrEqual(95);
|
|
271
|
+
expect(check.grade).toMatch(/^A/);
|
|
272
|
+
expect(check.iteration).toBe(1);
|
|
273
|
+
expect(check.checkId).toMatch(/^chk-/);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('should give low score to empty plan', () => {
|
|
277
|
+
const plan = planner.create({ objective: '', scope: '' });
|
|
278
|
+
const check = planner.grade(plan.id);
|
|
279
|
+
// Missing objective (critical=30) + scope (critical=30) + no tasks (critical=30) = 90 deduction
|
|
280
|
+
expect(check.score).toBeLessThanOrEqual(10);
|
|
281
|
+
expect(check.grade).toBe('F');
|
|
282
|
+
expect(check.gaps.length).toBeGreaterThan(0);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('should use severity-weighted scoring', () => {
|
|
286
|
+
// Plan with 1 critical gap (missing tasks) = -30 points
|
|
287
|
+
const plan = planner.create({
|
|
288
|
+
objective: 'Good objective with some detail',
|
|
289
|
+
scope: 'Narrow scope that excludes nothing important',
|
|
290
|
+
});
|
|
291
|
+
const check = planner.grade(plan.id);
|
|
292
|
+
// No tasks = critical (-30), but also minor gaps from completeness/semantic
|
|
293
|
+
// On iteration 1, minor gaps are free, so only critical gap counts
|
|
294
|
+
expect(check.score).toBe(70); // 100 - 30 (no tasks)
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('should detect duplicate task titles', () => {
|
|
298
|
+
const plan = planner.create({
|
|
299
|
+
objective: 'Test duplicate detection in plan grading system',
|
|
300
|
+
scope: 'Testing only, does not affect production',
|
|
301
|
+
decisions: ['Use approach A because it handles edge cases better due to type safety'],
|
|
302
|
+
tasks: [
|
|
303
|
+
{ title: 'Same title', description: 'First task with description' },
|
|
304
|
+
{ title: 'Same title', description: 'Second task with description' },
|
|
305
|
+
{ title: 'Unique title', description: 'Third task with description' },
|
|
306
|
+
],
|
|
307
|
+
});
|
|
308
|
+
const check = planner.grade(plan.id);
|
|
309
|
+
const dupGap = check.gaps.find((g) => g.description.includes('Duplicate'));
|
|
310
|
+
expect(dupGap).toBeDefined();
|
|
311
|
+
expect(dupGap!.category).toBe('semantic-quality');
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('should detect tasks with short/missing descriptions', () => {
|
|
315
|
+
const plan = planner.create({
|
|
316
|
+
objective: 'Test description detection in plan grading system',
|
|
317
|
+
scope: 'Testing only, does not affect production',
|
|
318
|
+
decisions: ['Use assertions because they provide clear feedback on failures'],
|
|
319
|
+
tasks: [
|
|
320
|
+
{ title: 'Task with desc', description: 'Has a proper description' },
|
|
321
|
+
{ title: 'Task without desc', description: '' },
|
|
322
|
+
{ title: 'Another task', description: 'Also has a description' },
|
|
323
|
+
],
|
|
324
|
+
});
|
|
325
|
+
const check = planner.grade(plan.id);
|
|
326
|
+
const descGap = check.gaps.find((g) => g.description.includes('short descriptions'));
|
|
327
|
+
expect(descGap).toBeDefined();
|
|
328
|
+
expect(descGap!.category).toBe('clarity');
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('should track iteration number across multiple grades', () => {
|
|
332
|
+
const plan = planner.create({
|
|
333
|
+
objective: 'Iteration tracking test plan',
|
|
334
|
+
scope: 'Test scope',
|
|
335
|
+
});
|
|
336
|
+
const check1 = planner.grade(plan.id);
|
|
337
|
+
const check2 = planner.grade(plan.id);
|
|
338
|
+
const check3 = planner.grade(plan.id);
|
|
339
|
+
expect(check1.iteration).toBe(1);
|
|
340
|
+
expect(check2.iteration).toBe(2);
|
|
341
|
+
expect(check3.iteration).toBe(3);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('should apply iteration leniency — minor gaps free on iter 1', () => {
|
|
345
|
+
// Plan with only minor gaps: no metrics in objective, no exclusions in scope
|
|
346
|
+
const plan = planner.create({
|
|
347
|
+
objective: 'Build a comprehensive authentication system for the application',
|
|
348
|
+
scope: 'Backend authentication module',
|
|
349
|
+
decisions: ['Use JWT tokens because they are stateless and work well with microservices'],
|
|
350
|
+
tasks: [
|
|
351
|
+
{ title: 'Create auth middleware', description: 'JWT validation middleware for Express' },
|
|
352
|
+
{
|
|
353
|
+
title: 'Add login endpoint',
|
|
354
|
+
description: 'POST /auth/login with credential validation',
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
title: 'Add refresh tokens',
|
|
358
|
+
description: 'Implement token refresh flow with rotation',
|
|
359
|
+
},
|
|
360
|
+
{ title: 'Write auth tests', description: 'Integration tests for all auth endpoints' },
|
|
361
|
+
],
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// Iteration 1: minor gaps free → score should be 100
|
|
365
|
+
const check1 = planner.grade(plan.id);
|
|
366
|
+
expect(check1.score).toBe(100);
|
|
367
|
+
|
|
368
|
+
// Iteration 2: minor gaps at half weight → score slightly lower
|
|
369
|
+
const check2 = planner.grade(plan.id);
|
|
370
|
+
expect(check2.score).toBeLessThan(check1.score);
|
|
371
|
+
|
|
372
|
+
// Iteration 3: minor gaps at full weight → score even lower
|
|
373
|
+
const check3 = planner.grade(plan.id);
|
|
374
|
+
expect(check3.score).toBeLessThanOrEqual(check2.score);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it('should cap category deductions', () => {
|
|
378
|
+
// Plan with many clarity issues (ambiguous words) — capped at 10
|
|
379
|
+
const plan = planner.create({
|
|
380
|
+
objective: 'Maybe perhaps build something simple and easy, possibly soon, etc',
|
|
381
|
+
scope: 'Various things, probably several modules, somehow',
|
|
382
|
+
decisions: ['Use some appropriate approach because it seems good due to various reasons'],
|
|
383
|
+
tasks: [
|
|
384
|
+
{ title: 'Do some stuff', description: 'Maybe implement various things somehow' },
|
|
385
|
+
{ title: 'Maybe test', description: 'Perhaps write some tests probably' },
|
|
386
|
+
{ title: 'Maybe deploy', description: 'Possibly deploy to various environments soon' },
|
|
387
|
+
],
|
|
388
|
+
});
|
|
389
|
+
// Grade on iteration 3 to get full minor weight
|
|
390
|
+
planner.grade(plan.id);
|
|
391
|
+
planner.grade(plan.id);
|
|
392
|
+
const check3 = planner.grade(plan.id);
|
|
393
|
+
// Clarity category should be capped at 10 even though there are many ambiguous words
|
|
394
|
+
// Without cap, multiple minor clarity gaps (3x2=6, but also semantic-quality gaps)
|
|
395
|
+
// The key assertion: score shouldn't be destroyed by clarity alone
|
|
396
|
+
expect(check3.score).toBeGreaterThanOrEqual(50);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it('should store check in plan history', () => {
|
|
400
|
+
const plan = planner.create({
|
|
401
|
+
objective: 'History test plan objective',
|
|
402
|
+
scope: 'test scope',
|
|
403
|
+
});
|
|
404
|
+
planner.grade(plan.id);
|
|
405
|
+
planner.grade(plan.id);
|
|
406
|
+
const history = planner.getCheckHistory(plan.id);
|
|
407
|
+
expect(history).toHaveLength(2);
|
|
408
|
+
expect(history[0].checkId).not.toBe(history[1].checkId);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it('should persist latestCheck', () => {
|
|
412
|
+
const plan = planner.create({
|
|
413
|
+
objective: 'Persist test plan objective',
|
|
414
|
+
scope: 'test scope',
|
|
415
|
+
});
|
|
416
|
+
const check = planner.grade(plan.id);
|
|
417
|
+
const latest = planner.getLatestCheck(plan.id);
|
|
418
|
+
expect(latest).not.toBeNull();
|
|
419
|
+
expect(latest!.checkId).toBe(check.checkId);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('should detect circular dependencies', () => {
|
|
423
|
+
const plan = planner.create({
|
|
424
|
+
objective: 'Circular dependency detection test plan',
|
|
425
|
+
scope: 'Test scope only, does not affect production',
|
|
426
|
+
decisions: ['Test with circular deps because it validates the analysis engine'],
|
|
427
|
+
tasks: [
|
|
428
|
+
{ title: 'Task A', description: 'First task in the cycle' },
|
|
429
|
+
{ title: 'Task B', description: 'Second task in the cycle' },
|
|
430
|
+
{ title: 'Task C', description: 'Third task (not in cycle)' },
|
|
431
|
+
],
|
|
432
|
+
});
|
|
433
|
+
// Manually create circular deps
|
|
434
|
+
const p = planner.get(plan.id)!;
|
|
435
|
+
p.tasks[0].dependsOn = ['task-2'];
|
|
436
|
+
p.tasks[1].dependsOn = ['task-1'];
|
|
437
|
+
const check = planner.grade(plan.id);
|
|
438
|
+
const circGap = check.gaps.find((g) => g.description.includes('Circular'));
|
|
439
|
+
expect(circGap).toBeDefined();
|
|
440
|
+
expect(circGap!.severity).toBe('critical');
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
it('should use correct grade thresholds: A+=95, A=90, B=80, C=70, D=60', () => {
|
|
444
|
+
// We can verify by creating plans with known gap profiles
|
|
445
|
+
// Plan with 1 major gap = score 85 → grade B (80-89)
|
|
446
|
+
const plan = planner.create({
|
|
447
|
+
objective: 'Test threshold plan with a good objective description',
|
|
448
|
+
scope: 'Narrow scope, does not include anything beyond testing',
|
|
449
|
+
decisions: [], // no decisions = major gap from semantic-quality (-15)
|
|
450
|
+
tasks: [
|
|
451
|
+
{ title: 'Task 1', description: 'First detailed task description' },
|
|
452
|
+
{ title: 'Task 2', description: 'Second detailed task description' },
|
|
453
|
+
{ title: 'Task 3', description: 'Third detailed task description' },
|
|
454
|
+
],
|
|
455
|
+
});
|
|
456
|
+
const check = planner.grade(plan.id);
|
|
457
|
+
// 1 major gap (no decisions for 3 tasks) = -15, iter 1 minor gaps free
|
|
458
|
+
expect(check.score).toBe(85);
|
|
459
|
+
expect(check.grade).toBe('B');
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
describe('meetsGrade', () => {
|
|
464
|
+
it('should return true when plan meets target grade', () => {
|
|
465
|
+
const plan = planner.create({
|
|
466
|
+
objective: 'Build a comprehensive feature for the testing module',
|
|
467
|
+
scope: 'Testing module only, does not include deployment',
|
|
468
|
+
decisions: ['Use vitest because it integrates well with TypeScript due to native support'],
|
|
469
|
+
tasks: [
|
|
470
|
+
{ title: 'Write unit tests', description: 'Cover all edge cases in auth module' },
|
|
471
|
+
{ title: 'Write integration tests', description: 'End-to-end API tests for auth flow' },
|
|
472
|
+
{ title: 'Add CI pipeline', description: 'Run tests on every PR automatically' },
|
|
473
|
+
{ title: 'Add coverage report', description: 'Track and verify code coverage metrics' },
|
|
474
|
+
],
|
|
475
|
+
});
|
|
476
|
+
const result = planner.meetsGrade(plan.id, 'B');
|
|
477
|
+
expect(result.meets).toBe(true);
|
|
478
|
+
expect(result.check.score).toBeGreaterThanOrEqual(80);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
it('should return false when plan does not meet target grade', () => {
|
|
482
|
+
const plan = planner.create({ objective: '', scope: '' });
|
|
483
|
+
const result = planner.meetsGrade(plan.id, 'A+');
|
|
484
|
+
expect(result.meets).toBe(false);
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
describe('getCheckHistory', () => {
|
|
489
|
+
it('should return empty array for plan with no checks', () => {
|
|
490
|
+
const plan = planner.create({ objective: 'No checks plan', scope: 'test scope' });
|
|
491
|
+
expect(planner.getCheckHistory(plan.id)).toEqual([]);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
it('should throw for unknown plan', () => {
|
|
495
|
+
expect(() => planner.getCheckHistory('plan-nonexistent')).toThrow('not found');
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
describe('getLatestCheck', () => {
|
|
500
|
+
it('should return null for plan with no checks', () => {
|
|
501
|
+
const plan = planner.create({ objective: 'No checks plan', scope: 'test scope' });
|
|
502
|
+
expect(planner.getLatestCheck(plan.id)).toBeNull();
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it('should throw for unknown plan', () => {
|
|
506
|
+
expect(() => planner.getLatestCheck('plan-nonexistent')).toThrow('not found');
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
describe('custom gap analysis passes', () => {
|
|
511
|
+
it('should run custom passes alongside built-in ones', () => {
|
|
512
|
+
const customPass = (plan: { objective: string }): PlanGap[] => {
|
|
513
|
+
if (plan.objective.includes('TODO')) {
|
|
514
|
+
return [
|
|
515
|
+
{
|
|
516
|
+
id: generateGapId(),
|
|
517
|
+
severity: 'major',
|
|
518
|
+
category: 'semantic-quality',
|
|
519
|
+
description: 'Objective contains TODO — not ready for grading.',
|
|
520
|
+
recommendation: 'Resolve all TODOs before grading the plan.',
|
|
521
|
+
location: 'objective',
|
|
522
|
+
_trigger: 'custom_todo_check',
|
|
523
|
+
},
|
|
524
|
+
];
|
|
525
|
+
}
|
|
526
|
+
return [];
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
const customPlanner = new Planner(join(tempDir, 'custom-plans.json'), {
|
|
530
|
+
customPasses: [customPass],
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
// Plan with TODO should get the custom gap
|
|
534
|
+
const plan = customPlanner.create({
|
|
535
|
+
objective: 'TODO: flesh out this objective for the project',
|
|
536
|
+
scope: 'Backend services only. Does not include frontend.',
|
|
537
|
+
decisions: ['Use TypeScript because it provides type safety due to static analysis'],
|
|
538
|
+
tasks: [
|
|
539
|
+
{ title: 'Task A', description: 'First implementation task' },
|
|
540
|
+
{ title: 'Task B', description: 'Second implementation task' },
|
|
541
|
+
{ title: 'Task C', description: 'Third implementation task' },
|
|
542
|
+
],
|
|
543
|
+
});
|
|
544
|
+
const check = customPlanner.grade(plan.id);
|
|
545
|
+
const todoGap = check.gaps.find((g) => g._trigger === 'custom_todo_check');
|
|
546
|
+
expect(todoGap).toBeDefined();
|
|
547
|
+
expect(todoGap!.severity).toBe('major');
|
|
548
|
+
// Score should reflect the -15 from the major custom gap
|
|
549
|
+
expect(check.score).toBeLessThan(100);
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
it('should not fire custom gaps when condition is not met', () => {
|
|
553
|
+
const customPass = (plan: { objective: string }): PlanGap[] => {
|
|
554
|
+
if (plan.objective.includes('TODO')) {
|
|
555
|
+
return [
|
|
556
|
+
{
|
|
557
|
+
id: generateGapId(),
|
|
558
|
+
severity: 'major',
|
|
559
|
+
category: 'semantic-quality',
|
|
560
|
+
description: 'Contains TODO',
|
|
561
|
+
recommendation: 'Fix it',
|
|
562
|
+
},
|
|
563
|
+
];
|
|
564
|
+
}
|
|
565
|
+
return [];
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
const customPlanner = new Planner(join(tempDir, 'custom-plans2.json'), {
|
|
569
|
+
customPasses: [customPass],
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
const plan = customPlanner.create({
|
|
573
|
+
objective: 'Build a clean authentication system for the API endpoints',
|
|
574
|
+
scope: 'Backend services only. Does not include frontend or mobile.',
|
|
575
|
+
decisions: ['Use JWT because it is stateless and works with microservices'],
|
|
576
|
+
tasks: [
|
|
577
|
+
{ title: 'Auth middleware', description: 'Create JWT validation middleware' },
|
|
578
|
+
{ title: 'Login endpoint', description: 'POST /auth/login with credentials' },
|
|
579
|
+
{ title: 'Refresh tokens', description: 'Token refresh flow with rotation' },
|
|
580
|
+
],
|
|
581
|
+
});
|
|
582
|
+
const check = customPlanner.grade(plan.id);
|
|
583
|
+
const todoGap = check.gaps.find((g) => g.description.includes('TODO'));
|
|
584
|
+
expect(todoGap).toBeUndefined();
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
|
|
228
588
|
describe('full lifecycle', () => {
|
|
229
|
-
it('should support draft → approved → executing → completed with tasks', () => {
|
|
589
|
+
it('should support draft → approved → executing → reconciling → completed with tasks', () => {
|
|
230
590
|
const plan = planner.create({
|
|
231
591
|
objective: 'Full lifecycle test',
|
|
232
592
|
scope: 'integration',
|
|
@@ -251,11 +611,60 @@ describe('Planner', () => {
|
|
|
251
611
|
planner.updateTask(plan.id, 'task-2', 'completed');
|
|
252
612
|
planner.updateTask(plan.id, 'task-3', 'skipped');
|
|
253
613
|
|
|
614
|
+
planner.startReconciliation(plan.id);
|
|
615
|
+
expect(planner.get(plan.id)!.status).toBe('reconciling');
|
|
616
|
+
|
|
254
617
|
const final = planner.complete(plan.id);
|
|
255
618
|
expect(final.status).toBe('completed');
|
|
256
619
|
expect(final.tasks[0].status).toBe('completed');
|
|
257
620
|
expect(final.tasks[1].status).toBe('completed');
|
|
258
621
|
expect(final.tasks[2].status).toBe('skipped');
|
|
259
622
|
});
|
|
623
|
+
|
|
624
|
+
it('should support brainstorming → draft → approved → executing lifecycle', () => {
|
|
625
|
+
const plan = planner.create({
|
|
626
|
+
objective: 'Brainstorming lifecycle test',
|
|
627
|
+
scope: 'integration',
|
|
628
|
+
initialStatus: 'brainstorming',
|
|
629
|
+
});
|
|
630
|
+
expect(plan.status).toBe('brainstorming');
|
|
631
|
+
|
|
632
|
+
planner.promoteToDraft(plan.id);
|
|
633
|
+
expect(planner.get(plan.id)!.status).toBe('draft');
|
|
634
|
+
|
|
635
|
+
planner.approve(plan.id);
|
|
636
|
+
expect(planner.get(plan.id)!.status).toBe('approved');
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
it('should support validating state', () => {
|
|
640
|
+
const plan = planner.create({
|
|
641
|
+
objective: 'Validation lifecycle test',
|
|
642
|
+
scope: 'integration',
|
|
643
|
+
tasks: [{ title: 'Task 1', description: 'Test task' }],
|
|
644
|
+
});
|
|
645
|
+
planner.approve(plan.id);
|
|
646
|
+
planner.startExecution(plan.id);
|
|
647
|
+
planner.startValidation(plan.id);
|
|
648
|
+
expect(planner.get(plan.id)!.status).toBe('validating');
|
|
649
|
+
|
|
650
|
+
// Can update tasks during validation
|
|
651
|
+
planner.updateTask(plan.id, 'task-1', 'completed');
|
|
652
|
+
|
|
653
|
+
// Can go back to executing from validating
|
|
654
|
+
planner.startExecution(plan.id);
|
|
655
|
+
expect(planner.get(plan.id)!.status).toBe('executing');
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
it('should support archiving completed plans', () => {
|
|
659
|
+
const plan = planner.create({ objective: 'Archive test', scope: 'test' });
|
|
660
|
+
planner.approve(plan.id);
|
|
661
|
+
planner.startExecution(plan.id);
|
|
662
|
+
planner.startReconciliation(plan.id);
|
|
663
|
+
planner.complete(plan.id);
|
|
664
|
+
|
|
665
|
+
const archived = planner.archive();
|
|
666
|
+
expect(archived).toHaveLength(1);
|
|
667
|
+
expect(archived[0].status).toBe('archived');
|
|
668
|
+
});
|
|
260
669
|
});
|
|
261
670
|
});
|