forge-workflow 0.1.0-beta.4 → 0.1.0-beta.6
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/AGENTS.md +18 -7
- package/CHANGELOG.md +79 -1
- package/CLAUDE.md +0 -12
- package/CODING_STANDARDS.md +72 -0
- package/README.md +6 -2
- package/bin/forge-cmd.js +20 -0
- package/bin/forge.js +28 -375
- package/docs/INDEX.md +1 -1
- package/docs/guides/BEADS_GITHUB_SYNC.md +2 -31
- package/docs/guides/MIGRATION.md +4 -4
- package/docs/guides/SETUP.md +16 -16
- package/docs/reference/COMMANDS.md +8 -5
- package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +4 -0
- package/docs/reference/INSIGHTS_RECAP.md +9 -20
- package/docs/reference/INSTALL.md +4 -0
- package/docs/reference/LEGACY_CLAIM_REPAIR.md +112 -0
- package/docs/reference/RELEASE.md +5 -3
- package/docs/reference/TOOLCHAIN.md +8 -0
- package/docs/reference/github-accounts.md +134 -0
- package/docs/reference/protected-state-surfaces.md +4 -4
- package/docs/reference/shepherd.md +114 -35
- package/lefthook.yml +12 -0
- package/lib/activation/ensure-forge-home.js +33 -15
- package/lib/adapters/pr-state-adapter.js +359 -144
- package/lib/audit-evidence.js +71 -110
- package/lib/base-remote.js +138 -0
- package/lib/beta5-compatibility-evidence.js +1093 -0
- package/lib/bun-lockfile-proof.js +413 -0
- package/lib/bun-workflow-pins.js +461 -0
- package/lib/capabilities/index.js +9 -0
- package/lib/capabilities/model.js +141 -0
- package/lib/capabilities/probes.js +347 -0
- package/lib/capped-jsonl-log.js +236 -0
- package/lib/codex-skills.js +2 -2
- package/lib/commands/_manifest.js +1 -0
- package/lib/commands/_registry.js +50 -20
- package/lib/commands/clean.js +252 -32
- package/lib/commands/dev.js +4 -33
- package/lib/commands/doctor.js +37 -6
- package/lib/commands/gate.js +197 -27
- package/lib/commands/github.js +215 -0
- package/lib/commands/hooks.js +276 -30
- package/lib/commands/insights.js +8 -3
- package/lib/commands/memory.js +66 -2
- package/lib/commands/merge.js +1265 -58
- package/lib/commands/plan.js +33 -2
- package/lib/commands/pr.js +3 -1
- package/lib/commands/preflight.js +21 -4
- package/lib/commands/prime.js +21 -8
- package/lib/commands/push.js +146 -54
- package/lib/commands/recall.js +127 -49
- package/lib/commands/recap.js +6 -1
- package/lib/commands/release.js +39 -3
- package/lib/commands/remember.js +28 -4
- package/lib/commands/serve.js +26 -9
- package/lib/commands/setup.js +323 -98
- package/lib/commands/shepherd.js +591 -73
- package/lib/commands/ship.js +36 -91
- package/lib/commands/skill.js +127 -11
- package/lib/commands/status.js +17 -1
- package/lib/commands/team.js +47 -8
- package/lib/commands/test.js +187 -38
- package/lib/commands/validate.js +65 -21
- package/lib/commands/worktree.js +359 -45
- package/lib/core/runtime-graph.js +1 -1
- package/lib/doc-assertions.js +297 -0
- package/lib/existing-tdd-gate.js +253 -0
- package/lib/fixtures/beta5-corpus/v1/README.md +9 -0
- package/lib/fixtures/beta5-corpus/v1/contract/command-contract.json +26 -0
- package/lib/fixtures/beta5-corpus/v1/contract/package-contract.json +13 -0
- package/lib/fixtures/beta5-corpus/v1/contract/workflow-stage-matrix.json +8 -0
- package/lib/fixtures/beta5-corpus/v1/manifest.json +25 -0
- package/lib/fixtures/beta5-corpus/v1/state/comments.jsonl +1 -0
- package/lib/fixtures/beta5-corpus/v1/state/config.yaml +6 -0
- package/lib/fixtures/beta5-corpus/v1/state/dependencies.jsonl +1 -0
- package/lib/fixtures/beta5-corpus/v1/state/issues.jsonl +2 -0
- package/lib/fixtures/beta5-corpus/v1/state/kernel.sql +20 -0
- package/lib/forge-context.js +1 -4
- package/lib/forge-issues.js +134 -32
- package/lib/gate-events.js +98 -10
- package/lib/git-defaults.js +56 -0
- package/lib/github-context.js +308 -0
- package/lib/global-flags.js +1 -0
- package/lib/harness-capability-matrix.js +3 -3
- package/lib/hook-renderer.js +122 -5
- package/lib/insights.js +96 -80
- package/lib/issue-render.js +19 -0
- package/lib/kernel/backing-issue.js +14 -2
- package/lib/kernel/broker.js +739 -31
- package/lib/kernel/claim-reconciler.js +238 -0
- package/lib/kernel/cli-broker-factory.js +12 -1
- package/lib/kernel/close-on-merge.js +154 -0
- package/lib/kernel/fs-class.js +42 -25
- package/lib/kernel/lease-enforcer.js +9 -4
- package/lib/kernel/legacy-claim-repair.js +442 -0
- package/lib/kernel/live-claim-projection.js +26 -0
- package/lib/kernel/migrations.js +118 -3
- package/lib/kernel/readiness-model.js +184 -12
- package/lib/kernel/schema.js +49 -1
- package/lib/kernel/sqlite-driver.js +3435 -172
- package/lib/kernel/taxonomy-validator.js +4 -1
- package/lib/kernel/windows-private-acl.js +239 -0
- package/lib/lefthook-wiring.js +21 -1
- package/lib/memory/hygiene.js +191 -0
- package/lib/memory/router.js +110 -28
- package/lib/memory/usage-evidence.js +4 -0
- package/lib/memory-digest.js +106 -15
- package/lib/memory-recall-events.js +145 -0
- package/lib/memory-recall.js +71 -10
- package/lib/merge-rules.js +143 -21
- package/lib/npm-publish-workflow.js +465 -0
- package/lib/orientation.js +68 -43
- package/lib/package-root.js +2 -0
- package/lib/plugin-catalog.js +14 -4
- package/lib/pr-bundle.js +5 -6
- package/lib/pr-monitor/auto-actions.js +169 -28
- package/lib/pr-monitor/differ.js +110 -4
- package/lib/pr-monitor/events.js +0 -0
- package/lib/pr-monitor/flow-monitor.js +1424 -0
- package/lib/pr-monitor/gather.js +251 -44
- package/lib/pr-monitor/journal.js +18 -39
- package/lib/pr-monitor/monitor.js +117 -10
- package/lib/pr-monitor/process-identity.js +117 -0
- package/lib/pr-monitor/reconcile-executor.js +1129 -470
- package/lib/pr-monitor/reconcile.js +0 -0
- package/lib/pr-monitor/render-summary.js +293 -0
- package/lib/pr-monitor/review-preflight.js +269 -0
- package/lib/pr-monitor/shepherd-lease.js +38 -20
- package/lib/pr-monitor/verdict.js +438 -0
- package/lib/pr-monitor/watch-lifecycle.js +145 -27
- package/lib/pr-monitor/watch-owner.js +1414 -0
- package/lib/pr-monitor/watch.js +129 -58
- package/lib/pr-pull.js +33 -14
- package/lib/pr-shepherd.js +51 -11
- package/lib/preflight/gates.js +65 -18
- package/lib/preflight/runner.js +5 -0
- package/lib/project-memory.js +178 -4
- package/lib/protected-state-authority.js +1100 -0
- package/lib/protected-state-surfaces.js +243 -45
- package/lib/release-readiness.js +53 -7
- package/lib/review-adapter.js +65 -0
- package/lib/shell-utils.js +1 -1
- package/lib/skills-sync.js +71 -35
- package/lib/smart-merge.js +28 -4
- package/lib/symlink-utils.js +74 -26
- package/lib/upgrade-safety.js +39 -0
- package/lib/using-forge.js +19 -6
- package/lib/validation/risk-manifest.js +339 -0
- package/lib/workflow/enforce-stage.js +44 -0
- package/lib/workflow/plan-authority.js +225 -0
- package/package.json +12 -9
- package/scripts/commitlint.js +13 -15
- package/scripts/doc-asserting-tests.js +158 -0
- package/scripts/generate-risk-manifest.js +91 -0
- package/scripts/github-context-bridge.sh +10 -0
- package/scripts/legacy-claim-repair.js +145 -0
- package/scripts/lib/behavioral-eval-runner.js +310 -0
- package/scripts/lib/behavioral-eval-runtime.js +457 -0
- package/scripts/lib/eval-evidence.js +328 -0
- package/scripts/lib/eval-runner.js +81 -41
- package/scripts/lib/immutable-eval-corpus.js +309 -0
- package/scripts/lib/promotion-evidence-loader.js +94 -0
- package/scripts/lib/promotion-scorecard.js +314 -0
- package/scripts/npm-release-receipt.js +134 -0
- package/scripts/process-tree.js +773 -0
- package/scripts/protected-state-check.js +479 -31
- package/scripts/run-command-eval.js +29 -1
- package/scripts/sync-agent-skills.js +333 -34
- package/scripts/sync-d20-audit.js +172 -0
- package/scripts/test-full-suite.js +935 -37
- package/scripts/test-profile.js +13 -3
- package/scripts/test.js +271 -57
- package/skills/coverage.json +1 -0
- package/skills/review/SKILL.md +6 -11
- package/skills/review/evals/scorecard.json +4 -4
- package/skills/rollback/SKILL.md +4 -11
- package/skills/rollback/evals/scorecard.json +3 -3
- package/skills/setup/SKILL.md +18 -0
- package/skills/setup/evals/scorecard.json +3 -3
- package/skills/shepherd/SKILL.md +39 -16
- package/skills/shepherd/evals/scorecard.json +4 -4
- package/skills/ship/SKILL.md +4 -12
- package/skills/ship/evals/scorecard.json +3 -3
- package/skills/validate/SKILL.md +3 -0
- package/skills/validate/evals/scorecard.json +1 -1
- package/skills/worktree/SKILL.md +6 -1
- package/skills/worktree/evals/scorecard.json +2 -2
- package/lib/beads-setup.js +0 -538
- package/lib/beads-sync-scaffold.js +0 -189
- package/lib/pat-setup.js +0 -207
- package/lib/pr-monitor/render-sticky.js +0 -206
- package/lib/pr-monitor/upsert-sticky.js +0 -169
- package/scripts/beads-context.sh +0 -577
- package/scripts/beads-migrate-to-dolt.sh +0 -7
- package/scripts/beads-upgrade-smoke.sh +0 -284
- package/scripts/lib/beads-migrate-to-dolt.mjs +0 -503
package/lib/preflight/runner.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* @typedef {Object} GateOutcome
|
|
20
20
|
* @property {boolean} ok - Whether the gate passed.
|
|
21
21
|
* @property {string} [summary] - Short human-readable result line.
|
|
22
|
+
* @property {string} [inputFingerprint] - Exact input snapshot tested by the gate.
|
|
22
23
|
*
|
|
23
24
|
* @typedef {Object} Gate
|
|
24
25
|
* @property {string} name
|
|
@@ -30,6 +31,7 @@
|
|
|
30
31
|
* @property {boolean} skipped
|
|
31
32
|
* @property {string} summary
|
|
32
33
|
* @property {number} [durationMs]
|
|
34
|
+
* @property {string} [inputFingerprint]
|
|
33
35
|
*/
|
|
34
36
|
|
|
35
37
|
/**
|
|
@@ -66,6 +68,9 @@ async function executeGate(gate) {
|
|
|
66
68
|
skipped,
|
|
67
69
|
summary: outcome?.summary || '',
|
|
68
70
|
durationMs,
|
|
71
|
+
...(typeof outcome?.inputFingerprint === 'string'
|
|
72
|
+
? { inputFingerprint: outcome.inputFingerprint }
|
|
73
|
+
: {}),
|
|
69
74
|
};
|
|
70
75
|
}
|
|
71
76
|
|
package/lib/project-memory.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { createHash, randomUUID } = require('node:crypto');
|
|
6
|
+
const { types: { isProxy } } = require('node:util');
|
|
3
7
|
const { resolveKernelDatabasePath } = require('./kernel/cli-broker-factory');
|
|
8
|
+
const { resolveGitCommonDir } = require('./kernel/broker');
|
|
4
9
|
const { createBuiltinSQLiteDriver } = require('./kernel/sqlite-driver');
|
|
10
|
+
const { normalizeRecallHit } = require('./memory-recall');
|
|
11
|
+
const { createUsageEvidenceStore } = require('../packages/memory');
|
|
5
12
|
|
|
6
13
|
// Project memory is a Forge read model persisted in the kernel store (kernel_memories),
|
|
7
14
|
// written DIRECTLY rather than through the issue CAS/guarded-event path. The store seam
|
|
@@ -30,6 +37,24 @@ function resolveStore(projectRoot, options = {}) {
|
|
|
30
37
|
return options.store ?? defaultStore(projectRoot, options);
|
|
31
38
|
}
|
|
32
39
|
|
|
40
|
+
function resolveProjectId(projectRoot, options = {}) {
|
|
41
|
+
const platform = options.platform || process.platform;
|
|
42
|
+
const pathImpl = platform === 'win32' ? path.win32 : path.posix;
|
|
43
|
+
const commonDir = options.gitCommonDir || resolveGitCommonDir(projectRoot, options);
|
|
44
|
+
const absolute = pathImpl.resolve(projectRoot, commonDir);
|
|
45
|
+
const realpath = options.realpath || fs.realpathSync.native;
|
|
46
|
+
let canonical;
|
|
47
|
+
try {
|
|
48
|
+
canonical = realpath(absolute);
|
|
49
|
+
} catch {
|
|
50
|
+
canonical = absolute;
|
|
51
|
+
}
|
|
52
|
+
canonical = canonical.replaceAll('\\', '/');
|
|
53
|
+
return platform === 'win32'
|
|
54
|
+
? canonical.toLowerCase()
|
|
55
|
+
: canonical;
|
|
56
|
+
}
|
|
57
|
+
|
|
33
58
|
function assertEntryObject(entry) {
|
|
34
59
|
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
|
|
35
60
|
throw new TypeError('project memory entry must be an object');
|
|
@@ -124,27 +149,169 @@ function list(projectRoot, options = {}) {
|
|
|
124
149
|
// driver so recall never loads and re-sorts the whole table. `options.agents` (a
|
|
125
150
|
// source_agent allow-list) scopes the read, e.g. to human `remember` notes only.
|
|
126
151
|
function recent(projectRoot, limit, options = {}) {
|
|
127
|
-
return resolveStore(projectRoot, options).recentMemories(limit, {
|
|
152
|
+
return resolveStore(projectRoot, options).recentMemories(limit, {
|
|
153
|
+
agents: options.agents,
|
|
154
|
+
kind: options.kind,
|
|
155
|
+
});
|
|
128
156
|
}
|
|
129
157
|
|
|
130
158
|
// Total stored memories (optionally scoped by `options.agents`) — paired with `recent` so
|
|
131
159
|
// recall can report "showing N of TOTAL".
|
|
132
160
|
function count(projectRoot, options = {}) {
|
|
133
|
-
return resolveStore(projectRoot, options).countMemories({
|
|
161
|
+
return resolveStore(projectRoot, options).countMemories({
|
|
162
|
+
agents: options.agents,
|
|
163
|
+
kind: options.kind,
|
|
164
|
+
});
|
|
134
165
|
}
|
|
135
166
|
|
|
136
167
|
// BM25 top-N recall over the FTS5 index (token-AND). Unlike `search` (the legacy LIKE
|
|
137
168
|
// helper) this does not short-circuit an empty query — the driver falls back to recent so
|
|
138
169
|
// recall stays capped either way.
|
|
139
170
|
function searchRanked(projectRoot, query, limit, options = {}) {
|
|
140
|
-
return resolveStore(projectRoot, options).searchMemoriesRanked(query, limit
|
|
171
|
+
return resolveStore(projectRoot, options).searchMemoriesRanked(query, limit, {
|
|
172
|
+
kind: options.kind,
|
|
173
|
+
});
|
|
141
174
|
}
|
|
142
175
|
|
|
143
176
|
// Relevance-only BM25 recall that returns the raw bm25 `score` per entry, so a caller can
|
|
144
177
|
// apply a relevance floor. A no-match/empty query returns [] (no recency fallback). The
|
|
145
178
|
// per-turn memory-recall hook uses this to inject nothing unless a note clearly matches.
|
|
146
179
|
function searchRankedScored(projectRoot, query, limit, options = {}) {
|
|
147
|
-
|
|
180
|
+
const projectId = resolveProjectId(projectRoot, options);
|
|
181
|
+
const searchOptions = {
|
|
182
|
+
projectId,
|
|
183
|
+
excludeKeys: options.excludeKeys || [],
|
|
184
|
+
...(options.now ? { now: options.now } : {}),
|
|
185
|
+
...(options.busyTimeoutMs !== undefined ? { busyTimeoutMs: options.busyTimeoutMs } : {}),
|
|
186
|
+
};
|
|
187
|
+
return resolveStore(projectRoot, options)
|
|
188
|
+
.searchMemoriesRankedScored(query, limit, searchOptions)
|
|
189
|
+
.map(hit => normalizeRecallHit(hit, projectId));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function opaqueUsageIdentity(kind, value) {
|
|
193
|
+
return createHash('sha256').update(`${kind}\0${value}`).digest('hex');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function memoryUsageIdentity(key) {
|
|
197
|
+
return opaqueUsageIdentity('forge.memory.key.v1', key);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function ownDataValue(value, field) {
|
|
201
|
+
if (!value || typeof value !== 'object' || isProxy(value)) return undefined;
|
|
202
|
+
let descriptor;
|
|
203
|
+
try { descriptor = Object.getOwnPropertyDescriptor(value, field); } catch { return undefined; }
|
|
204
|
+
return descriptor && Object.hasOwn(descriptor, 'value') ? descriptor.value : undefined;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function usageResolutionOptions(options) {
|
|
208
|
+
const resolutionOptions = {};
|
|
209
|
+
for (const field of ['store', 'gitCommonDir', 'platform', 'realpath', 'databasePath']) {
|
|
210
|
+
const option = ownDataValue(options, field);
|
|
211
|
+
if (option !== undefined) resolutionOptions[field] = option;
|
|
212
|
+
}
|
|
213
|
+
return resolutionOptions;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function usageInvocationId(options) {
|
|
217
|
+
const value = ownDataValue(options, 'invocationId');
|
|
218
|
+
return typeof value === 'string' && value ? value : randomUUID();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function usageObservedAt(options) {
|
|
222
|
+
const invocationStartedAt = ownDataValue(options, 'invocationStartedAt');
|
|
223
|
+
if (typeof invocationStartedAt === 'string') return invocationStartedAt;
|
|
224
|
+
const now = ownDataValue(options, 'now');
|
|
225
|
+
if (typeof now === 'string') return now;
|
|
226
|
+
return new Date().toISOString();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function usageMemoryIdentities(notes) {
|
|
230
|
+
return notes
|
|
231
|
+
.map(note => ownDataValue(note, 'id'))
|
|
232
|
+
.filter(id => typeof id === 'string' && id.length > 0)
|
|
233
|
+
.map(memoryUsageIdentity);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function appendRecallUsage(store, identities, invocationId, scope, selectionDigest, observedAt) {
|
|
237
|
+
let appended = 0;
|
|
238
|
+
let failed = 0;
|
|
239
|
+
for (const memoryId of identities) {
|
|
240
|
+
try {
|
|
241
|
+
const result = store.append({
|
|
242
|
+
event_id: opaqueUsageIdentity('forge.memory.used.event.v1', `${invocationId}\0${memoryId}`),
|
|
243
|
+
memory_id: memoryId,
|
|
244
|
+
scope,
|
|
245
|
+
use_kind: 'cli-recall',
|
|
246
|
+
consumer_id: 'cli-recall',
|
|
247
|
+
selection_digest: selectionDigest,
|
|
248
|
+
observed_at: observedAt,
|
|
249
|
+
idempotency_key: opaqueUsageIdentity('forge.memory.used.idempotency.v1', `${invocationId}\0${memoryId}`),
|
|
250
|
+
});
|
|
251
|
+
if (result?.appended) appended += 1;
|
|
252
|
+
} catch {
|
|
253
|
+
// Evidence is advisory: a storage failure must never hide a useful recall.
|
|
254
|
+
failed += 1;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return { attempted: identities.length, appended, failed };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Recall evidence deliberately accepts only the returned note identifiers. It hashes those
|
|
261
|
+
// identifiers immediately, so neither a user path, query, nor note content can reach storage.
|
|
262
|
+
function recordRecallUsage(projectRoot, selected, options = {}) {
|
|
263
|
+
const notes = Array.isArray(selected) ? selected : [];
|
|
264
|
+
if (notes.length === 0) return { attempted: 0, appended: 0, failed: 0 };
|
|
265
|
+
const usageStore = ownDataValue(options, 'usageStore');
|
|
266
|
+
const resolutionOptions = usageResolutionOptions(options);
|
|
267
|
+
const invocationId = usageInvocationId(options);
|
|
268
|
+
const observedAt = usageObservedAt(options);
|
|
269
|
+
const identities = usageMemoryIdentities(notes);
|
|
270
|
+
if (identities.length === 0) return { attempted: 0, appended: 0, failed: 0 };
|
|
271
|
+
let scope;
|
|
272
|
+
let selectionDigest;
|
|
273
|
+
let store;
|
|
274
|
+
try {
|
|
275
|
+
scope = opaqueUsageIdentity('forge.memory.scope.v1', resolveProjectId(projectRoot, resolutionOptions));
|
|
276
|
+
selectionDigest = opaqueUsageIdentity('forge.memory.selection.v1', identities.join('\0'));
|
|
277
|
+
store = createUsageEvidenceStore(usageStore || resolveStore(projectRoot, resolutionOptions));
|
|
278
|
+
} catch {
|
|
279
|
+
return { attempted: identities.length, appended: 0, failed: identities.length };
|
|
280
|
+
}
|
|
281
|
+
return appendRecallUsage(store, identities, invocationId, scope, selectionDigest, observedAt);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function usageProjection(projectRoot, key, options = {}) {
|
|
285
|
+
if (typeof key !== 'string' || !key) return null;
|
|
286
|
+
try {
|
|
287
|
+
const usageStore = ownDataValue(options, 'usageStore');
|
|
288
|
+
return createUsageEvidenceStore(usageStore || resolveStore(projectRoot, options))
|
|
289
|
+
.projection(opaqueUsageIdentity('forge.memory.key.v1', key));
|
|
290
|
+
} catch {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function usageProjectionStatus(projectRoot, keys, options = {}) {
|
|
296
|
+
if (!Array.isArray(keys) || keys.length === 0) return { available: true, projections: new Map() };
|
|
297
|
+
const rawKeys = [...new Set(keys.filter(key => typeof key === 'string' && key))].slice(0, 200);
|
|
298
|
+
if (rawKeys.length === 0) return { available: true, projections: new Map() };
|
|
299
|
+
const usageStore = ownDataValue(options, 'usageStore');
|
|
300
|
+
const identities = rawKeys.map(memoryUsageIdentity);
|
|
301
|
+
try {
|
|
302
|
+
const rows = createUsageEvidenceStore(usageStore || resolveStore(projectRoot, options)).projections(identities);
|
|
303
|
+
const keyByIdentity = new Map(rawKeys.map((key, index) => [identities[index], key]));
|
|
304
|
+
return {
|
|
305
|
+
available: true,
|
|
306
|
+
projections: new Map(rows.map(row => [keyByIdentity.get(row.memory_id), row]).filter(([key]) => key)),
|
|
307
|
+
};
|
|
308
|
+
} catch {
|
|
309
|
+
return { available: false, projections: new Map() };
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function usageProjections(projectRoot, keys, options = {}) {
|
|
314
|
+
return usageProjectionStatus(projectRoot, keys, options).projections;
|
|
148
315
|
}
|
|
149
316
|
|
|
150
317
|
// Close and forget every cached default store. The CLI process is short-lived (the OS
|
|
@@ -170,5 +337,12 @@ module.exports = {
|
|
|
170
337
|
count,
|
|
171
338
|
searchRanked,
|
|
172
339
|
searchRankedScored,
|
|
340
|
+
recordRecallUsage,
|
|
341
|
+
usageProjection,
|
|
342
|
+
usageProjectionStatus,
|
|
343
|
+
usageProjections,
|
|
344
|
+
memoryUsageIdentity,
|
|
345
|
+
resolveStore,
|
|
346
|
+
resolveProjectId,
|
|
173
347
|
closeAll,
|
|
174
348
|
};
|