@soleri/core 9.2.0 → 9.3.1
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/build.flow.yaml +8 -9
- package/data/flows/deliver.flow.yaml +9 -10
- package/data/flows/design.flow.yaml +3 -4
- package/data/flows/enhance.flow.yaml +5 -6
- package/data/flows/explore.flow.yaml +3 -4
- package/data/flows/fix.flow.yaml +5 -6
- package/data/flows/plan.flow.yaml +4 -5
- package/data/flows/review.flow.yaml +3 -4
- package/dist/curator/curator.d.ts.map +1 -1
- package/dist/curator/curator.js +98 -22
- package/dist/curator/curator.js.map +1 -1
- package/dist/engine/bin/soleri-engine.js.map +1 -1
- package/dist/engine/module-manifest.d.ts +2 -0
- package/dist/engine/module-manifest.d.ts.map +1 -1
- package/dist/engine/module-manifest.js +136 -1
- package/dist/engine/module-manifest.js.map +1 -1
- package/dist/engine/register-engine.d.ts.map +1 -1
- package/dist/engine/register-engine.js +25 -1
- package/dist/engine/register-engine.js.map +1 -1
- package/dist/flows/gate-evaluator.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/operator/operator-profile.d.ts.map +1 -1
- package/dist/operator/operator-profile.js +11 -5
- package/dist/operator/operator-profile.js.map +1 -1
- package/dist/operator/operator-signals.d.ts.map +1 -1
- package/dist/operator/operator-signals.js.map +1 -1
- package/dist/planning/evidence-collector.js.map +1 -1
- package/dist/planning/gap-passes.d.ts.map +1 -1
- package/dist/planning/gap-passes.js +23 -6
- package/dist/planning/gap-passes.js.map +1 -1
- package/dist/planning/gap-patterns.d.ts.map +1 -1
- package/dist/planning/gap-patterns.js +57 -11
- package/dist/planning/gap-patterns.js.map +1 -1
- package/dist/planning/github-projection.d.ts.map +1 -1
- package/dist/planning/github-projection.js +39 -20
- package/dist/planning/github-projection.js.map +1 -1
- package/dist/planning/impact-analyzer.d.ts.map +1 -1
- package/dist/planning/impact-analyzer.js +20 -18
- package/dist/planning/impact-analyzer.js.map +1 -1
- package/dist/planning/plan-lifecycle.d.ts.map +1 -1
- package/dist/planning/plan-lifecycle.js +22 -9
- package/dist/planning/plan-lifecycle.js.map +1 -1
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +60 -17
- package/dist/planning/planner.js.map +1 -1
- package/dist/planning/rationalization-detector.d.ts.map +1 -1
- package/dist/planning/rationalization-detector.js.map +1 -1
- package/dist/planning/reconciliation-engine.d.ts.map +1 -1
- package/dist/planning/reconciliation-engine.js.map +1 -1
- package/dist/planning/task-complexity-assessor.d.ts +42 -0
- package/dist/planning/task-complexity-assessor.d.ts.map +1 -0
- package/dist/planning/task-complexity-assessor.js +132 -0
- package/dist/planning/task-complexity-assessor.js.map +1 -0
- package/dist/planning/task-verifier.d.ts.map +1 -1
- package/dist/planning/task-verifier.js +14 -6
- package/dist/planning/task-verifier.js.map +1 -1
- package/dist/runtime/admin-ops.d.ts.map +1 -1
- package/dist/runtime/admin-ops.js +18 -0
- package/dist/runtime/admin-ops.js.map +1 -1
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
- package/dist/runtime/admin-setup-ops.js +2 -1
- package/dist/runtime/admin-setup-ops.js.map +1 -1
- package/dist/runtime/branching-ops.d.ts +12 -0
- package/dist/runtime/branching-ops.d.ts.map +1 -0
- package/dist/runtime/branching-ops.js +100 -0
- package/dist/runtime/branching-ops.js.map +1 -0
- package/dist/runtime/context-health.d.ts.map +1 -1
- package/dist/runtime/context-health.js.map +1 -1
- package/dist/runtime/facades/branching-facade.d.ts +7 -0
- package/dist/runtime/facades/branching-facade.d.ts.map +1 -0
- package/dist/runtime/facades/branching-facade.js +8 -0
- package/dist/runtime/facades/branching-facade.js.map +1 -0
- package/dist/runtime/facades/chat-service-ops.d.ts.map +1 -1
- package/dist/runtime/facades/chat-service-ops.js +3 -1
- package/dist/runtime/facades/chat-service-ops.js.map +1 -1
- package/dist/runtime/facades/chat-transport-ops.d.ts.map +1 -1
- package/dist/runtime/facades/chat-transport-ops.js.map +1 -1
- package/dist/runtime/facades/index.d.ts.map +1 -1
- package/dist/runtime/facades/index.js +42 -0
- package/dist/runtime/facades/index.js.map +1 -1
- package/dist/runtime/facades/intake-facade.d.ts +9 -0
- package/dist/runtime/facades/intake-facade.d.ts.map +1 -0
- package/dist/runtime/facades/intake-facade.js +11 -0
- package/dist/runtime/facades/intake-facade.js.map +1 -0
- package/dist/runtime/facades/links-facade.d.ts +9 -0
- package/dist/runtime/facades/links-facade.d.ts.map +1 -0
- package/dist/runtime/facades/links-facade.js +10 -0
- package/dist/runtime/facades/links-facade.js.map +1 -0
- package/dist/runtime/facades/operator-facade.d.ts.map +1 -1
- package/dist/runtime/facades/operator-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +4 -1
- package/dist/runtime/facades/plan-facade.js.map +1 -1
- package/dist/runtime/facades/tier-facade.d.ts +7 -0
- package/dist/runtime/facades/tier-facade.d.ts.map +1 -0
- package/dist/runtime/facades/tier-facade.js +8 -0
- package/dist/runtime/facades/tier-facade.js.map +1 -0
- package/dist/runtime/facades/vault-facade.d.ts +9 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +44 -187
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/github-integration.d.ts.map +1 -1
- package/dist/runtime/github-integration.js +11 -4
- package/dist/runtime/github-integration.js.map +1 -1
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
- package/dist/runtime/orchestrate-ops.js +75 -42
- package/dist/runtime/orchestrate-ops.js.map +1 -1
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
- package/dist/runtime/planning-extra-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +3 -1
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/session-briefing.d.ts.map +1 -1
- package/dist/runtime/session-briefing.js +5 -1
- package/dist/runtime/session-briefing.js.map +1 -1
- package/dist/runtime/tier-ops.d.ts +13 -0
- package/dist/runtime/tier-ops.d.ts.map +1 -0
- package/dist/runtime/tier-ops.js +110 -0
- package/dist/runtime/tier-ops.js.map +1 -0
- package/dist/skills/sync-skills.d.ts.map +1 -1
- package/dist/skills/sync-skills.js +1 -1
- package/dist/skills/sync-skills.js.map +1 -1
- package/dist/vault/linking.d.ts.map +1 -1
- package/dist/vault/linking.js +41 -5
- package/dist/vault/linking.js.map +1 -1
- package/dist/vault/vault-entries.d.ts.map +1 -1
- package/dist/vault/vault-entries.js +68 -26
- package/dist/vault/vault-entries.js.map +1 -1
- package/dist/vault/vault-maintenance.d.ts.map +1 -1
- package/dist/vault/vault-maintenance.js +6 -2
- package/dist/vault/vault-maintenance.js.map +1 -1
- package/dist/vault/vault-markdown-sync.d.ts.map +1 -1
- package/dist/vault/vault-markdown-sync.js.map +1 -1
- package/dist/vault/vault-memories.d.ts.map +1 -1
- package/dist/vault/vault-memories.js +3 -1
- package/dist/vault/vault-memories.js.map +1 -1
- package/dist/vault/vault-schema.js +36 -10
- package/dist/vault/vault-schema.js.map +1 -1
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +5 -1
- package/dist/vault/vault.js.map +1 -1
- package/package.json +7 -7
- package/src/agency/agency-manager.test.ts +60 -40
- package/src/agency/default-rules.test.ts +17 -9
- package/src/capabilities/registry.test.ts +2 -12
- package/src/chat/agent-loop.test.ts +33 -43
- package/src/chat/mcp-bridge.test.ts +7 -2
- package/src/claudemd/inject.test.ts +2 -12
- package/src/context/context-engine.test.ts +96 -51
- package/src/control/intent-router.test.ts +3 -3
- package/src/curator/classifier.test.ts +14 -8
- package/src/curator/contradiction-detector.test.ts +30 -5
- package/src/curator/curator.ts +278 -56
- package/src/curator/duplicate-detector.test.ts +77 -15
- package/src/curator/quality-gate.test.ts +71 -31
- package/src/curator/tag-manager.test.ts +12 -4
- package/src/domain-packs/knowledge-installer.test.ts +2 -10
- package/src/domain-packs/token-resolver.test.ts +1 -3
- package/src/domain-packs/types.test.ts +16 -2
- package/src/enforcement/registry.test.ts +2 -8
- package/src/engine/bin/soleri-engine.ts +3 -1
- package/src/engine/module-manifest.test.ts +48 -4
- package/src/engine/module-manifest.ts +138 -1
- package/src/engine/register-engine.test.ts +6 -1
- package/src/engine/register-engine.ts +26 -3
- package/src/errors/classify.test.ts +6 -2
- package/src/errors/retry.test.ts +1 -4
- package/src/facades/facade-factory.test.ts +110 -64
- package/src/flows/epilogue.test.ts +16 -10
- package/src/flows/gate-evaluator.test.ts +12 -6
- package/src/flows/gate-evaluator.ts +1 -3
- package/src/governance/governance.test.ts +137 -21
- package/src/health/health-registry.test.ts +8 -1
- package/src/index.ts +8 -0
- package/src/intake/content-classifier.test.ts +121 -51
- package/src/intake/dedup-gate.test.ts +38 -22
- package/src/intake/intake-pipeline.test.ts +5 -3
- package/src/intake/text-ingester.test.ts +26 -20
- package/src/llm/key-pool.test.ts +1 -3
- package/src/llm/llm-client.test.ts +1 -4
- package/src/llm/oauth-discovery.test.ts +16 -16
- package/src/llm/utils.test.ts +62 -18
- package/src/logging/logger.test.ts +4 -1
- package/src/loop/loop-manager.test.ts +2 -6
- package/src/migrations/migration-runner.edge-cases.test.ts +2 -7
- package/src/operator/operator-profile-extended.test.ts +15 -5
- package/src/operator/operator-profile.test.ts +26 -8
- package/src/operator/operator-profile.ts +38 -22
- package/src/operator/operator-signals-extended.test.ts +35 -23
- package/src/operator/operator-signals.test.ts +6 -10
- package/src/operator/operator-signals.ts +2 -1
- package/src/operator/prompts/hook-precompact-operator-dispatch.md +10 -6
- package/src/operator/prompts/subagent-soft-signal-extractor.md +5 -0
- package/src/operator/prompts/subagent-synthesis-cognition.md +19 -10
- package/src/operator/prompts/subagent-synthesis-communication.md +13 -7
- package/src/operator/prompts/subagent-synthesis-technical.md +19 -9
- package/src/operator/prompts/subagent-synthesis-trust.md +27 -21
- package/src/persona/defaults.test.ts +1 -5
- package/src/planning/evidence-collector.test.ts +147 -38
- package/src/planning/evidence-collector.ts +1 -4
- package/src/planning/gap-analysis-alternatives.test.ts +41 -11
- package/src/planning/gap-passes.test.ts +215 -33
- package/src/planning/gap-passes.ts +115 -46
- package/src/planning/gap-patterns.test.ts +87 -13
- package/src/planning/gap-patterns.ts +114 -31
- package/src/planning/github-projection.test.ts +6 -1
- package/src/planning/github-projection.ts +41 -20
- package/src/planning/impact-analyzer.test.ts +10 -23
- package/src/planning/impact-analyzer.ts +33 -46
- package/src/planning/plan-lifecycle.test.ts +103 -36
- package/src/planning/plan-lifecycle.ts +49 -18
- package/src/planning/planner.test.ts +12 -2
- package/src/planning/planner.ts +198 -58
- package/src/planning/rationalization-detector.test.ts +5 -20
- package/src/planning/rationalization-detector.ts +14 -16
- package/src/planning/reconciliation-engine.test.ts +20 -3
- package/src/planning/reconciliation-engine.ts +1 -2
- package/src/planning/task-complexity-assessor.test.ts +298 -0
- package/src/planning/task-complexity-assessor.ts +183 -0
- package/src/planning/task-verifier.test.ts +59 -27
- package/src/planning/task-verifier.ts +15 -9
- package/src/playbooks/playbook-executor.test.ts +1 -3
- package/src/plugins/plugin-loader.test.ts +19 -14
- package/src/plugins/plugin-registry.test.ts +45 -33
- package/src/project/project-registry.test.ts +23 -12
- package/src/prompts/template-manager.test.ts +4 -1
- package/src/queue/job-queue.test.ts +10 -14
- package/src/runtime/admin-extra-ops.test.ts +5 -19
- package/src/runtime/admin-ops.test.ts +22 -1
- package/src/runtime/admin-ops.ts +19 -0
- package/src/runtime/admin-setup-ops.test.ts +3 -4
- package/src/runtime/admin-setup-ops.ts +9 -2
- package/src/runtime/archive-ops.test.ts +4 -1
- package/src/runtime/branching-ops.test.ts +144 -0
- package/src/runtime/branching-ops.ts +107 -0
- package/src/runtime/capture-ops.test.ts +7 -21
- package/src/runtime/chain-ops.test.ts +16 -6
- package/src/runtime/claude-md-helpers.test.ts +1 -3
- package/src/runtime/context-health.test.ts +1 -3
- package/src/runtime/context-health.ts +1 -3
- package/src/runtime/curator-extra-ops.test.ts +3 -1
- package/src/runtime/domain-ops.test.ts +46 -36
- package/src/runtime/facades/admin-facade.test.ts +1 -4
- package/src/runtime/facades/archive-facade.test.ts +21 -7
- package/src/runtime/facades/brain-facade.test.ts +176 -72
- package/src/runtime/facades/branching-facade.test.ts +43 -0
- package/src/runtime/facades/branching-facade.ts +11 -0
- package/src/runtime/facades/chat-facade.test.ts +81 -28
- package/src/runtime/facades/chat-service-ops.test.ts +178 -73
- package/src/runtime/facades/chat-service-ops.ts +3 -1
- package/src/runtime/facades/chat-session-ops.test.ts +25 -10
- package/src/runtime/facades/chat-transport-ops.test.ts +101 -34
- package/src/runtime/facades/chat-transport-ops.ts +0 -1
- package/src/runtime/facades/context-facade.test.ts +19 -4
- package/src/runtime/facades/control-facade.test.ts +3 -3
- package/src/runtime/facades/index.ts +42 -0
- package/src/runtime/facades/intake-facade.test.ts +215 -0
- package/src/runtime/facades/intake-facade.ts +14 -0
- package/src/runtime/facades/links-facade.test.ts +203 -0
- package/src/runtime/facades/links-facade.ts +13 -0
- package/src/runtime/facades/loop-facade.test.ts +22 -5
- package/src/runtime/facades/memory-facade.test.ts +19 -5
- package/src/runtime/facades/operator-facade.test.ts +17 -4
- package/src/runtime/facades/operator-facade.ts +11 -3
- package/src/runtime/facades/orchestrate-facade.test.ts +7 -1
- package/src/runtime/facades/plan-facade.test.ts +29 -12
- package/src/runtime/facades/plan-facade.ts +7 -2
- package/src/runtime/facades/tier-facade.test.ts +47 -0
- package/src/runtime/facades/tier-facade.ts +11 -0
- package/src/runtime/facades/vault-facade.test.ts +174 -242
- package/src/runtime/facades/vault-facade.ts +55 -199
- package/src/runtime/github-integration.ts +11 -8
- package/src/runtime/grading-ops.test.ts +39 -8
- package/src/runtime/intake-ops.test.ts +69 -16
- package/src/runtime/loop-ops.test.ts +16 -6
- package/src/runtime/memory-cross-project-ops.test.ts +25 -14
- package/src/runtime/orchestrate-ops.test.ts +204 -0
- package/src/runtime/orchestrate-ops.ts +103 -65
- package/src/runtime/pack-ops.test.ts +23 -6
- package/src/runtime/planning-extra-ops.test.ts +17 -7
- package/src/runtime/planning-extra-ops.ts +3 -1
- package/src/runtime/playbook-ops.test.ts +26 -3
- package/src/runtime/plugin-ops.test.ts +83 -25
- package/src/runtime/project-ops.test.ts +26 -6
- package/src/runtime/runtime.ts +3 -1
- package/src/runtime/session-briefing.test.ts +183 -54
- package/src/runtime/session-briefing.ts +8 -2
- package/src/runtime/sync-ops.test.ts +3 -12
- package/src/runtime/telemetry-ops.test.ts +31 -6
- package/src/runtime/tier-ops.test.ts +159 -0
- package/src/runtime/tier-ops.ts +119 -0
- package/src/runtime/vault-extra-ops.test.ts +32 -8
- package/src/runtime/vault-sharing-ops.test.ts +1 -4
- package/src/skills/sync-skills.ts +2 -12
- package/src/transport/ws-server.test.ts +7 -4
- package/src/vault/__tests__/vault-characterization.test.ts +492 -81
- package/src/vault/linking.test.ts +50 -17
- package/src/vault/linking.ts +48 -7
- package/src/vault/obsidian-sync.test.ts +6 -3
- package/src/vault/scope-detector.test.ts +1 -3
- package/src/vault/vault-branching.test.ts +9 -7
- package/src/vault/vault-entries.ts +209 -65
- package/src/vault/vault-maintenance.ts +7 -12
- package/src/vault/vault-manager.test.ts +10 -10
- package/src/vault/vault-markdown-sync.ts +4 -1
- package/src/vault/vault-memories.ts +7 -7
- package/src/vault/vault-scaling.test.ts +5 -5
- package/src/vault/vault-schema.ts +72 -15
- package/src/vault/vault.ts +55 -9
- package/src/brain/strength-scorer.ts +0 -404
- package/src/engine/index.ts +0 -21
- package/src/persona/index.ts +0 -9
- package/src/vault/vault-interfaces.ts +0 -56
|
@@ -31,21 +31,20 @@ export interface ImpactReport {
|
|
|
31
31
|
// Constants
|
|
32
32
|
// ---------------------------------------------------------------------------
|
|
33
33
|
|
|
34
|
-
const CODE_EXTENSIONS = new Set([
|
|
35
|
-
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
|
|
36
|
-
'.vue', '.svelte',
|
|
37
|
-
]);
|
|
34
|
+
const CODE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.vue', '.svelte']);
|
|
38
35
|
|
|
39
|
-
const TEST_PATTERNS = [
|
|
40
|
-
/\.test\./,
|
|
41
|
-
/\.spec\./,
|
|
42
|
-
/__tests__/,
|
|
43
|
-
/\.stories\./,
|
|
44
|
-
];
|
|
36
|
+
const TEST_PATTERNS = [/\.test\./, /\.spec\./, /__tests__/, /\.stories\./];
|
|
45
37
|
|
|
46
38
|
const SKIP_DIRS = new Set([
|
|
47
|
-
'node_modules',
|
|
48
|
-
'.
|
|
39
|
+
'node_modules',
|
|
40
|
+
'.git',
|
|
41
|
+
'dist',
|
|
42
|
+
'build',
|
|
43
|
+
'coverage',
|
|
44
|
+
'.next',
|
|
45
|
+
'.nuxt',
|
|
46
|
+
'.svelte-kit',
|
|
47
|
+
'.turbo',
|
|
49
48
|
]);
|
|
50
49
|
|
|
51
50
|
const MAX_FILES = 5000;
|
|
@@ -58,11 +57,7 @@ export class ImpactAnalyzer {
|
|
|
58
57
|
/**
|
|
59
58
|
* Analyze the downstream impact of modified files.
|
|
60
59
|
*/
|
|
61
|
-
analyzeImpact(
|
|
62
|
-
modifiedFiles: string[],
|
|
63
|
-
projectPath: string,
|
|
64
|
-
planScope?: string[],
|
|
65
|
-
): ImpactReport {
|
|
60
|
+
analyzeImpact(modifiedFiles: string[], projectPath: string, planScope?: string[]): ImpactReport {
|
|
66
61
|
if (modifiedFiles.length === 0 || !existsSync(projectPath)) {
|
|
67
62
|
return emptyReport(modifiedFiles);
|
|
68
63
|
}
|
|
@@ -72,11 +67,7 @@ export class ImpactAnalyzer {
|
|
|
72
67
|
const untestedConsumers = filterUntested(consumers);
|
|
73
68
|
const scopeViolations = detectScopeViolations(modifiedFiles, planScope);
|
|
74
69
|
const riskLevel = assessRisk(consumers.length);
|
|
75
|
-
const recommendations = buildRecommendations(
|
|
76
|
-
consumers,
|
|
77
|
-
untestedConsumers,
|
|
78
|
-
scopeViolations,
|
|
79
|
-
);
|
|
70
|
+
const recommendations = buildRecommendations(consumers, untestedConsumers, scopeViolations);
|
|
80
71
|
|
|
81
72
|
return {
|
|
82
73
|
modifiedFiles,
|
|
@@ -166,18 +157,17 @@ function findConsumers(
|
|
|
166
157
|
/**
|
|
167
158
|
* Build regex-friendly stems from modified file paths.
|
|
168
159
|
*/
|
|
169
|
-
function buildImportPatterns(
|
|
170
|
-
modifiedFiles
|
|
171
|
-
|
|
172
|
-
):
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}).filter((p) => p.length >= 3);
|
|
160
|
+
function buildImportPatterns(modifiedFiles: string[], projectPath: string): string[] {
|
|
161
|
+
return modifiedFiles
|
|
162
|
+
.map((f) => {
|
|
163
|
+
const rel = f.startsWith('/') ? relative(projectPath, f) : f;
|
|
164
|
+
// Strip extension for import matching
|
|
165
|
+
const stem = rel.replace(/\.[^.]+$/, '');
|
|
166
|
+
// Also match the bare filename without extension
|
|
167
|
+
const bare = basename(rel).replace(/\.[^.]+$/, '');
|
|
168
|
+
return bare.length >= 3 ? bare : stem;
|
|
169
|
+
})
|
|
170
|
+
.filter((p) => p.length >= 3);
|
|
181
171
|
}
|
|
182
172
|
|
|
183
173
|
/**
|
|
@@ -191,34 +181,28 @@ function matchImports(filePath: string, patterns: string[]): string[] {
|
|
|
191
181
|
return [];
|
|
192
182
|
}
|
|
193
183
|
|
|
194
|
-
const importRegex =
|
|
184
|
+
const importRegex =
|
|
185
|
+
/(?:import\s+.*?from\s+['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\))/g;
|
|
195
186
|
const importPaths: string[] = [];
|
|
196
187
|
let match: RegExpExecArray | null;
|
|
197
188
|
while ((match = importRegex.exec(content)) !== null) {
|
|
198
189
|
importPaths.push(match[1] ?? match[2]);
|
|
199
190
|
}
|
|
200
191
|
|
|
201
|
-
return patterns.filter((p) =>
|
|
202
|
-
importPaths.some((imp) => imp.includes(p)),
|
|
203
|
-
);
|
|
192
|
+
return patterns.filter((p) => importPaths.some((imp) => imp.includes(p)));
|
|
204
193
|
}
|
|
205
194
|
|
|
206
195
|
/**
|
|
207
196
|
* Filter consumers that are NOT test files.
|
|
208
197
|
*/
|
|
209
198
|
function filterUntested(consumers: AffectedConsumer[]): string[] {
|
|
210
|
-
return consumers
|
|
211
|
-
.map((c) => c.file)
|
|
212
|
-
.filter((f) => !TEST_PATTERNS.some((p) => p.test(f)));
|
|
199
|
+
return consumers.map((c) => c.file).filter((f) => !TEST_PATTERNS.some((p) => p.test(f)));
|
|
213
200
|
}
|
|
214
201
|
|
|
215
202
|
/**
|
|
216
203
|
* Flag modified files not in the declared plan scope.
|
|
217
204
|
*/
|
|
218
|
-
function detectScopeViolations(
|
|
219
|
-
modifiedFiles: string[],
|
|
220
|
-
planScope?: string[],
|
|
221
|
-
): string[] {
|
|
205
|
+
function detectScopeViolations(modifiedFiles: string[], planScope?: string[]): string[] {
|
|
222
206
|
if (!planScope || planScope.length === 0) return [];
|
|
223
207
|
|
|
224
208
|
return modifiedFiles.filter((f) => {
|
|
@@ -248,7 +232,10 @@ function buildRecommendations(
|
|
|
248
232
|
|
|
249
233
|
if (consumers.length > 0) {
|
|
250
234
|
recs.push(
|
|
251
|
-
`Run tests for ${consumers.length} affected consumer(s): ${consumers
|
|
235
|
+
`Run tests for ${consumers.length} affected consumer(s): ${consumers
|
|
236
|
+
.map((c) => c.file)
|
|
237
|
+
.slice(0, 5)
|
|
238
|
+
.join(', ')}`,
|
|
252
239
|
);
|
|
253
240
|
}
|
|
254
241
|
|
|
@@ -110,8 +110,15 @@ describe('plan-lifecycle', () => {
|
|
|
110
110
|
|
|
111
111
|
describe('PlanGradeRejectionError', () => {
|
|
112
112
|
it('contains grade, score, minGrade and gaps', () => {
|
|
113
|
-
const gaps = [
|
|
114
|
-
|
|
113
|
+
const gaps = [
|
|
114
|
+
{
|
|
115
|
+
id: 'g1',
|
|
116
|
+
severity: 'critical' as const,
|
|
117
|
+
category: 'structure',
|
|
118
|
+
description: 'Missing structure',
|
|
119
|
+
recommendation: 'Fix it',
|
|
120
|
+
},
|
|
121
|
+
];
|
|
115
122
|
const err = new PlanGradeRejectionError('C', 65, 'A', gaps);
|
|
116
123
|
expect(err.grade).toBe('C');
|
|
117
124
|
expect(err.score).toBe(65);
|
|
@@ -122,8 +129,20 @@ describe('plan-lifecycle', () => {
|
|
|
122
129
|
});
|
|
123
130
|
it('includes critical and major gaps in message', () => {
|
|
124
131
|
const gaps = [
|
|
125
|
-
{
|
|
126
|
-
|
|
132
|
+
{
|
|
133
|
+
id: 'g1',
|
|
134
|
+
severity: 'critical' as const,
|
|
135
|
+
category: 'x',
|
|
136
|
+
description: 'Crit gap',
|
|
137
|
+
recommendation: '',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: 'g2',
|
|
141
|
+
severity: 'minor' as const,
|
|
142
|
+
category: 'x',
|
|
143
|
+
description: 'Minor gap',
|
|
144
|
+
recommendation: '',
|
|
145
|
+
},
|
|
127
146
|
];
|
|
128
147
|
const err = new PlanGradeRejectionError('D', 55, 'A', gaps);
|
|
129
148
|
expect(err.message).toContain('Crit gap');
|
|
@@ -133,24 +152,33 @@ describe('plan-lifecycle', () => {
|
|
|
133
152
|
|
|
134
153
|
describe('hasCircularDependencies', () => {
|
|
135
154
|
it('returns false for no dependencies', () => {
|
|
136
|
-
expect(hasCircularDependencies([
|
|
137
|
-
{ id: 'a' }, { id: 'b' },
|
|
138
|
-
])).toBe(false);
|
|
155
|
+
expect(hasCircularDependencies([{ id: 'a' }, { id: 'b' }])).toBe(false);
|
|
139
156
|
});
|
|
140
157
|
it('returns false for linear dependencies', () => {
|
|
141
|
-
expect(
|
|
142
|
-
|
|
143
|
-
|
|
158
|
+
expect(
|
|
159
|
+
hasCircularDependencies([
|
|
160
|
+
{ id: 'a' },
|
|
161
|
+
{ id: 'b', dependsOn: ['a'] },
|
|
162
|
+
{ id: 'c', dependsOn: ['b'] },
|
|
163
|
+
]),
|
|
164
|
+
).toBe(false);
|
|
144
165
|
});
|
|
145
166
|
it('returns true for direct cycle', () => {
|
|
146
|
-
expect(
|
|
147
|
-
|
|
148
|
-
|
|
167
|
+
expect(
|
|
168
|
+
hasCircularDependencies([
|
|
169
|
+
{ id: 'a', dependsOn: ['b'] },
|
|
170
|
+
{ id: 'b', dependsOn: ['a'] },
|
|
171
|
+
]),
|
|
172
|
+
).toBe(true);
|
|
149
173
|
});
|
|
150
174
|
it('returns true for indirect cycle', () => {
|
|
151
|
-
expect(
|
|
152
|
-
|
|
153
|
-
|
|
175
|
+
expect(
|
|
176
|
+
hasCircularDependencies([
|
|
177
|
+
{ id: 'a', dependsOn: ['c'] },
|
|
178
|
+
{ id: 'b', dependsOn: ['a'] },
|
|
179
|
+
{ id: 'c', dependsOn: ['b'] },
|
|
180
|
+
]),
|
|
181
|
+
).toBe(true);
|
|
154
182
|
});
|
|
155
183
|
it('returns true for self-dependency', () => {
|
|
156
184
|
expect(hasCircularDependencies([{ id: 'a', dependsOn: ['a'] }])).toBe(true);
|
|
@@ -162,29 +190,60 @@ describe('plan-lifecycle', () => {
|
|
|
162
190
|
expect(calculateScore([])).toBe(100);
|
|
163
191
|
});
|
|
164
192
|
it('deducts critical gaps at weight 30', () => {
|
|
165
|
-
const gaps = [
|
|
166
|
-
|
|
193
|
+
const gaps = [
|
|
194
|
+
{
|
|
195
|
+
id: 'g',
|
|
196
|
+
severity: 'critical' as const,
|
|
197
|
+
category: 'structure',
|
|
198
|
+
description: 'x',
|
|
199
|
+
recommendation: 'y',
|
|
200
|
+
},
|
|
201
|
+
];
|
|
167
202
|
expect(calculateScore(gaps)).toBe(70);
|
|
168
203
|
});
|
|
169
204
|
it('treats minor gaps as free on iteration 1', () => {
|
|
170
|
-
const gaps = [
|
|
171
|
-
|
|
205
|
+
const gaps = [
|
|
206
|
+
{
|
|
207
|
+
id: 'g',
|
|
208
|
+
severity: 'minor' as const,
|
|
209
|
+
category: 'clarity',
|
|
210
|
+
description: 'x',
|
|
211
|
+
recommendation: 'y',
|
|
212
|
+
},
|
|
213
|
+
];
|
|
172
214
|
expect(calculateScore(gaps, 1)).toBe(100);
|
|
173
215
|
});
|
|
174
216
|
it('treats minor gaps at half weight on iteration 2', () => {
|
|
175
|
-
const gaps = [
|
|
176
|
-
|
|
217
|
+
const gaps = [
|
|
218
|
+
{
|
|
219
|
+
id: 'g',
|
|
220
|
+
severity: 'minor' as const,
|
|
221
|
+
category: 'clarity',
|
|
222
|
+
description: 'x',
|
|
223
|
+
recommendation: 'y',
|
|
224
|
+
},
|
|
225
|
+
];
|
|
177
226
|
expect(calculateScore(gaps, 2)).toBe(99);
|
|
178
227
|
});
|
|
179
228
|
it('treats minor gaps at full weight on iteration 3', () => {
|
|
180
|
-
const gaps = [
|
|
181
|
-
|
|
229
|
+
const gaps = [
|
|
230
|
+
{
|
|
231
|
+
id: 'g',
|
|
232
|
+
severity: 'minor' as const,
|
|
233
|
+
category: 'clarity',
|
|
234
|
+
description: 'x',
|
|
235
|
+
recommendation: 'y',
|
|
236
|
+
},
|
|
237
|
+
];
|
|
182
238
|
expect(calculateScore(gaps, 3)).toBe(98);
|
|
183
239
|
});
|
|
184
240
|
it('floors at 0', () => {
|
|
185
241
|
const gaps = Array.from({ length: 5 }, (_, i) => ({
|
|
186
|
-
id: `g${i}`,
|
|
187
|
-
|
|
242
|
+
id: `g${i}`,
|
|
243
|
+
severity: 'critical' as const,
|
|
244
|
+
category: `cat${i}`,
|
|
245
|
+
description: 'x',
|
|
246
|
+
recommendation: 'y',
|
|
188
247
|
}));
|
|
189
248
|
expect(calculateScore(gaps)).toBe(0);
|
|
190
249
|
});
|
|
@@ -201,7 +260,9 @@ describe('plan-lifecycle', () => {
|
|
|
201
260
|
});
|
|
202
261
|
it('adds tasks with correct IDs', () => {
|
|
203
262
|
const plan = makePlan();
|
|
204
|
-
plan.tasks = [
|
|
263
|
+
plan.tasks = [
|
|
264
|
+
{ id: 'task-1', title: 'T1', description: 'd', status: 'pending', updatedAt: 0 },
|
|
265
|
+
];
|
|
205
266
|
applyIteration(plan, { addTasks: [{ title: 'T2', description: 'd2' }] });
|
|
206
267
|
expect(plan.tasks).toHaveLength(2);
|
|
207
268
|
expect(plan.tasks[1].id).toBe('task-2');
|
|
@@ -230,22 +291,24 @@ describe('plan-lifecycle', () => {
|
|
|
230
291
|
});
|
|
231
292
|
it('throws on unknown dependency', () => {
|
|
232
293
|
const plan = createPlanObject({ objective: 'test', scope: 'test' });
|
|
233
|
-
expect(() =>
|
|
234
|
-
{ title: 'A', description: 'a', dependsOn: ['task-99'] },
|
|
235
|
-
|
|
294
|
+
expect(() =>
|
|
295
|
+
applySplitTasks(plan, [{ title: 'A', description: 'a', dependsOn: ['task-99'] }]),
|
|
296
|
+
).toThrow('depends on unknown task');
|
|
236
297
|
});
|
|
237
298
|
it('preserves acceptance criteria', () => {
|
|
238
299
|
const plan = createPlanObject({ objective: 'test', scope: 'test' });
|
|
239
|
-
applySplitTasks(plan, [
|
|
240
|
-
{ title: 'A', description: 'a', acceptanceCriteria: ['cr1', 'cr2'] },
|
|
241
|
-
]);
|
|
300
|
+
applySplitTasks(plan, [{ title: 'A', description: 'a', acceptanceCriteria: ['cr1', 'cr2'] }]);
|
|
242
301
|
expect(plan.tasks[0].acceptanceCriteria).toEqual(['cr1', 'cr2']);
|
|
243
302
|
});
|
|
244
303
|
});
|
|
245
304
|
|
|
246
305
|
describe('applyTaskStatusUpdate', () => {
|
|
247
306
|
const makeTask = (): PlanTask => ({
|
|
248
|
-
id: 'task-1',
|
|
307
|
+
id: 'task-1',
|
|
308
|
+
title: 'T',
|
|
309
|
+
description: 'd',
|
|
310
|
+
status: 'pending',
|
|
311
|
+
updatedAt: 0,
|
|
249
312
|
});
|
|
250
313
|
|
|
251
314
|
it('sets startedAt on first in_progress', () => {
|
|
@@ -295,8 +358,12 @@ describe('plan-lifecycle', () => {
|
|
|
295
358
|
});
|
|
296
359
|
it('creates numbered tasks', () => {
|
|
297
360
|
const plan = createPlanObject({
|
|
298
|
-
objective: 'x',
|
|
299
|
-
|
|
361
|
+
objective: 'x',
|
|
362
|
+
scope: 'y',
|
|
363
|
+
tasks: [
|
|
364
|
+
{ title: 'A', description: 'a' },
|
|
365
|
+
{ title: 'B', description: 'b' },
|
|
366
|
+
],
|
|
300
367
|
});
|
|
301
368
|
expect(plan.tasks[0].id).toBe('task-1');
|
|
302
369
|
expect(plan.tasks[1].id).toBe('task-2');
|
|
@@ -229,10 +229,17 @@ export function hasCircularDependencies(
|
|
|
229
229
|
import type { PlanTask, TaskStatus, Plan, PlanDecision } from './planner-types.js';
|
|
230
230
|
|
|
231
231
|
export interface IterateChanges {
|
|
232
|
-
objective?: string;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
232
|
+
objective?: string;
|
|
233
|
+
scope?: string;
|
|
234
|
+
decisions?: (string | PlanDecision)[];
|
|
235
|
+
addTasks?: Array<{ title: string; description: string }>;
|
|
236
|
+
removeTasks?: string[];
|
|
237
|
+
approach?: string;
|
|
238
|
+
context?: string;
|
|
239
|
+
success_criteria?: string[];
|
|
240
|
+
tool_chain?: string[];
|
|
241
|
+
flow?: string;
|
|
242
|
+
target_mode?: string;
|
|
236
243
|
}
|
|
237
244
|
|
|
238
245
|
/**
|
|
@@ -261,8 +268,11 @@ export function applyIteration(plan: Plan, changes: IterateChanges): void {
|
|
|
261
268
|
}, 0);
|
|
262
269
|
for (let i = 0; i < changes.addTasks.length; i++) {
|
|
263
270
|
plan.tasks.push({
|
|
264
|
-
id: `task-${maxIndex + i + 1}`,
|
|
265
|
-
|
|
271
|
+
id: `task-${maxIndex + i + 1}`,
|
|
272
|
+
title: changes.addTasks[i].title,
|
|
273
|
+
description: changes.addTasks[i].description,
|
|
274
|
+
status: 'pending' as TaskStatus,
|
|
275
|
+
updatedAt: now,
|
|
266
276
|
});
|
|
267
277
|
}
|
|
268
278
|
}
|
|
@@ -295,23 +305,32 @@ export function applyTaskStatusUpdate(task: PlanTask, status: TaskStatus): void
|
|
|
295
305
|
* Create a new Plan object (factory). Does not persist.
|
|
296
306
|
*/
|
|
297
307
|
export function createPlanObject(params: {
|
|
298
|
-
objective: string;
|
|
308
|
+
objective: string;
|
|
309
|
+
scope: string;
|
|
299
310
|
decisions?: (string | PlanDecision)[];
|
|
300
311
|
tasks?: Array<{ title: string; description: string }>;
|
|
301
|
-
approach?: string;
|
|
302
|
-
|
|
312
|
+
approach?: string;
|
|
313
|
+
context?: string;
|
|
314
|
+
success_criteria?: string[];
|
|
315
|
+
tool_chain?: string[];
|
|
316
|
+
flow?: string;
|
|
317
|
+
target_mode?: string;
|
|
303
318
|
alternatives?: import('./planner-types.js').PlanAlternative[];
|
|
304
319
|
initialStatus?: 'brainstorming' | 'draft';
|
|
305
320
|
}): Plan {
|
|
306
321
|
const now = Date.now();
|
|
307
322
|
return {
|
|
308
323
|
id: `plan-${now}-${Math.random().toString(36).slice(2, 8)}`,
|
|
309
|
-
objective: params.objective,
|
|
324
|
+
objective: params.objective,
|
|
325
|
+
scope: params.scope,
|
|
310
326
|
status: params.initialStatus ?? 'draft',
|
|
311
327
|
decisions: params.decisions ?? [],
|
|
312
328
|
tasks: (params.tasks ?? []).map((t, i) => ({
|
|
313
|
-
id: `task-${i + 1}`,
|
|
314
|
-
|
|
329
|
+
id: `task-${i + 1}`,
|
|
330
|
+
title: t.title,
|
|
331
|
+
description: t.description,
|
|
332
|
+
status: 'pending' as TaskStatus,
|
|
333
|
+
updatedAt: now,
|
|
315
334
|
})),
|
|
316
335
|
...(params.approach !== undefined && { approach: params.approach }),
|
|
317
336
|
...(params.context !== undefined && { context: params.context }),
|
|
@@ -320,25 +339,37 @@ export function createPlanObject(params: {
|
|
|
320
339
|
...(params.flow !== undefined && { flow: params.flow }),
|
|
321
340
|
...(params.target_mode !== undefined && { target_mode: params.target_mode }),
|
|
322
341
|
...(params.alternatives !== undefined && { alternatives: params.alternatives }),
|
|
323
|
-
checks: [],
|
|
342
|
+
checks: [],
|
|
343
|
+
createdAt: now,
|
|
344
|
+
updatedAt: now,
|
|
324
345
|
};
|
|
325
346
|
}
|
|
326
347
|
|
|
327
348
|
export function applySplitTasks(
|
|
328
349
|
plan: Plan,
|
|
329
|
-
tasks: Array<{
|
|
350
|
+
tasks: Array<{
|
|
351
|
+
title: string;
|
|
352
|
+
description: string;
|
|
353
|
+
dependsOn?: string[];
|
|
354
|
+
acceptanceCriteria?: string[];
|
|
355
|
+
}>,
|
|
330
356
|
): void {
|
|
331
357
|
const now = Date.now();
|
|
332
358
|
plan.tasks = tasks.map((t, i) => ({
|
|
333
|
-
id: `task-${i + 1}`,
|
|
334
|
-
|
|
335
|
-
|
|
359
|
+
id: `task-${i + 1}`,
|
|
360
|
+
title: t.title,
|
|
361
|
+
description: t.description,
|
|
362
|
+
status: 'pending' as TaskStatus,
|
|
363
|
+
dependsOn: t.dependsOn,
|
|
364
|
+
...(t.acceptanceCriteria && { acceptanceCriteria: t.acceptanceCriteria }),
|
|
365
|
+
updatedAt: now,
|
|
336
366
|
}));
|
|
337
367
|
const taskIds = new Set(plan.tasks.map((t) => t.id));
|
|
338
368
|
for (const task of plan.tasks) {
|
|
339
369
|
if (task.dependsOn) {
|
|
340
370
|
for (const dep of task.dependsOn) {
|
|
341
|
-
if (!taskIds.has(dep))
|
|
371
|
+
if (!taskIds.has(dep))
|
|
372
|
+
throw new Error(`Task '${task.id}' depends on unknown task '${dep}'`);
|
|
342
373
|
}
|
|
343
374
|
}
|
|
344
375
|
}
|
|
@@ -9,8 +9,18 @@ import { tmpdir } from 'node:os';
|
|
|
9
9
|
|
|
10
10
|
/** Two well-structured alternatives to satisfy pass 8. */
|
|
11
11
|
const TWO_ALTERNATIVES: PlanAlternative[] = [
|
|
12
|
-
{
|
|
13
|
-
|
|
12
|
+
{
|
|
13
|
+
approach: 'Use alternative A',
|
|
14
|
+
pros: ['Pro A'],
|
|
15
|
+
cons: ['Con A'],
|
|
16
|
+
rejected_reason: 'Not suitable for our use case',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
approach: 'Use alternative B',
|
|
20
|
+
pros: ['Pro B'],
|
|
21
|
+
cons: ['Con B'],
|
|
22
|
+
rejected_reason: 'Too complex for the scope',
|
|
23
|
+
},
|
|
14
24
|
];
|
|
15
25
|
|
|
16
26
|
describe('Planner', () => {
|