@soleri/core 7.0.0 → 8.1.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/agency/agency-manager.d.ts +27 -1
- package/dist/agency/agency-manager.d.ts.map +1 -1
- package/dist/agency/agency-manager.js +180 -9
- package/dist/agency/agency-manager.js.map +1 -1
- package/dist/agency/default-rules.d.ts +7 -0
- package/dist/agency/default-rules.d.ts.map +1 -0
- package/dist/agency/default-rules.js +79 -0
- package/dist/agency/default-rules.js.map +1 -0
- package/dist/agency/types.d.ts +48 -0
- package/dist/agency/types.d.ts.map +1 -1
- package/dist/brain/brain.d.ts +17 -2
- package/dist/brain/brain.d.ts.map +1 -1
- package/dist/brain/brain.js +118 -8
- package/dist/brain/brain.js.map +1 -1
- package/dist/brain/knowledge-synthesizer.d.ts +37 -0
- package/dist/brain/knowledge-synthesizer.d.ts.map +1 -0
- package/dist/brain/knowledge-synthesizer.js +159 -0
- package/dist/brain/knowledge-synthesizer.js.map +1 -0
- package/dist/brain/learning-radar.d.ts +96 -0
- package/dist/brain/learning-radar.d.ts.map +1 -0
- package/dist/brain/learning-radar.js +202 -0
- package/dist/brain/learning-radar.js.map +1 -0
- package/dist/brain/types.d.ts +15 -0
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/context/context-engine.d.ts.map +1 -1
- package/dist/context/context-engine.js +82 -17
- package/dist/context/context-engine.js.map +1 -1
- package/dist/context/types.d.ts +5 -0
- package/dist/context/types.d.ts.map +1 -1
- package/dist/control/intent-router.d.ts +12 -1
- package/dist/control/intent-router.d.ts.map +1 -1
- package/dist/control/intent-router.js +68 -0
- package/dist/control/intent-router.js.map +1 -1
- package/dist/control/types.d.ts +17 -0
- package/dist/control/types.d.ts.map +1 -1
- package/dist/curator/classifier.d.ts +18 -0
- package/dist/curator/classifier.d.ts.map +1 -0
- package/dist/curator/classifier.js +59 -0
- package/dist/curator/classifier.js.map +1 -0
- package/dist/curator/quality-gate.d.ts +29 -0
- package/dist/curator/quality-gate.d.ts.map +1 -0
- package/dist/curator/quality-gate.js +86 -0
- package/dist/curator/quality-gate.js.map +1 -0
- package/dist/domain-packs/index.d.ts +0 -3
- package/dist/domain-packs/index.d.ts.map +1 -1
- package/dist/domain-packs/index.js +0 -3
- package/dist/domain-packs/index.js.map +1 -1
- package/dist/domain-packs/loader.d.ts.map +1 -1
- package/dist/domain-packs/loader.js +20 -4
- package/dist/domain-packs/loader.js.map +1 -1
- package/dist/domain-packs/pack-runtime.d.ts +5 -5
- package/dist/domain-packs/pack-runtime.d.ts.map +1 -1
- package/dist/domain-packs/pack-runtime.js +2 -2
- package/dist/domain-packs/pack-runtime.js.map +1 -1
- package/dist/domain-packs/types.d.ts +8 -2
- package/dist/domain-packs/types.d.ts.map +1 -1
- package/dist/domain-packs/types.js.map +1 -1
- package/dist/engine/bin/soleri-engine.js +13 -2
- package/dist/engine/bin/soleri-engine.js.map +1 -1
- package/dist/engine/index.d.ts +2 -0
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +1 -0
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/module-manifest.d.ts +28 -0
- package/dist/engine/module-manifest.d.ts.map +1 -0
- package/dist/engine/module-manifest.js +85 -0
- package/dist/engine/module-manifest.js.map +1 -0
- package/dist/engine/register-engine.d.ts +19 -0
- package/dist/engine/register-engine.d.ts.map +1 -1
- package/dist/engine/register-engine.js +15 -2
- package/dist/engine/register-engine.js.map +1 -1
- package/dist/events/event-bus.d.ts +30 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/event-bus.js +51 -0
- package/dist/events/event-bus.js.map +1 -0
- package/dist/flows/chain-runner.d.ts +46 -0
- package/dist/flows/chain-runner.d.ts.map +1 -0
- package/dist/flows/chain-runner.js +271 -0
- package/dist/flows/chain-runner.js.map +1 -0
- package/dist/flows/chain-types.d.ts +103 -0
- package/dist/flows/chain-types.d.ts.map +1 -0
- package/dist/flows/chain-types.js +23 -0
- package/dist/flows/chain-types.js.map +1 -0
- package/dist/health/doctor-checks.d.ts +15 -0
- package/dist/health/doctor-checks.d.ts.map +1 -0
- package/dist/health/doctor-checks.js +98 -0
- package/dist/health/doctor-checks.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/intake/content-classifier.d.ts.map +1 -1
- package/dist/intake/content-classifier.js +0 -2
- package/dist/intake/content-classifier.js.map +1 -1
- package/dist/intake/text-ingester.d.ts +52 -0
- package/dist/intake/text-ingester.d.ts.map +1 -0
- package/dist/intake/text-ingester.js +181 -0
- package/dist/intake/text-ingester.js.map +1 -0
- package/dist/llm/llm-client.d.ts.map +1 -1
- package/dist/llm/llm-client.js +45 -5
- package/dist/llm/llm-client.js.map +1 -1
- package/dist/llm/oauth-discovery.d.ts +18 -0
- package/dist/llm/oauth-discovery.d.ts.map +1 -0
- package/dist/llm/oauth-discovery.js +130 -0
- package/dist/llm/oauth-discovery.js.map +1 -0
- package/dist/llm/types.d.ts +4 -2
- package/dist/llm/types.d.ts.map +1 -1
- package/dist/packs/pack-installer.d.ts +2 -1
- package/dist/packs/pack-installer.d.ts.map +1 -1
- package/dist/packs/pack-installer.js +10 -1
- package/dist/packs/pack-installer.js.map +1 -1
- package/dist/persistence/index.d.ts +0 -1
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +0 -1
- package/dist/persistence/index.js.map +1 -1
- package/dist/persistence/types.d.ts +2 -6
- package/dist/persistence/types.d.ts.map +1 -1
- package/dist/planning/evidence-collector.d.ts +41 -0
- package/dist/planning/evidence-collector.d.ts.map +1 -0
- package/dist/planning/evidence-collector.js +194 -0
- package/dist/planning/evidence-collector.js.map +1 -0
- package/dist/planning/planner.d.ts +4 -0
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +11 -0
- package/dist/planning/planner.js.map +1 -1
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +4 -0
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/plugin-registry.d.ts +4 -0
- package/dist/plugins/plugin-registry.d.ts.map +1 -1
- package/dist/plugins/plugin-registry.js +4 -0
- package/dist/plugins/plugin-registry.js.map +1 -1
- package/dist/plugins/types.d.ts +32 -27
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/plugins/types.js +6 -3
- package/dist/plugins/types.js.map +1 -1
- package/dist/queue/job-queue.d.ts +92 -0
- package/dist/queue/job-queue.d.ts.map +1 -0
- package/dist/queue/job-queue.js +180 -0
- package/dist/queue/job-queue.js.map +1 -0
- package/dist/queue/pipeline-runner.d.ts +62 -0
- package/dist/queue/pipeline-runner.d.ts.map +1 -0
- package/dist/queue/pipeline-runner.js +126 -0
- package/dist/queue/pipeline-runner.js.map +1 -0
- package/dist/runtime/admin-setup-ops.d.ts +20 -0
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -0
- package/dist/runtime/admin-setup-ops.js +583 -0
- package/dist/runtime/admin-setup-ops.js.map +1 -0
- package/dist/runtime/chain-ops.d.ts +9 -0
- package/dist/runtime/chain-ops.d.ts.map +1 -0
- package/dist/runtime/chain-ops.js +107 -0
- package/dist/runtime/chain-ops.js.map +1 -0
- package/dist/runtime/claude-md-helpers.d.ts +56 -0
- package/dist/runtime/claude-md-helpers.d.ts.map +1 -0
- package/dist/runtime/claude-md-helpers.js +160 -0
- package/dist/runtime/claude-md-helpers.js.map +1 -0
- package/dist/runtime/curator-extra-ops.d.ts +3 -2
- package/dist/runtime/curator-extra-ops.d.ts.map +1 -1
- package/dist/runtime/curator-extra-ops.js +81 -3
- package/dist/runtime/curator-extra-ops.js.map +1 -1
- package/dist/runtime/facades/admin-facade.d.ts.map +1 -1
- package/dist/runtime/facades/admin-facade.js +5 -2
- package/dist/runtime/facades/admin-facade.js.map +1 -1
- package/dist/runtime/facades/agency-facade.d.ts.map +1 -1
- package/dist/runtime/facades/agency-facade.js +64 -0
- package/dist/runtime/facades/agency-facade.js.map +1 -1
- package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
- package/dist/runtime/facades/brain-facade.js +122 -1
- package/dist/runtime/facades/brain-facade.js.map +1 -1
- package/dist/runtime/facades/control-facade.d.ts.map +1 -1
- package/dist/runtime/facades/control-facade.js +42 -0
- package/dist/runtime/facades/control-facade.js.map +1 -1
- package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
- package/dist/runtime/facades/memory-facade.js +20 -2
- package/dist/runtime/facades/memory-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +2 -0
- 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 +25 -5
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/intake-ops.d.ts +7 -5
- package/dist/runtime/intake-ops.d.ts.map +1 -1
- package/dist/runtime/intake-ops.js +98 -5
- package/dist/runtime/intake-ops.js.map +1 -1
- package/dist/runtime/memory-extra-ops.d.ts +6 -3
- package/dist/runtime/memory-extra-ops.d.ts.map +1 -1
- package/dist/runtime/memory-extra-ops.js +292 -4
- package/dist/runtime/memory-extra-ops.js.map +1 -1
- package/dist/runtime/pack-ops.d.ts +3 -0
- package/dist/runtime/pack-ops.d.ts.map +1 -1
- package/dist/runtime/pack-ops.js +18 -1
- package/dist/runtime/pack-ops.js.map +1 -1
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
- package/dist/runtime/planning-extra-ops.js +85 -0
- package/dist/runtime/planning-extra-ops.js.map +1 -1
- package/dist/runtime/playbook-ops.js +1 -1
- package/dist/runtime/playbook-ops.js.map +1 -1
- package/dist/runtime/plugin-ops.d.ts.map +1 -1
- package/dist/runtime/plugin-ops.js +3 -0
- package/dist/runtime/plugin-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +143 -2
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/session-briefing.d.ts +23 -0
- package/dist/runtime/session-briefing.d.ts.map +1 -0
- package/dist/runtime/session-briefing.js +154 -0
- package/dist/runtime/session-briefing.js.map +1 -0
- package/dist/runtime/types.d.ts +23 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.js +3 -7
- package/dist/runtime/vault-linking-ops.js.map +1 -1
- package/dist/vault/vault.d.ts +34 -0
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +89 -3
- package/dist/vault/vault.js.map +1 -1
- package/package.json +6 -4
- package/src/__tests__/admin-setup-ops.test.ts +355 -0
- package/src/__tests__/async-infrastructure.test.ts +307 -0
- package/src/__tests__/cognee-client-gaps.test.ts +6 -2
- package/src/__tests__/cognee-hybrid-search.test.ts +49 -35
- package/src/__tests__/cognee-sync-manager-deep.test.ts +89 -65
- package/src/__tests__/curator-extra-ops.test.ts +6 -2
- package/src/__tests__/curator-pipeline-e2e.test.ts +545 -0
- package/src/__tests__/memory-extra-ops.test.ts +2 -2
- package/src/__tests__/module-manifest-drift.test.ts +59 -0
- package/src/__tests__/planning-extra-ops.test.ts +2 -2
- package/src/__tests__/second-brain-features.test.ts +583 -0
- package/src/agency/agency-manager.ts +217 -9
- package/src/agency/default-rules.ts +83 -0
- package/src/agency/types.ts +61 -0
- package/src/brain/brain.ts +110 -8
- package/src/brain/knowledge-synthesizer.ts +216 -0
- package/src/brain/learning-radar.ts +340 -0
- package/src/brain/types.ts +16 -0
- package/src/context/context-engine.ts +114 -15
- package/src/context/types.ts +5 -0
- package/src/control/intent-router.ts +107 -0
- package/src/control/types.ts +10 -0
- package/src/curator/classifier.ts +86 -0
- package/src/curator/quality-gate.ts +127 -0
- package/src/domain-packs/index.ts +0 -6
- package/src/domain-packs/loader.ts +25 -5
- package/src/domain-packs/pack-runtime.ts +6 -6
- package/src/domain-packs/types.ts +8 -2
- package/src/engine/bin/soleri-engine.ts +18 -2
- package/src/engine/index.ts +2 -0
- package/src/engine/module-manifest.ts +99 -0
- package/src/engine/register-engine.ts +21 -2
- package/src/events/event-bus.ts +58 -0
- package/src/flows/chain-runner.ts +369 -0
- package/src/flows/chain-types.ts +57 -0
- package/src/index.ts +0 -1
- package/src/intake/content-classifier.ts +0 -2
- package/src/intake/text-ingester.ts +234 -0
- package/src/llm/llm-client.ts +50 -7
- package/src/llm/oauth-discovery.ts +151 -0
- package/src/llm/types.ts +4 -2
- package/src/packs/pack-installer.ts +16 -1
- package/src/persistence/index.ts +0 -1
- package/src/persistence/types.ts +2 -6
- package/src/planning/evidence-collector.ts +247 -0
- package/src/planning/planner.ts +11 -0
- package/src/plugins/index.ts +4 -0
- package/src/plugins/plugin-registry.ts +6 -1
- package/src/plugins/types.ts +10 -5
- package/src/queue/job-queue.ts +281 -0
- package/src/queue/pipeline-runner.ts +149 -0
- package/src/runtime/admin-setup-ops.ts +664 -0
- package/src/runtime/chain-ops.ts +121 -0
- package/src/runtime/claude-md-helpers.ts +218 -0
- package/src/runtime/curator-extra-ops.ts +86 -3
- package/src/runtime/facades/admin-facade.ts +5 -2
- package/src/runtime/facades/agency-facade.ts +68 -0
- package/src/runtime/facades/brain-facade.ts +142 -1
- package/src/runtime/facades/control-facade.ts +45 -0
- package/src/runtime/facades/memory-facade.ts +20 -2
- package/src/runtime/facades/plan-facade.ts +2 -0
- package/src/runtime/facades/vault-facade.ts +28 -5
- package/src/runtime/intake-ops.ts +107 -5
- package/src/runtime/memory-extra-ops.ts +312 -4
- package/src/runtime/pack-ops.ts +26 -1
- package/src/runtime/planning-extra-ops.ts +94 -0
- package/src/runtime/playbook-ops.ts +1 -1
- package/src/runtime/plugin-ops.ts +3 -0
- package/src/runtime/runtime.ts +138 -2
- package/src/runtime/session-briefing.ts +175 -0
- package/src/runtime/types.ts +23 -0
- package/src/runtime/vault-linking-ops.ts +3 -7
- package/src/vault/vault.ts +105 -4
- package/src/__tests__/postgres-provider.test.ts +0 -116
- package/src/persistence/postgres-provider.ts +0 -310
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evidence Collector — cross-references plan tasks against git reality.
|
|
3
|
+
*
|
|
4
|
+
* Runs `git diff` to find what actually changed, then matches file changes
|
|
5
|
+
* against planned tasks to produce an evidence-based drift report.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { execFileSync } from 'node:child_process';
|
|
9
|
+
import type { Plan, PlanTask } from './planner.js';
|
|
10
|
+
|
|
11
|
+
export interface FileChange {
|
|
12
|
+
path: string;
|
|
13
|
+
status: 'added' | 'modified' | 'deleted' | 'renamed';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface GitTaskEvidence {
|
|
17
|
+
taskId: string;
|
|
18
|
+
taskTitle: string;
|
|
19
|
+
plannedStatus: string;
|
|
20
|
+
matchedFiles: FileChange[];
|
|
21
|
+
verdict: 'DONE' | 'PARTIAL' | 'MISSING' | 'SKIPPED';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface UnplannedChange {
|
|
25
|
+
file: FileChange;
|
|
26
|
+
possibleReason: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface EvidenceReport {
|
|
30
|
+
planId: string;
|
|
31
|
+
planObjective: string;
|
|
32
|
+
accuracy: number;
|
|
33
|
+
evidenceSources: string[];
|
|
34
|
+
taskEvidence: GitTaskEvidence[];
|
|
35
|
+
unplannedChanges: UnplannedChange[];
|
|
36
|
+
missingWork: GitTaskEvidence[];
|
|
37
|
+
summary: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Collect git diff evidence for a plan.
|
|
42
|
+
*
|
|
43
|
+
* @param plan - The plan to verify
|
|
44
|
+
* @param projectPath - Project root (must be a git repo)
|
|
45
|
+
* @param baseBranch - Compare against this branch (default: 'main')
|
|
46
|
+
*/
|
|
47
|
+
export function collectGitEvidence(
|
|
48
|
+
plan: Plan,
|
|
49
|
+
projectPath: string,
|
|
50
|
+
baseBranch: string = 'main',
|
|
51
|
+
): EvidenceReport {
|
|
52
|
+
const fileChanges = getGitDiff(projectPath, baseBranch);
|
|
53
|
+
const taskEvidence: GitTaskEvidence[] = [];
|
|
54
|
+
const matchedFiles = new Set<string>();
|
|
55
|
+
|
|
56
|
+
for (const task of plan.tasks) {
|
|
57
|
+
const matches = findMatchingFiles(task, fileChanges);
|
|
58
|
+
for (const m of matches) matchedFiles.add(m.path);
|
|
59
|
+
|
|
60
|
+
const verdict = determineVerdict(task, matches);
|
|
61
|
+
taskEvidence.push({
|
|
62
|
+
taskId: task.id,
|
|
63
|
+
taskTitle: task.title,
|
|
64
|
+
plannedStatus: task.status,
|
|
65
|
+
matchedFiles: matches,
|
|
66
|
+
verdict,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const unplannedChanges: UnplannedChange[] = fileChanges
|
|
71
|
+
.filter((f) => !matchedFiles.has(f.path))
|
|
72
|
+
.map((f) => ({
|
|
73
|
+
file: f,
|
|
74
|
+
possibleReason: inferReason(f),
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
const missingWork = taskEvidence.filter((te) => te.verdict === 'MISSING');
|
|
78
|
+
|
|
79
|
+
const totalTasks = taskEvidence.length;
|
|
80
|
+
const doneTasks = taskEvidence.filter((te) => te.verdict === 'DONE').length;
|
|
81
|
+
const partialTasks = taskEvidence.filter((te) => te.verdict === 'PARTIAL').length;
|
|
82
|
+
const skippedTasks = taskEvidence.filter((te) => te.verdict === 'SKIPPED').length;
|
|
83
|
+
const accuracy =
|
|
84
|
+
totalTasks > 0
|
|
85
|
+
? Math.round(((doneTasks + partialTasks * 0.5 + skippedTasks * 0.25) / totalTasks) * 100)
|
|
86
|
+
: 100;
|
|
87
|
+
|
|
88
|
+
const summary = buildSummary(
|
|
89
|
+
totalTasks,
|
|
90
|
+
doneTasks,
|
|
91
|
+
partialTasks,
|
|
92
|
+
missingWork.length,
|
|
93
|
+
unplannedChanges.length,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
planId: plan.id,
|
|
98
|
+
planObjective: plan.objective,
|
|
99
|
+
accuracy,
|
|
100
|
+
evidenceSources: ['git'],
|
|
101
|
+
taskEvidence,
|
|
102
|
+
unplannedChanges,
|
|
103
|
+
missingWork,
|
|
104
|
+
summary,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function getGitDiff(projectPath: string, baseBranch: string): FileChange[] {
|
|
109
|
+
try {
|
|
110
|
+
const currentBranch = execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
111
|
+
cwd: projectPath,
|
|
112
|
+
encoding: 'utf-8',
|
|
113
|
+
timeout: 5000,
|
|
114
|
+
}).trim();
|
|
115
|
+
|
|
116
|
+
const diffTarget = currentBranch === baseBranch ? 'HEAD~10' : baseBranch;
|
|
117
|
+
|
|
118
|
+
let output: string;
|
|
119
|
+
try {
|
|
120
|
+
output = execFileSync('git', ['diff', '--name-status', `${diffTarget}...HEAD`], {
|
|
121
|
+
cwd: projectPath,
|
|
122
|
+
encoding: 'utf-8',
|
|
123
|
+
timeout: 10000,
|
|
124
|
+
});
|
|
125
|
+
} catch {
|
|
126
|
+
output = execFileSync('git', ['diff', '--name-status', 'HEAD~5'], {
|
|
127
|
+
cwd: projectPath,
|
|
128
|
+
encoding: 'utf-8',
|
|
129
|
+
timeout: 10000,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return output
|
|
134
|
+
.trim()
|
|
135
|
+
.split('\n')
|
|
136
|
+
.filter((line) => line.length > 0)
|
|
137
|
+
.map(parseGitDiffLine)
|
|
138
|
+
.filter((f): f is FileChange => f !== null);
|
|
139
|
+
} catch {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function parseGitDiffLine(line: string): FileChange | null {
|
|
145
|
+
const match = line.match(/^([AMDRC])\d*\t(.+?)(?:\t(.+))?$/);
|
|
146
|
+
if (!match) return null;
|
|
147
|
+
|
|
148
|
+
const statusChar = match[1];
|
|
149
|
+
const path = match[3] ?? match[2];
|
|
150
|
+
|
|
151
|
+
const statusMap: Record<string, FileChange['status']> = {
|
|
152
|
+
A: 'added',
|
|
153
|
+
M: 'modified',
|
|
154
|
+
D: 'deleted',
|
|
155
|
+
R: 'renamed',
|
|
156
|
+
C: 'added',
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
return { path, status: statusMap[statusChar] ?? 'modified' };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function findMatchingFiles(task: PlanTask, files: FileChange[]): FileChange[] {
|
|
163
|
+
const keywords = extractKeywords(task.title + ' ' + task.description);
|
|
164
|
+
if (keywords.length === 0) return [];
|
|
165
|
+
|
|
166
|
+
return files.filter((f) => {
|
|
167
|
+
const pathLower = f.path.toLowerCase();
|
|
168
|
+
return keywords.some((kw) => pathLower.includes(kw));
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function extractKeywords(text: string): string[] {
|
|
173
|
+
const stopWords = new Set([
|
|
174
|
+
'the',
|
|
175
|
+
'and',
|
|
176
|
+
'for',
|
|
177
|
+
'with',
|
|
178
|
+
'that',
|
|
179
|
+
'this',
|
|
180
|
+
'from',
|
|
181
|
+
'into',
|
|
182
|
+
'add',
|
|
183
|
+
'create',
|
|
184
|
+
'implement',
|
|
185
|
+
'update',
|
|
186
|
+
'fix',
|
|
187
|
+
'remove',
|
|
188
|
+
'delete',
|
|
189
|
+
'new',
|
|
190
|
+
'use',
|
|
191
|
+
'should',
|
|
192
|
+
'must',
|
|
193
|
+
'will',
|
|
194
|
+
'can',
|
|
195
|
+
'all',
|
|
196
|
+
'each',
|
|
197
|
+
'when',
|
|
198
|
+
'not',
|
|
199
|
+
'are',
|
|
200
|
+
'has',
|
|
201
|
+
'have',
|
|
202
|
+
'been',
|
|
203
|
+
'was',
|
|
204
|
+
]);
|
|
205
|
+
|
|
206
|
+
const words = text
|
|
207
|
+
.toLowerCase()
|
|
208
|
+
.replace(/[^a-z0-9\s\-_/.]/g, ' ')
|
|
209
|
+
.split(/[\s\-_/]+/)
|
|
210
|
+
.filter((w) => w.length >= 3 && !stopWords.has(w));
|
|
211
|
+
|
|
212
|
+
return [...new Set(words)];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function determineVerdict(task: PlanTask, matches: FileChange[]): GitTaskEvidence['verdict'] {
|
|
216
|
+
if (task.status === 'skipped') return 'SKIPPED';
|
|
217
|
+
if (matches.length === 0) return 'MISSING';
|
|
218
|
+
if (task.status === 'completed') return 'DONE';
|
|
219
|
+
if (matches.length > 0) return 'PARTIAL';
|
|
220
|
+
return 'MISSING';
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function inferReason(file: FileChange): string {
|
|
224
|
+
const path = file.path.toLowerCase();
|
|
225
|
+
if (path.includes('index.') || path.includes('barrel')) return 'likely re-export update';
|
|
226
|
+
if (path.includes('config') || path.includes('.env')) return 'configuration change';
|
|
227
|
+
if (path.includes('test') || path.includes('spec')) return 'test file';
|
|
228
|
+
if (path.includes('package.json') || path.includes('lock')) return 'dependency update';
|
|
229
|
+
if (path.includes('readme') || path.includes('.md')) return 'documentation';
|
|
230
|
+
if (path.includes('types') || path.includes('.d.ts')) return 'type definition update';
|
|
231
|
+
return 'unplanned scope';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function buildSummary(
|
|
235
|
+
total: number,
|
|
236
|
+
done: number,
|
|
237
|
+
partial: number,
|
|
238
|
+
missing: number,
|
|
239
|
+
unplanned: number,
|
|
240
|
+
): string {
|
|
241
|
+
const parts: string[] = [];
|
|
242
|
+
parts.push(`${done}/${total} tasks verified by git evidence`);
|
|
243
|
+
if (partial > 0) parts.push(`${partial} partially done`);
|
|
244
|
+
if (missing > 0) parts.push(`${missing} with no file evidence`);
|
|
245
|
+
if (unplanned > 0) parts.push(`${unplanned} unplanned file changes`);
|
|
246
|
+
return parts.join(', ');
|
|
247
|
+
}
|
package/src/planning/planner.ts
CHANGED
|
@@ -385,6 +385,17 @@ export class Planner {
|
|
|
385
385
|
return [...this.store.plans];
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
+
/**
|
|
389
|
+
* Permanently remove a plan by ID. Returns true if found and removed.
|
|
390
|
+
*/
|
|
391
|
+
remove(planId: string): boolean {
|
|
392
|
+
const idx = this.store.plans.findIndex((p) => p.id === planId);
|
|
393
|
+
if (idx < 0) return false;
|
|
394
|
+
this.store.plans.splice(idx, 1);
|
|
395
|
+
this.save();
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
|
|
388
399
|
/**
|
|
389
400
|
* Transition a plan to a new status using the typed FSM.
|
|
390
401
|
* Validates that the transition is allowed before applying it.
|
package/src/plugins/index.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Plugin System — Barrel Exports
|
|
3
|
+
*
|
|
4
|
+
* @deprecated Prefer knowledge packs (soleri-pack.json) for new extensions.
|
|
5
|
+
* The plugin system is maintained for backwards compatibility and is used
|
|
6
|
+
* internally by the pack installer for facade registration.
|
|
3
7
|
*/
|
|
4
8
|
|
|
5
9
|
export {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Plugin Registry — tracks loaded plugins and their lifecycle.
|
|
3
3
|
*
|
|
4
|
+
* @deprecated The plugin system is superseded by knowledge packs (`soleri-pack.json`).
|
|
5
|
+
* This registry is still used internally by the pack installer to register facades,
|
|
6
|
+
* but new extensions should use the pack system directly.
|
|
7
|
+
*
|
|
4
8
|
* Not a singleton — lives on AgentRuntime for testability.
|
|
5
9
|
* Lifecycle: load → register → activate → (deactivate | error)
|
|
6
10
|
*/
|
|
@@ -161,7 +165,8 @@ export class PluginRegistry {
|
|
|
161
165
|
throw new Error(`Plugin module "${moduleFile}" must export createFacades(ctx)`);
|
|
162
166
|
} catch (e) {
|
|
163
167
|
throw new Error(
|
|
164
|
-
`Failed to load plugin module "${moduleFile}": ${e instanceof Error ? e.message : String(e)}`,
|
|
168
|
+
`Failed to load plugin module "${moduleFile}": ${e instanceof Error ? e.message : String(e)}`,
|
|
169
|
+
{ cause: e },
|
|
165
170
|
);
|
|
166
171
|
}
|
|
167
172
|
}
|
package/src/plugins/types.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Plugin System — Types & Manifest Schema
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* @deprecated Prefer knowledge packs (`soleri-pack.json`) over plugins (`soleri-plugin.json`).
|
|
5
|
+
* Knowledge packs are a superset of plugins — they support facades, vault entries, skills,
|
|
6
|
+
* hooks, and capability declarations. Plugins only support facades and intelligence entries.
|
|
7
|
+
*
|
|
8
|
+
* This module is maintained for backwards compatibility. New extensions should use
|
|
9
|
+
* the pack system in `../packs/`. See docs/architecture/extension-tiers.md.
|
|
7
10
|
*/
|
|
8
11
|
|
|
9
12
|
import { z } from 'zod';
|
|
@@ -101,8 +104,10 @@ export type PluginFacadeBuilder = (ctx: PluginContext) => FacadeConfig[];
|
|
|
101
104
|
* Context passed to plugin facade builders during activation.
|
|
102
105
|
*/
|
|
103
106
|
export interface PluginContext {
|
|
104
|
-
/**
|
|
105
|
-
|
|
107
|
+
/** Narrowed runtime — vault, projects, session checks. Preferred over full runtime. */
|
|
108
|
+
packRuntime: import('../domain-packs/pack-runtime.js').PackRuntime;
|
|
109
|
+
/** @deprecated Full agent runtime. Use packRuntime instead — only vault, projects, and session checks are guaranteed. */
|
|
110
|
+
runtime: unknown;
|
|
106
111
|
/** The plugin's own manifest */
|
|
107
112
|
manifest: PluginManifest;
|
|
108
113
|
/** The plugin's directory on disk */
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job Queue — SQLite-backed FIFO queue with DAG dependencies and retries.
|
|
3
|
+
*
|
|
4
|
+
* Generic infrastructure — not curator-specific. Reusable by agency, intake, etc.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Persistent jobs (survive process restarts)
|
|
8
|
+
* - DAG dependency resolution (job B waits for job A)
|
|
9
|
+
* - Pipeline grouping (group related jobs under one ID)
|
|
10
|
+
* - Configurable retries with max limit
|
|
11
|
+
* - Status tracking: pending → running → completed | failed
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { randomUUID } from 'node:crypto';
|
|
15
|
+
import type { PersistenceProvider } from '../persistence/types.js';
|
|
16
|
+
|
|
17
|
+
// ─── Types ───────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
export type JobStatus = 'pending' | 'running' | 'completed' | 'failed';
|
|
20
|
+
|
|
21
|
+
export interface Job {
|
|
22
|
+
id: string;
|
|
23
|
+
type: string;
|
|
24
|
+
status: JobStatus;
|
|
25
|
+
entryId: string | null;
|
|
26
|
+
payload: Record<string, unknown>;
|
|
27
|
+
dependsOn: string[];
|
|
28
|
+
pipelineId: string | null;
|
|
29
|
+
retryCount: number;
|
|
30
|
+
maxRetries: number;
|
|
31
|
+
result: unknown | null;
|
|
32
|
+
error: string | null;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
startedAt: string | null;
|
|
35
|
+
completedAt: string | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface JobQueueStats {
|
|
39
|
+
pending: number;
|
|
40
|
+
running: number;
|
|
41
|
+
completed: number;
|
|
42
|
+
failed: number;
|
|
43
|
+
total: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface EnqueueOptions {
|
|
47
|
+
entryId?: string;
|
|
48
|
+
payload?: Record<string, unknown>;
|
|
49
|
+
dependsOn?: string[];
|
|
50
|
+
pipelineId?: string;
|
|
51
|
+
maxRetries?: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ─── Class ───────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
export class JobQueue {
|
|
57
|
+
private provider: PersistenceProvider;
|
|
58
|
+
|
|
59
|
+
constructor(provider: PersistenceProvider) {
|
|
60
|
+
this.provider = provider;
|
|
61
|
+
this.initializeTable();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private initializeTable(): void {
|
|
65
|
+
this.provider.execSql(`
|
|
66
|
+
CREATE TABLE IF NOT EXISTS job_queue (
|
|
67
|
+
id TEXT PRIMARY KEY,
|
|
68
|
+
type TEXT NOT NULL,
|
|
69
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
70
|
+
entry_id TEXT,
|
|
71
|
+
payload TEXT DEFAULT '{}',
|
|
72
|
+
depends_on TEXT DEFAULT '[]',
|
|
73
|
+
pipeline_id TEXT,
|
|
74
|
+
retry_count INTEGER DEFAULT 0,
|
|
75
|
+
max_retries INTEGER DEFAULT 3,
|
|
76
|
+
result TEXT,
|
|
77
|
+
error TEXT,
|
|
78
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
79
|
+
started_at TEXT,
|
|
80
|
+
completed_at TEXT
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
CREATE INDEX IF NOT EXISTS idx_job_queue_status ON job_queue(status);
|
|
84
|
+
CREATE INDEX IF NOT EXISTS idx_job_queue_pipeline ON job_queue(pipeline_id);
|
|
85
|
+
`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Enqueue a new job. Returns the job ID.
|
|
90
|
+
*/
|
|
91
|
+
enqueue(type: string, options?: EnqueueOptions): string {
|
|
92
|
+
const id = randomUUID().slice(0, 12);
|
|
93
|
+
this.provider.run(
|
|
94
|
+
`INSERT INTO job_queue (id, type, entry_id, payload, depends_on, pipeline_id, max_retries)
|
|
95
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
96
|
+
[
|
|
97
|
+
id,
|
|
98
|
+
type,
|
|
99
|
+
options?.entryId ?? null,
|
|
100
|
+
JSON.stringify(options?.payload ?? {}),
|
|
101
|
+
JSON.stringify(options?.dependsOn ?? []),
|
|
102
|
+
options?.pipelineId ?? null,
|
|
103
|
+
options?.maxRetries ?? 3,
|
|
104
|
+
],
|
|
105
|
+
);
|
|
106
|
+
return id;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Dequeue the oldest pending job with all dependencies completed.
|
|
111
|
+
* Marks it as running. Returns null if no ready jobs.
|
|
112
|
+
*/
|
|
113
|
+
dequeue(): Job | null {
|
|
114
|
+
const ready = this.dequeueReady(1);
|
|
115
|
+
return ready.length > 0 ? ready[0] : null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Dequeue up to `limit` pending jobs whose dependencies are all completed.
|
|
120
|
+
*/
|
|
121
|
+
dequeueReady(limit: number = 10): Job[] {
|
|
122
|
+
const rows = this.provider.all<JobRow>(
|
|
123
|
+
"SELECT * FROM job_queue WHERE status = 'pending' ORDER BY created_at ASC LIMIT ?",
|
|
124
|
+
[limit * 3], // Over-fetch to filter by deps
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const ready: Job[] = [];
|
|
128
|
+
for (const row of rows) {
|
|
129
|
+
if (ready.length >= limit) break;
|
|
130
|
+
const deps = JSON.parse(row.depends_on) as string[];
|
|
131
|
+
if (deps.length === 0 || this.allDepsCompleted(deps)) {
|
|
132
|
+
this.provider.run(
|
|
133
|
+
"UPDATE job_queue SET status = 'running', started_at = datetime('now') WHERE id = ?",
|
|
134
|
+
[row.id],
|
|
135
|
+
);
|
|
136
|
+
const job = rowToJob(row);
|
|
137
|
+
job.status = 'running';
|
|
138
|
+
ready.push(job);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return ready;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Mark a job as completed with an optional result.
|
|
146
|
+
*/
|
|
147
|
+
complete(jobId: string, result?: unknown): void {
|
|
148
|
+
this.provider.run(
|
|
149
|
+
"UPDATE job_queue SET status = 'completed', completed_at = datetime('now'), result = ? WHERE id = ?",
|
|
150
|
+
[result !== undefined ? JSON.stringify(result) : null, jobId],
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Mark a job as failed with an error message.
|
|
156
|
+
*/
|
|
157
|
+
fail(jobId: string, error: string): void {
|
|
158
|
+
this.provider.run(
|
|
159
|
+
"UPDATE job_queue SET status = 'failed', completed_at = datetime('now'), error = ? WHERE id = ?",
|
|
160
|
+
[error, jobId],
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Retry a failed job (resets to pending). Returns false if max retries exceeded.
|
|
166
|
+
*/
|
|
167
|
+
retry(jobId: string): boolean {
|
|
168
|
+
const row = this.provider.get<JobRow>('SELECT * FROM job_queue WHERE id = ?', [jobId]);
|
|
169
|
+
if (!row) return false;
|
|
170
|
+
if (row.retry_count >= row.max_retries) return false;
|
|
171
|
+
|
|
172
|
+
this.provider.run(
|
|
173
|
+
"UPDATE job_queue SET status = 'pending', retry_count = retry_count + 1, error = NULL, started_at = NULL, completed_at = NULL WHERE id = ?",
|
|
174
|
+
[jobId],
|
|
175
|
+
);
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get queue statistics.
|
|
181
|
+
*/
|
|
182
|
+
getStats(): JobQueueStats {
|
|
183
|
+
const rows = this.provider.all<{ status: string; count: number }>(
|
|
184
|
+
'SELECT status, COUNT(*) as count FROM job_queue GROUP BY status',
|
|
185
|
+
);
|
|
186
|
+
const byStatus: Record<string, number> = {};
|
|
187
|
+
let total = 0;
|
|
188
|
+
for (const row of rows) {
|
|
189
|
+
byStatus[row.status] = row.count;
|
|
190
|
+
total += row.count;
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
pending: byStatus['pending'] ?? 0,
|
|
194
|
+
running: byStatus['running'] ?? 0,
|
|
195
|
+
completed: byStatus['completed'] ?? 0,
|
|
196
|
+
failed: byStatus['failed'] ?? 0,
|
|
197
|
+
total,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Get all jobs for a pipeline.
|
|
203
|
+
*/
|
|
204
|
+
getByPipeline(pipelineId: string): Job[] {
|
|
205
|
+
const rows = this.provider.all<JobRow>(
|
|
206
|
+
'SELECT * FROM job_queue WHERE pipeline_id = ? ORDER BY created_at ASC',
|
|
207
|
+
[pipelineId],
|
|
208
|
+
);
|
|
209
|
+
return rows.map(rowToJob);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get a single job by ID.
|
|
214
|
+
*/
|
|
215
|
+
get(jobId: string): Job | null {
|
|
216
|
+
const row = this.provider.get<JobRow>('SELECT * FROM job_queue WHERE id = ?', [jobId]);
|
|
217
|
+
return row ? rowToJob(row) : null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Purge completed/failed jobs older than N days.
|
|
222
|
+
*/
|
|
223
|
+
purge(olderThanDays: number = 30): number {
|
|
224
|
+
const result = this.provider.run(
|
|
225
|
+
"DELETE FROM job_queue WHERE status IN ('completed', 'failed') AND completed_at < datetime('now', ?)",
|
|
226
|
+
[`-${olderThanDays} days`],
|
|
227
|
+
);
|
|
228
|
+
return result.changes;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ─── Internal ──────────────────────────────────────────────────────
|
|
232
|
+
|
|
233
|
+
private allDepsCompleted(deps: string[]): boolean {
|
|
234
|
+
for (const depId of deps) {
|
|
235
|
+
const row = this.provider.get<{ status: string }>(
|
|
236
|
+
'SELECT status FROM job_queue WHERE id = ?',
|
|
237
|
+
[depId],
|
|
238
|
+
);
|
|
239
|
+
if (!row || row.status !== 'completed') return false;
|
|
240
|
+
}
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ─── Row Types ───────────────────────────────────────────────────────
|
|
246
|
+
|
|
247
|
+
interface JobRow {
|
|
248
|
+
id: string;
|
|
249
|
+
type: string;
|
|
250
|
+
status: string;
|
|
251
|
+
entry_id: string | null;
|
|
252
|
+
payload: string;
|
|
253
|
+
depends_on: string;
|
|
254
|
+
pipeline_id: string | null;
|
|
255
|
+
retry_count: number;
|
|
256
|
+
max_retries: number;
|
|
257
|
+
result: string | null;
|
|
258
|
+
error: string | null;
|
|
259
|
+
created_at: string;
|
|
260
|
+
started_at: string | null;
|
|
261
|
+
completed_at: string | null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function rowToJob(row: JobRow): Job {
|
|
265
|
+
return {
|
|
266
|
+
id: row.id,
|
|
267
|
+
type: row.type,
|
|
268
|
+
status: row.status as JobStatus,
|
|
269
|
+
entryId: row.entry_id,
|
|
270
|
+
payload: JSON.parse(row.payload) as Record<string, unknown>,
|
|
271
|
+
dependsOn: JSON.parse(row.depends_on) as string[],
|
|
272
|
+
pipelineId: row.pipeline_id,
|
|
273
|
+
retryCount: row.retry_count,
|
|
274
|
+
maxRetries: row.max_retries,
|
|
275
|
+
result: row.result ? JSON.parse(row.result) : null,
|
|
276
|
+
error: row.error,
|
|
277
|
+
createdAt: row.created_at,
|
|
278
|
+
startedAt: row.started_at,
|
|
279
|
+
completedAt: row.completed_at,
|
|
280
|
+
};
|
|
281
|
+
}
|