@ijfw/memory-server 1.4.4 → 1.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/fixtures/truncation-corpus/_generate-corpus.js +367 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-01/events.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-01/intent-journal.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-01/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-01/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-02/events.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-02/intent-journal.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-02/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-02/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-03/events.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-03/intent-journal.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-03/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-03/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-04/events.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-04/intent-journal.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-04/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-04/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-05/events.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-05/intent-journal.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-05/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-01-clean-exit-05/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-01/events.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-01/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-01/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-01/snapshots/v-midO-1-advance.json +11 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-01/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-02/events.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-02/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-02/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-02/snapshots/v-midO-2-advance.json +11 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-02/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-03/events.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-03/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-03/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-03/snapshots/v-midO-3-advance.json +11 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-03/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-04/events.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-04/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-04/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-04/snapshots/v-midO-4-advance.json +11 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-04/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-05/events.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-05/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-05/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-05/snapshots/v-midO-5-advance.json +11 -0
- package/fixtures/truncation-corpus/fx-02-mid-overwrite-05/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-01/events.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-01/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-01/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-01/target/.ijfw/blackboard/decisions.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-02/events.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-02/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-02/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-02/target/.ijfw/blackboard/decisions.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-03/events.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-03/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-03/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-03/target/.ijfw/blackboard/decisions.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-04/events.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-04/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-04/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-04/target/.ijfw/blackboard/decisions.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-05/events.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-05/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-05/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-03-mid-append-05/target/.ijfw/blackboard/decisions.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-04-no-events-01/events.jsonl +0 -0
- package/fixtures/truncation-corpus/fx-04-no-events-01/intent-journal.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-04-no-events-01/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-04-no-events-01/snapshots/v-noEv-1-set-phase.json +11 -0
- package/fixtures/truncation-corpus/fx-04-no-events-01/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-04-no-events-02/events.jsonl +0 -0
- package/fixtures/truncation-corpus/fx-04-no-events-02/intent-journal.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-04-no-events-02/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-04-no-events-02/snapshots/v-noEv-2-set-phase.json +11 -0
- package/fixtures/truncation-corpus/fx-04-no-events-02/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-04-no-events-03/events.jsonl +0 -0
- package/fixtures/truncation-corpus/fx-04-no-events-03/intent-journal.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-04-no-events-03/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-04-no-events-03/snapshots/v-noEv-3-set-phase.json +11 -0
- package/fixtures/truncation-corpus/fx-04-no-events-03/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-04-no-events-04/events.jsonl +0 -0
- package/fixtures/truncation-corpus/fx-04-no-events-04/intent-journal.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-04-no-events-04/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-04-no-events-04/snapshots/v-noEv-4-set-phase.json +11 -0
- package/fixtures/truncation-corpus/fx-04-no-events-04/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-04-no-events-05/events.jsonl +0 -0
- package/fixtures/truncation-corpus/fx-04-no-events-05/intent-journal.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-04-no-events-05/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-04-no-events-05/snapshots/v-noEv-5-set-phase.json +11 -0
- package/fixtures/truncation-corpus/fx-04-no-events-05/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-01/events.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-01/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-01/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-01/snapshots/v-errT-1-partial.json +11 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-01/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-02/events.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-02/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-02/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-02/target/.ijfw/blackboard/decisions.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-03/events.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-03/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-03/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-03/snapshots/v-errT-3-partial.json +11 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-03/target/.ijfw/state/workflow.json +1 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-04/events.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-04/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-04/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-04/target/.ijfw/blackboard/decisions.jsonl +1 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-05/events.jsonl +2 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-05/intent-journal.jsonl +3 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-05/meta.json +18 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-05/snapshots/v-errT-5-partial.json +11 -0
- package/fixtures/truncation-corpus/fx-05-error-terminated-05/target/.ijfw/state/workflow.json +1 -0
- package/package.json +1 -1
- package/src/active-extension-writer.js +144 -64
- package/src/api-client.js +43 -5
- package/src/audit-roster.js +80 -5
- package/src/blackboard.js +298 -6
- package/src/cli-run.js +33 -5
- package/src/codex-agents.js +96 -5
- package/src/cost/aggregator.js +39 -9
- package/src/cost/pricing.js +57 -0
- package/src/cost/readers/gemini.js +1 -1
- package/src/cross-audit-chunker.js +189 -0
- package/src/cross-dispatcher.js +124 -21
- package/src/cross-orchestrator-cli.js +550 -14
- package/src/cross-orchestrator.js +1016 -17
- package/src/cross-project-search.js +195 -9
- package/src/dashboard-client-waves.html +304 -0
- package/src/dashboard-client.html +5 -1
- package/src/dashboard-server.js +73 -0
- package/src/deploy-alerts.js +150 -0
- package/src/design/iframe-bridge.js +242 -0
- package/src/design-companion.js +144 -0
- package/src/dispatch/checkpoint-cli.js +97 -0
- package/src/dispatch/colon-syntax.js +81 -1
- package/src/dispatch/extension.js +26 -2
- package/src/dispatch/registry-cli.js +4 -1
- package/src/dispatch/wave-cli.js +201 -6
- package/src/dispatch/worktree-cli.js +40 -0
- package/src/dispatch-planner.js +97 -2
- package/src/dream/runner.mjs +47 -11
- package/src/dream/stage-runner.js +40 -0
- package/src/dream/state-file.js +102 -0
- package/src/extension-installer.js +70 -24
- package/src/extension-quota-tracker.js +4 -2
- package/src/extension-registry.js +289 -35
- package/src/feedback-detector.js +26 -0
- package/src/fs-lock.js +259 -7
- package/src/gate-result.js +95 -1
- package/src/hero-line.js +86 -5
- package/src/intent-router.js +35 -0
- package/src/lib/a11y-contract.js +117 -0
- package/src/lib/atomic-io.js +29 -8
- package/src/lib/cache-keepalive.js +150 -0
- package/src/lib/jsonl-rotation.js +104 -0
- package/src/lib/lighthouse-pillar.js +121 -0
- package/src/lib/llm-call.js +121 -0
- package/src/lib/playwright-baseline.js +205 -0
- package/src/lib/rekor-bridge.js +221 -0
- package/src/lib/repo-map.js +392 -0
- package/src/lib/shasum-verify.js +164 -0
- package/src/lib/sketches-gc.js +132 -0
- package/src/lib/tmp-suffix.js +62 -0
- package/src/lib/ui-review-runner.js +554 -0
- package/src/lib/uispec-drift.js +301 -0
- package/src/lib/uispec-intake.js +381 -0
- package/src/lib/worktree-guards.js +118 -0
- package/src/lib/worktree-recovery.js +100 -0
- package/src/memory/auto-linker.js +152 -0
- package/src/memory/benchmark.js +498 -0
- package/src/memory/dedup.js +126 -0
- package/src/memory/embedding-cache.js +136 -0
- package/src/memory/fact-extractor.js +168 -0
- package/src/memory/fts5.js +65 -1
- package/src/memory/migrations/004-bitemporal.js +91 -0
- package/src/memory/migrations/005-vector-cache.js +61 -0
- package/src/memory/migrations/006-obsidian-graph.js +46 -0
- package/src/memory/migrations/007-skill-telemetry.js +24 -0
- package/src/memory/migrations/008-write-provenance.js +41 -0
- package/src/memory/obsidian-parser.js +91 -0
- package/src/memory/query-dataview.js +86 -0
- package/src/memory/search.js +10 -0
- package/src/memory/temporal.js +529 -0
- package/src/memory/tokenize.js +10 -0
- package/src/memory-facts-handler.js +37 -0
- package/src/memory-feedback.js +260 -2
- package/src/model-refresh.js +292 -0
- package/src/observability/cost-anomaly.js +166 -0
- package/src/observability/evaluator-checkpoint-contract.js +117 -0
- package/src/observability/trace-id.js +163 -0
- package/src/orchestrator/agents-md-blackboard.js +152 -0
- package/src/orchestrator/checkpoint-contract.md +140 -0
- package/src/orchestrator/debug-trident.js +570 -0
- package/src/orchestrator/merge-block-aware.js +350 -0
- package/src/orchestrator/plan-checker.js +475 -0
- package/src/orchestrator/post-done-runner.js +249 -0
- package/src/orchestrator/review.js +38 -3
- package/src/orchestrator/runtime-loop.js +430 -0
- package/src/orchestrator/skill-telemetry-sink.js +29 -0
- package/src/orchestrator/skill-telemetry.js +37 -0
- package/src/orchestrator/state-events.js +459 -0
- package/src/orchestrator/state-sdk.js +1764 -0
- package/src/orchestrator/status-protocol.js +84 -17
- package/src/orchestrator/subagent-telemetry.js +452 -0
- package/src/orchestrator/termination.js +160 -0
- package/src/orchestrator/verification-gate.js +200 -16
- package/src/orchestrator/wave-state.js +332 -23
- package/src/orchestrator/worktree-provision.js +77 -0
- package/src/override-use-registry.js +111 -5
- package/src/receipts.js +36 -4
- package/src/recovery/checkpoint.js +56 -3
- package/src/recovery/code-fixer.js +656 -0
- package/src/recovery/truncation.js +317 -0
- package/src/redactor.js +75 -6
- package/src/runtime-mediator.js +15 -0
- package/src/sanitizer.js +10 -0
- package/src/search-hybrid.js +139 -0
- package/src/server.js +603 -59
- package/src/swarm/worktree.js +27 -4
- package/src/swarm-config.js +94 -17
- package/src/team/domain-templates/book.json +51 -0
- package/src/team/domain-templates/business.json +41 -0
- package/src/team/domain-templates/content.json +50 -0
- package/src/team/domain-templates/design.json +44 -0
- package/src/team/domain-templates/research.json +41 -0
- package/src/team/domain-templates/software.json +40 -0
- package/src/team/generator.js +278 -3
- package/src/team/modify.js +203 -0
- package/src/team/schemas.js +48 -0
- package/src/update-apply.js +19 -3
package/src/receipts.js
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
import fs from 'node:fs';
|
|
11
11
|
import path from 'node:path';
|
|
12
|
+
// v1.5.0 N4.obs M1: tag every receipt with the orchestrator's trace_id so the
|
|
13
|
+
// dashboard can roll up sessions->traces->observations like Langfuse / Helicone.
|
|
14
|
+
import { getTraceId } from './observability/trace-id.js';
|
|
12
15
|
|
|
13
16
|
export function RECEIPTS_FILE(projectDir) {
|
|
14
17
|
return path.join(projectDir, '.ijfw', 'receipts', 'cross-runs.jsonl');
|
|
@@ -24,7 +27,13 @@ export function writeReceipt(projectDir, record) {
|
|
|
24
27
|
const dest = RECEIPTS_FILE(projectDir);
|
|
25
28
|
const dir = path.dirname(dest);
|
|
26
29
|
fs.mkdirSync(dir, { recursive: true });
|
|
27
|
-
|
|
30
|
+
// v1.5.0 N4.obs M1: tag with trace_id if one is set + caller hasn't supplied
|
|
31
|
+
// one. Never overwrite an explicit caller-supplied trace_id.
|
|
32
|
+
const traceId = getTraceId();
|
|
33
|
+
const enriched = (traceId && record && typeof record === 'object' && !record.trace_id)
|
|
34
|
+
? { ...record, trace_id: traceId }
|
|
35
|
+
: record;
|
|
36
|
+
fs.appendFileSync(dest, JSON.stringify(enriched) + '\n');
|
|
28
37
|
_pruneReceipts(dest);
|
|
29
38
|
}
|
|
30
39
|
|
|
@@ -46,8 +55,27 @@ export function purgeReceipts(projectDir) {
|
|
|
46
55
|
return count;
|
|
47
56
|
}
|
|
48
57
|
|
|
49
|
-
//
|
|
50
|
-
|
|
58
|
+
// v1.5.0 audit-LOW-obs-L2: per-tier cache-read savings rate.
|
|
59
|
+
//
|
|
60
|
+
// Anthropic prompt caching: a cached read costs ~10% of an uncached input
|
|
61
|
+
// token. Savings are computed as (uncached_input_rate - cached_read_rate),
|
|
62
|
+
// which collapses to (0.9 * input_rate) per cached-read token. Values are
|
|
63
|
+
// derived from the canonical pricing table (mcp-server/src/cost/pricing.js).
|
|
64
|
+
//
|
|
65
|
+
// Default tier remains sonnet (matches the prior single-constant behaviour
|
|
66
|
+
// and is the dominant model on the hero-line surface), but cache_stats
|
|
67
|
+
// records that carry a `model` field now dispatch to the right rate.
|
|
68
|
+
const SONNET_CACHE_SAVINGS_PER_TOKEN = 2.70 / 1_000_000;
|
|
69
|
+
const OPUS_CACHE_SAVINGS_PER_TOKEN = 13.50 / 1_000_000;
|
|
70
|
+
const HAIKU_CACHE_SAVINGS_PER_TOKEN = 0.72 / 1_000_000;
|
|
71
|
+
|
|
72
|
+
function cacheSavingsPerTokenFor(model) {
|
|
73
|
+
if (typeof model !== 'string' || !model) return SONNET_CACHE_SAVINGS_PER_TOKEN;
|
|
74
|
+
const m = model.toLowerCase();
|
|
75
|
+
if (m.includes('opus')) return OPUS_CACHE_SAVINGS_PER_TOKEN;
|
|
76
|
+
if (m.includes('haiku')) return HAIKU_CACHE_SAVINGS_PER_TOKEN;
|
|
77
|
+
return SONNET_CACHE_SAVINGS_PER_TOKEN;
|
|
78
|
+
}
|
|
51
79
|
|
|
52
80
|
// renderReceipt(record, phaseWave?, stepNum?)
|
|
53
81
|
// phaseWave -- caller-supplied label for the narration header. Default is
|
|
@@ -101,7 +129,11 @@ export function renderReceipt(record, phaseWave = 'Trident', stepNum = 1) {
|
|
|
101
129
|
lines.push(`Step ${stepNum}.4 -- cache created: ${cs.cache_creation_input_tokens} tokens`);
|
|
102
130
|
}
|
|
103
131
|
if (typeof cs.cache_read_input_tokens === 'number') {
|
|
104
|
-
|
|
132
|
+
// v1.5.0 audit-LOW-obs-L2: dispatch on cache_stats.model when set;
|
|
133
|
+
// fall back to receipt-level model; finally fall back to sonnet.
|
|
134
|
+
const modelForRate = cs.model || record.model || null;
|
|
135
|
+
const rate = cacheSavingsPerTokenFor(modelForRate);
|
|
136
|
+
const saved = cs.cache_read_input_tokens * rate;
|
|
105
137
|
const savedStr = saved >= 0.01 ? ` (~$${saved.toFixed(2)} saved)` : '';
|
|
106
138
|
lines.push(`Step ${stepNum}.5 -- cache read: ${cs.cache_read_input_tokens} tokens${savedStr}`);
|
|
107
139
|
}
|
|
@@ -4,10 +4,15 @@
|
|
|
4
4
|
// not a replacement for IJFW memory, but they make recovery possible when chat
|
|
5
5
|
// context or a generated memory summary goes missing.
|
|
6
6
|
|
|
7
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync } from 'node:fs';
|
|
7
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
8
8
|
import { basename, join, resolve } from 'node:path';
|
|
9
9
|
import { writeAtomic } from '../lib/atomic-io.js';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
appendBlackboardEvent,
|
|
12
|
+
blackboardPaths,
|
|
13
|
+
blackboardStatus,
|
|
14
|
+
readBlackboard,
|
|
15
|
+
} from '../blackboard.js';
|
|
11
16
|
import { readTeamAssembly } from '../team/generator.js';
|
|
12
17
|
import { buildSwarmPlan } from '../swarm/planner.js';
|
|
13
18
|
|
|
@@ -89,13 +94,43 @@ export function listCheckpoints(projectRoot = process.cwd()) {
|
|
|
89
94
|
.map((file) => join(paths.dir, file));
|
|
90
95
|
}
|
|
91
96
|
|
|
97
|
+
// v1.5.0 audit-LOW-work-L2: memoise buildSnapshot per (projectRoot, ms).
|
|
98
|
+
// Snapshot construction reads team + plan + blackboard, which are themselves
|
|
99
|
+
// I/O-heavy reads. The bb mtime cache already shortcuts the inner reads, but
|
|
100
|
+
// when a caller does back-to-back createCheckpoint() calls (e.g. on a wave
|
|
101
|
+
// boundary) we still re-build the wrapper N times. Memo is keyed on the
|
|
102
|
+
// project root + blackboard mtimes + ts so any state change invalidates;
|
|
103
|
+
// hot-path cache size is capped at 8 entries to stay tiny.
|
|
104
|
+
const SNAPSHOT_CACHE = new Map();
|
|
105
|
+
const SNAPSHOT_CACHE_MAX = 8;
|
|
106
|
+
|
|
107
|
+
function snapshotCacheKey(projectRoot, ts) {
|
|
108
|
+
const paths = blackboardPaths(projectRoot);
|
|
109
|
+
let tasksMtime = 0, claimsMtime = 0;
|
|
110
|
+
try { tasksMtime = statSync(paths.tasks).mtimeMs; } catch { /* default 0 */ }
|
|
111
|
+
try { claimsMtime = statSync(paths.claims).mtimeMs; } catch { /* default 0 */ }
|
|
112
|
+
return `${paths.root}::${ts}::${tasksMtime}::${claimsMtime}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
92
115
|
function buildSnapshot(projectRoot, meta) {
|
|
116
|
+
const cacheKey = snapshotCacheKey(projectRoot, meta.ts);
|
|
117
|
+
const cached = SNAPSHOT_CACHE.get(cacheKey);
|
|
118
|
+
if (cached) {
|
|
119
|
+
// Cached body is independent of meta.id / meta.label / meta.message;
|
|
120
|
+
// those are reapplied from the current call.
|
|
121
|
+
return {
|
|
122
|
+
...cached,
|
|
123
|
+
id: meta.id,
|
|
124
|
+
label: meta.label,
|
|
125
|
+
message: meta.message || null,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
93
128
|
const blackboard = readBlackboard(projectRoot);
|
|
94
129
|
const team = readTeamAssembly(projectRoot);
|
|
95
130
|
const plan = buildSwarmPlan(projectRoot);
|
|
96
131
|
const status = blackboardStatus(projectRoot);
|
|
97
132
|
const tasks = blackboard.tasks.data.tasks || [];
|
|
98
|
-
|
|
133
|
+
const snapshot = {
|
|
99
134
|
schema_version: 'ijfw-checkpoint/v1',
|
|
100
135
|
id: meta.id,
|
|
101
136
|
label: meta.label,
|
|
@@ -122,6 +157,24 @@ function buildSnapshot(projectRoot, meta) {
|
|
|
122
157
|
recent: blackboard.recent,
|
|
123
158
|
next: recommendedNext(team, plan, tasks),
|
|
124
159
|
};
|
|
160
|
+
// Stash a meta-agnostic copy in the cache (id/label/message reapplied on hit).
|
|
161
|
+
SNAPSHOT_CACHE.set(cacheKey, {
|
|
162
|
+
...snapshot,
|
|
163
|
+
id: null,
|
|
164
|
+
label: null,
|
|
165
|
+
message: null,
|
|
166
|
+
});
|
|
167
|
+
// Narrow LRU: cap the cache size and drop the oldest insertion when over.
|
|
168
|
+
if (SNAPSHOT_CACHE.size > SNAPSHOT_CACHE_MAX) {
|
|
169
|
+
const firstKey = SNAPSHOT_CACHE.keys().next().value;
|
|
170
|
+
if (firstKey !== undefined) SNAPSHOT_CACHE.delete(firstKey);
|
|
171
|
+
}
|
|
172
|
+
return snapshot;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Exposed for tests / cache invalidation hooks.
|
|
176
|
+
export function _resetSnapshotCache() {
|
|
177
|
+
SNAPSHOT_CACHE.clear();
|
|
125
178
|
}
|
|
126
179
|
|
|
127
180
|
function renderCheckpoint(snapshot) {
|