codemem 0.37.1 → 0.38.0-alpha.2
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/README.md +1 -0
- package/dist/index.js +315 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { DEDUP_KEY_BACKFILL_JOB, DEFAULT_COORDINATOR_DB_PATH, DedupKeyBackfillRunner, MUTATING_TOOL_NAMES, MemoryStore, ObserverClient, REF_BACKFILL_JOB, RawEventSweeper, RefBackfillRunner, SCOPE_BACKFILL_JOB, SESSION_CONTEXT_BACKFILL_JOB, SUMMARY_DEDUP_BACKFILL_JOB, ScopeBackfillRunner, SessionContextBackfillRunner, SummaryDedupBackfillRunner, SyncRetentionRunner, VERSION, VectorModelMigrationRunner, aiBackfillStructuredContent, applyBootstrapSnapshot, backfillMemoryDedupKeys, backfillNarrativeFromBody, backfillTagsText, backfillVectors, buildAuthHeaders, buildBaseUrl, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, compareMemoryRoleReports, connect, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnrollDeviceAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorUpdateScopeAction, createBetterSqliteCoordinatorApp, deactivateLowSignalMemories, deactivateLowSignalObservations, dedupNearDuplicateMemories, ensureDeviceIdentity, ensureSchemaBootstrapped, exportMemories, extractApplyPatchPaths, fetchAllSnapshotPages, fingerprintPublicKey, flushRawEvents, formatHostPort, getExtractionBenchmarkProfile, getInjectionEvalScenarioPack, getInjectionEvalScenarioPrompts, getMaintenanceJob, getMemoryRoleReport, getRawEventRelinkPlan, getRawEventRelinkReport, getRawEventStatus, getSemanticIndexDiagnostics, getSessionExtractionEval, getSessionExtractionEvalScenario, getWorkspaceCodememConfigPath, hasPendingDedupKeyBackfill, hasPendingRefBackfill, hasPendingScopeBackfill, hasPendingSessionContextBackfill, hasPendingSummaryDedupBackfill, hasUnsyncedSharedMemoryChanges, importMemories, initDatabase, isEmbeddingDisabled, listMaintenanceJobs, listPerPeerScopeSyncState, listRetentionScopeIds, loadObserverConfig, loadPublicKey, loadSqliteVec, mdnsEnabled, planReplicationOpsAgePrune, pruneReplicationOpsUntilCaughtUp, rawEventsGate, readCodememConfigFile, readCodememConfigFileAtPath, readCoordinatorSyncConfig, readImportPayload, replayBatchExtraction, replayBatchExtractionWithTierRouting, requestJson, resolveCodememConfigPath, resolveDbPath, resolveHookProject, resolveProject, retryRawEventFailures, runSyncDaemon, runSyncPass, scanSecretsRetroactive, schema, setPeerProjectFilter, stripJsonComments, stripPrivateObj, stripTrailingCommas, syncPassPreflight, updatePeerAddresses, vacuumDatabase, writeCodememConfigFile } from "@codemem/core";
|
|
2
|
+
import { DEDUP_KEY_BACKFILL_JOB, DEFAULT_COORDINATOR_DB_PATH, DedupKeyBackfillRunner, MUTATING_TOOL_NAMES, MemoryStore, ObserverClient, REF_BACKFILL_JOB, RawEventSweeper, RefBackfillRunner, SCOPE_BACKFILL_JOB, SESSION_CONTEXT_BACKFILL_JOB, SUMMARY_DEDUP_BACKFILL_JOB, ScopeBackfillRunner, SessionContextBackfillRunner, SummaryDedupBackfillRunner, SyncRetentionRunner, VERSION, VectorModelMigrationRunner, aiBackfillStructuredContent, applyBootstrapSnapshot, applyDistillRule, backfillMemoryDedupKeys, backfillNarrativeFromBody, backfillTagsText, backfillVectors, buildAuthHeaders, buildBaseUrl, buildDistillReport, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, compareMemoryRoleReports, connect, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnrollDeviceAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorUpdateScopeAction, createBetterSqliteCoordinatorApp, deactivateLowSignalMemories, deactivateLowSignalObservations, dedupNearDuplicateMemories, draftDistillRule, ensureDeviceIdentity, ensureSchemaBootstrapped, exportMemories, extractApplyPatchPaths, fetchAllSnapshotPages, fingerprintPublicKey, flushRawEvents, formatHostPort, getExtractionBenchmarkProfile, getInjectionEvalScenarioPack, getInjectionEvalScenarioPrompts, getMaintenanceJob, getMemoryArtifactReport, getMemoryRoleReport, getRawEventRelinkPlan, getRawEventRelinkReport, getRawEventStatus, getSemanticIndexDiagnostics, getSessionExtractionEval, getSessionExtractionEvalScenario, getWorkspaceCodememConfigPath, hasPendingDedupKeyBackfill, hasPendingRefBackfill, hasPendingScopeBackfill, hasPendingSessionContextBackfill, hasPendingSummaryDedupBackfill, hasUnsyncedSharedMemoryChanges, importMemories, initDatabase, isEmbeddingDisabled, judgeDistillReport, listMaintenanceJobs, listPerPeerScopeSyncState, listRetentionScopeIds, loadObserverConfig, loadPublicKey, loadSqliteVec, mdnsEnabled, planReplicationOpsAgePrune, projectMatchesFilter, pruneReplicationOpsUntilCaughtUp, rawEventsGate, readCodememConfigFile, readCodememConfigFileAtPath, readCoordinatorSyncConfig, readImportPayload, renderUnifiedDiff, replayBatchExtraction, replayBatchExtractionWithTierRouting, requestJson, resolveCodememConfigPath, resolveDbPath, resolveHookProject, resolveProject, resolveProjectRoot, retryRawEventFailures, runSyncDaemon, runSyncPass, scanSecretsRetroactive, schema, setPeerProjectFilter, stripJsonComments, stripPrivateObj, stripTrailingCommas, syncPassPreflight, updatePeerAddresses, vacuumDatabase, writeCodememConfigFile } from "@codemem/core";
|
|
3
3
|
import { Command, Option } from "commander";
|
|
4
4
|
import omelette from "omelette";
|
|
5
5
|
import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
@@ -3722,6 +3722,272 @@ scanSecretsCmd.action((opts) => {
|
|
|
3722
3722
|
});
|
|
3723
3723
|
dbCommand.addCommand(scanSecretsCmd);
|
|
3724
3724
|
//#endregion
|
|
3725
|
+
//#region src/commands/distill.ts
|
|
3726
|
+
var DistillUsageError = class extends Error {};
|
|
3727
|
+
function collectKind(value, previous) {
|
|
3728
|
+
return [...previous, ...value.split(",")].map((kind) => kind.trim()).filter(Boolean);
|
|
3729
|
+
}
|
|
3730
|
+
function parsePositiveInteger(value, name) {
|
|
3731
|
+
const parsed = Number.parseInt(value, 10);
|
|
3732
|
+
if (!Number.isFinite(parsed) || parsed < 1 || String(parsed) !== value.trim()) throw new DistillUsageError(`${name} must be a positive integer`);
|
|
3733
|
+
return parsed;
|
|
3734
|
+
}
|
|
3735
|
+
function readContextFile(path, displayPath, scope) {
|
|
3736
|
+
if (!existsSync(path)) return null;
|
|
3737
|
+
const text = readFileSync(path, "utf8");
|
|
3738
|
+
return text.trim() ? {
|
|
3739
|
+
path: displayPath,
|
|
3740
|
+
text,
|
|
3741
|
+
scope
|
|
3742
|
+
} : null;
|
|
3743
|
+
}
|
|
3744
|
+
function loadDefaultContextDocuments(includeProjectContext, cwd = process.cwd()) {
|
|
3745
|
+
const projectRoot = resolveProjectRoot(cwd) ?? cwd;
|
|
3746
|
+
return [includeProjectContext ? readContextFile(join(projectRoot, "AGENTS.md"), "AGENTS.md", "project") : null, readContextFile(join(homedir(), ".config", "opencode", "AGENTS.md"), "~/.config/opencode/AGENTS.md", "user")].filter((document) => document != null);
|
|
3747
|
+
}
|
|
3748
|
+
function shouldIncludeProjectContext(opts) {
|
|
3749
|
+
if (opts.allProjects) return false;
|
|
3750
|
+
const currentProject = resolveProject(process.cwd());
|
|
3751
|
+
if (!currentProject) return false;
|
|
3752
|
+
const targetProject = opts.project ? resolveProject(process.cwd(), opts.project) : process.env.CODEMEM_PROJECT?.trim() || currentProject;
|
|
3753
|
+
if (!targetProject) return false;
|
|
3754
|
+
return projectMatchesFilter(targetProject, currentProject);
|
|
3755
|
+
}
|
|
3756
|
+
function buildFilters(opts) {
|
|
3757
|
+
if (opts.allProjects && opts.project) throw new DistillUsageError("--project cannot be combined with --all-projects");
|
|
3758
|
+
if (opts.allProjects) return void 0;
|
|
3759
|
+
const defaultProject = process.env.CODEMEM_PROJECT?.trim() || null;
|
|
3760
|
+
const project = opts.project ? resolveProject(process.cwd(), opts.project) : defaultProject ?? resolveProject(process.cwd());
|
|
3761
|
+
return project ? { project } : void 0;
|
|
3762
|
+
}
|
|
3763
|
+
var JUDGE_OVERFETCH_FACTOR = 3;
|
|
3764
|
+
var JUDGE_OVERFETCH_MAX_EXTRA = 20;
|
|
3765
|
+
function judgeFetchLimit(limit) {
|
|
3766
|
+
return Math.min(limit * JUDGE_OVERFETCH_FACTOR, limit + JUDGE_OVERFETCH_MAX_EXTRA);
|
|
3767
|
+
}
|
|
3768
|
+
async function runDistill(store, opts, limit) {
|
|
3769
|
+
const minRecurrence = parsePositiveInteger(opts.minRecurrence, "min recurrence");
|
|
3770
|
+
return buildDistillReport(store, {
|
|
3771
|
+
candidate: {
|
|
3772
|
+
includeDocumented: opts.includeDocumented ?? false,
|
|
3773
|
+
maxEvidenceItems: opts.explain ? 10 : 5
|
|
3774
|
+
},
|
|
3775
|
+
contextDocuments: loadDefaultContextDocuments(shouldIncludeProjectContext(opts)),
|
|
3776
|
+
corpus: {
|
|
3777
|
+
filters: buildFilters(opts) ?? null,
|
|
3778
|
+
kinds: opts.kind.length > 0 ? opts.kind : void 0
|
|
3779
|
+
},
|
|
3780
|
+
limit,
|
|
3781
|
+
minRecurrence
|
|
3782
|
+
});
|
|
3783
|
+
}
|
|
3784
|
+
/**
|
|
3785
|
+
* B-side worthiness gate: an LLM judges each deterministic candidate and
|
|
3786
|
+
* routine-activity clusters are dropped. Recurrence alone cannot make this
|
|
3787
|
+
* call — releases, review passes, and context lookups recur by definition.
|
|
3788
|
+
*/
|
|
3789
|
+
async function judgeReport(report) {
|
|
3790
|
+
const client = new ObserverClient();
|
|
3791
|
+
return judgeDistillReport(report, async (system, user) => {
|
|
3792
|
+
return (await client.observe(system, user)).raw;
|
|
3793
|
+
});
|
|
3794
|
+
}
|
|
3795
|
+
function renderDistillReport(report, explain = false) {
|
|
3796
|
+
if (report.candidates.length === 0) return "No distill candidates found.";
|
|
3797
|
+
const lines = [`Distill candidates (${report.candidates.length})`, ""];
|
|
3798
|
+
for (const [index, candidate] of report.candidates.entries()) {
|
|
3799
|
+
lines.push(`${index + 1}. [${candidate.scope}] score=${candidate.score.toFixed(3)} recurrence=${candidate.recurrence} target=${candidate.suggested_target}`);
|
|
3800
|
+
lines.push(` projects: ${candidate.projects.join(", ") || "(none)"}`);
|
|
3801
|
+
lines.push(` concepts: ${candidate.concepts.join(", ") || "(none)"}`);
|
|
3802
|
+
lines.push(` members: ${candidate.member_ids.join(", ")}`);
|
|
3803
|
+
const judge = candidate.judge;
|
|
3804
|
+
if (judge) lines.push(` judge: ${judge.verdict}${judge.reason ? ` — ${judge.reason}` : ""}`);
|
|
3805
|
+
if (explain) for (const evidence of candidate.evidence) lines.push(` - ${evidence}`);
|
|
3806
|
+
lines.push("");
|
|
3807
|
+
}
|
|
3808
|
+
return lines.join("\n").trimEnd();
|
|
3809
|
+
}
|
|
3810
|
+
function resolveCandidateTarget(candidate) {
|
|
3811
|
+
if (candidate.scope === "user") return {
|
|
3812
|
+
path: join(homedir(), ".config", "opencode", "AGENTS.md"),
|
|
3813
|
+
display: "~/.config/opencode/AGENTS.md"
|
|
3814
|
+
};
|
|
3815
|
+
return {
|
|
3816
|
+
path: join(resolveProjectRoot(process.cwd()) ?? process.cwd(), "AGENTS.md"),
|
|
3817
|
+
display: "AGENTS.md"
|
|
3818
|
+
};
|
|
3819
|
+
}
|
|
3820
|
+
async function draftTopCandidate(report, opts) {
|
|
3821
|
+
const candidate = report.candidates[0];
|
|
3822
|
+
if (!candidate) {
|
|
3823
|
+
if (opts.json) console.log(JSON.stringify({
|
|
3824
|
+
draft: null,
|
|
3825
|
+
reason: "no_candidates"
|
|
3826
|
+
}, null, 2));
|
|
3827
|
+
else {
|
|
3828
|
+
p.intro("codemem distill");
|
|
3829
|
+
p.log.warn("No distill candidates to draft.");
|
|
3830
|
+
p.outro("done");
|
|
3831
|
+
}
|
|
3832
|
+
return;
|
|
3833
|
+
}
|
|
3834
|
+
if (candidate.scope === "project") {
|
|
3835
|
+
const currentProject = resolveProject(process.cwd());
|
|
3836
|
+
if (!(currentProject != null && candidate.projects.every((project) => projectMatchesFilter(project, currentProject)))) {
|
|
3837
|
+
const projects = candidate.projects.join(", ") || "(unknown)";
|
|
3838
|
+
if (opts.json) console.log(JSON.stringify({
|
|
3839
|
+
draft: null,
|
|
3840
|
+
reason: "project_mismatch",
|
|
3841
|
+
representative_id: candidate.representative_id,
|
|
3842
|
+
projects: candidate.projects
|
|
3843
|
+
}, null, 2));
|
|
3844
|
+
else {
|
|
3845
|
+
p.intro("codemem distill draft");
|
|
3846
|
+
p.log.warn(`The top candidate belongs to project "${projects}", not this checkout. Run distill from that repo to draft its AGENTS.md rule.`);
|
|
3847
|
+
p.outro("nothing written");
|
|
3848
|
+
}
|
|
3849
|
+
return;
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
const target = resolveCandidateTarget(candidate);
|
|
3853
|
+
const current = existsSync(target.path) ? readFileSync(target.path, "utf8") : "";
|
|
3854
|
+
let rule;
|
|
3855
|
+
let raw;
|
|
3856
|
+
try {
|
|
3857
|
+
const client = new ObserverClient();
|
|
3858
|
+
const drafted = await draftDistillRule(candidate, async (system, user) => {
|
|
3859
|
+
return (await client.observe(system, user)).raw;
|
|
3860
|
+
});
|
|
3861
|
+
rule = drafted.rule;
|
|
3862
|
+
raw = drafted.raw;
|
|
3863
|
+
} catch (error) {
|
|
3864
|
+
const guidance = `drafting needs a configured observer model: ${error instanceof Error ? error.message : String(error)}`;
|
|
3865
|
+
if (opts.json) emitJsonError("draft_failed", guidance, 1);
|
|
3866
|
+
else {
|
|
3867
|
+
p.log.error(guidance);
|
|
3868
|
+
process.exitCode = 1;
|
|
3869
|
+
}
|
|
3870
|
+
return;
|
|
3871
|
+
}
|
|
3872
|
+
if (!rule) {
|
|
3873
|
+
if (opts.json) console.log(JSON.stringify({
|
|
3874
|
+
draft: null,
|
|
3875
|
+
reason: "model_declined",
|
|
3876
|
+
representative_id: candidate.representative_id,
|
|
3877
|
+
raw
|
|
3878
|
+
}, null, 2));
|
|
3879
|
+
else {
|
|
3880
|
+
p.intro("codemem distill draft");
|
|
3881
|
+
p.log.warn("The model declined to draft a rule for the top candidate (too vague).");
|
|
3882
|
+
p.outro("done");
|
|
3883
|
+
}
|
|
3884
|
+
return;
|
|
3885
|
+
}
|
|
3886
|
+
const applied = applyDistillRule(current, rule);
|
|
3887
|
+
const diff = renderUnifiedDiff(target.display, current, applied.text);
|
|
3888
|
+
if (opts.json) {
|
|
3889
|
+
const wrote = Boolean(opts.apply && applied.changed);
|
|
3890
|
+
if (wrote) {
|
|
3891
|
+
mkdirSync(dirname(target.path), { recursive: true });
|
|
3892
|
+
writeFileSync(target.path, applied.text);
|
|
3893
|
+
}
|
|
3894
|
+
console.log(JSON.stringify({ draft: {
|
|
3895
|
+
target: target.display,
|
|
3896
|
+
scope: candidate.scope,
|
|
3897
|
+
representative_id: candidate.representative_id,
|
|
3898
|
+
recurrence: candidate.recurrence,
|
|
3899
|
+
score: candidate.score,
|
|
3900
|
+
rule,
|
|
3901
|
+
diff,
|
|
3902
|
+
already_present: !applied.changed,
|
|
3903
|
+
applied: wrote
|
|
3904
|
+
} }, null, 2));
|
|
3905
|
+
return;
|
|
3906
|
+
}
|
|
3907
|
+
p.intro("codemem distill draft");
|
|
3908
|
+
p.log.info(`Top candidate [${candidate.scope}] recurrence=${candidate.recurrence} → ${target.display}`);
|
|
3909
|
+
p.log.step(`Proposed rule:\n ${rule}`);
|
|
3910
|
+
if (!applied.changed) {
|
|
3911
|
+
p.log.warn("This rule is already present in the target file.");
|
|
3912
|
+
p.outro("nothing to apply");
|
|
3913
|
+
return;
|
|
3914
|
+
}
|
|
3915
|
+
console.log(diff);
|
|
3916
|
+
if (!opts.apply) {
|
|
3917
|
+
p.outro(`dry run — re-run with --apply to write ${target.display}`);
|
|
3918
|
+
return;
|
|
3919
|
+
}
|
|
3920
|
+
const confirmed = await p.confirm({ message: `Apply this change to ${target.display}?` });
|
|
3921
|
+
if (p.isCancel(confirmed) || !confirmed) {
|
|
3922
|
+
p.outro("aborted — nothing written");
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
mkdirSync(dirname(target.path), { recursive: true });
|
|
3926
|
+
writeFileSync(target.path, applied.text);
|
|
3927
|
+
p.outro(`wrote ${target.display}`);
|
|
3928
|
+
}
|
|
3929
|
+
async function distillAction(opts) {
|
|
3930
|
+
let store = null;
|
|
3931
|
+
try {
|
|
3932
|
+
store = new MemoryStore(resolveDbPath(resolveDbOpt(opts)));
|
|
3933
|
+
const limit = parsePositiveInteger(opts.limit, "limit");
|
|
3934
|
+
const judging = opts.judge !== false;
|
|
3935
|
+
let result = await runDistill(store, opts, judging ? judgeFetchLimit(limit) : limit);
|
|
3936
|
+
if (judging) {
|
|
3937
|
+
try {
|
|
3938
|
+
result = await judgeReport(result);
|
|
3939
|
+
} catch (error) {
|
|
3940
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3941
|
+
result = {
|
|
3942
|
+
...result,
|
|
3943
|
+
metadata: {
|
|
3944
|
+
...result.metadata,
|
|
3945
|
+
judged: false,
|
|
3946
|
+
judge_error: message
|
|
3947
|
+
}
|
|
3948
|
+
};
|
|
3949
|
+
}
|
|
3950
|
+
if (result.candidates.length > limit) result = {
|
|
3951
|
+
...result,
|
|
3952
|
+
candidates: result.candidates.slice(0, limit),
|
|
3953
|
+
metadata: {
|
|
3954
|
+
...result.metadata,
|
|
3955
|
+
candidate_count: limit
|
|
3956
|
+
}
|
|
3957
|
+
};
|
|
3958
|
+
}
|
|
3959
|
+
if (opts.draft || opts.apply) {
|
|
3960
|
+
await draftTopCandidate(result, opts);
|
|
3961
|
+
return;
|
|
3962
|
+
}
|
|
3963
|
+
if (opts.json) {
|
|
3964
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3965
|
+
return;
|
|
3966
|
+
}
|
|
3967
|
+
p.intro("codemem distill");
|
|
3968
|
+
console.log(renderDistillReport(result, opts.explain ?? false));
|
|
3969
|
+
if (result.metadata.judged) p.log.info(`judge dropped ${result.metadata.routine_filtered_count ?? 0} routine-activity candidate(s)`);
|
|
3970
|
+
else if (result.metadata.judge_error) p.log.warn(`worthiness judgment skipped (needs a configured observer model): ${result.metadata.judge_error}. Candidates are unfiltered; recurring routine activity may rank high.`);
|
|
3971
|
+
p.outro("review candidates before editing context files");
|
|
3972
|
+
} catch (error) {
|
|
3973
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3974
|
+
const usageError = error instanceof DistillUsageError;
|
|
3975
|
+
if (opts.json) {
|
|
3976
|
+
emitJsonError(usageError ? "usage_error" : "distill_failed", message, usageError ? 2 : 1);
|
|
3977
|
+
return;
|
|
3978
|
+
}
|
|
3979
|
+
p.log.error(message);
|
|
3980
|
+
process.exitCode = usageError ? 2 : 1;
|
|
3981
|
+
} finally {
|
|
3982
|
+
store?.close();
|
|
3983
|
+
}
|
|
3984
|
+
}
|
|
3985
|
+
var cmd$3 = new Command("distill").configureHelp(helpStyle).description("Mine recurring memories into reviewable context candidates").option("-p, --project <project>", "project identifier (defaults to git repo root)").option("-A, --all-projects", "mine memories across all projects").option("-k, --kind <kind>", "memory kind to mine (repeat or comma-separate)", collectKind, []).option("-m, --min-recurrence <n>", "minimum member count per candidate", "2").option("-l, --limit <n>", "max candidates", "10").option("-e, --explain", "include evidence snippets in human output").option("--include-documented", "include candidates already represented in context files").option("--no-judge", "skip the observer-model worthiness judgment that drops routine-activity clusters").option("-D, --draft", "draft an AGENTS.md rule for the top candidate and show the diff").option("--apply", "write the drafted rule to the target file (implies --draft; prompts to confirm; with --json applies immediately without prompting)");
|
|
3986
|
+
addDbOption(cmd$3);
|
|
3987
|
+
addJsonOption(cmd$3);
|
|
3988
|
+
cmd$3.action(distillAction);
|
|
3989
|
+
var distillCommand = cmd$3;
|
|
3990
|
+
//#endregion
|
|
3725
3991
|
//#region src/commands/embed.ts
|
|
3726
3992
|
function parseOptionalPositiveInt(value) {
|
|
3727
3993
|
if (!value) return void 0;
|
|
@@ -4654,6 +4920,51 @@ function createMemoryRoleCompareCommand() {
|
|
|
4654
4920
|
});
|
|
4655
4921
|
return cmd;
|
|
4656
4922
|
}
|
|
4923
|
+
function createMemoryArtifactReportCommand() {
|
|
4924
|
+
const cmd = new Command("artifact-report").configureHelp(helpStyle).description("Analyze legacy memory artifacts in a DB snapshot without mutating rows").option("--project <project>", "project identifier (defaults to git repo root)").option("--all-projects", "analyze across all projects").option("--inactive", "include inactive memories");
|
|
4925
|
+
addDbOption(cmd);
|
|
4926
|
+
addJsonOption(cmd);
|
|
4927
|
+
cmd.action((opts) => {
|
|
4928
|
+
try {
|
|
4929
|
+
const project = opts.allProjects === true ? null : opts.project?.trim() || process.env.CODEMEM_PROJECT?.trim() || resolveProject(process.cwd(), null);
|
|
4930
|
+
const result = getMemoryArtifactReport(resolveDbOpt(opts), {
|
|
4931
|
+
project,
|
|
4932
|
+
allProjects: opts.allProjects === true,
|
|
4933
|
+
includeInactive: opts.inactive === true
|
|
4934
|
+
});
|
|
4935
|
+
if (opts.json) {
|
|
4936
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4937
|
+
return;
|
|
4938
|
+
}
|
|
4939
|
+
p.intro("codemem memory artifact-report");
|
|
4940
|
+
p.log.info([
|
|
4941
|
+
`Memories: ${result.totals.memories}`,
|
|
4942
|
+
`Active: ${result.totals.active}`,
|
|
4943
|
+
`Sessions: ${result.totals.sessions}`
|
|
4944
|
+
].join("\n"));
|
|
4945
|
+
p.log.info("Counts by artifact:");
|
|
4946
|
+
for (const [artifact, count] of Object.entries(result.counts_by_artifact)) p.log.message(` ${artifact.padEnd(16)} ${String(count)}`);
|
|
4947
|
+
p.log.info("Counts by action:");
|
|
4948
|
+
for (const [action, count] of Object.entries(result.counts_by_action)) p.log.message(` ${action.padEnd(14)} ${String(count)}`);
|
|
4949
|
+
const topReasons = Object.entries(result.counts_by_reason).sort(([, a], [, b]) => b - a).slice(0, 10);
|
|
4950
|
+
if (topReasons.length > 0) {
|
|
4951
|
+
p.log.info("Top reasons:");
|
|
4952
|
+
for (const [reason, count] of topReasons) p.log.message(` ${reason.padEnd(36)} ${String(count)}`);
|
|
4953
|
+
}
|
|
4954
|
+
p.log.info(`High-confidence telemetry: ${result.high_confidence_telemetry.total}`);
|
|
4955
|
+
p.outro("done");
|
|
4956
|
+
} catch (error) {
|
|
4957
|
+
const message = error instanceof Error ? error.message : "Artifact report failed";
|
|
4958
|
+
if (opts.json) emitJsonError("artifact_report_failed", message);
|
|
4959
|
+
else {
|
|
4960
|
+
p.log.error(message);
|
|
4961
|
+
process.exitCode = 1;
|
|
4962
|
+
}
|
|
4963
|
+
return;
|
|
4964
|
+
}
|
|
4965
|
+
});
|
|
4966
|
+
return cmd;
|
|
4967
|
+
}
|
|
4657
4968
|
function createMemoryExtractionReportCommand() {
|
|
4658
4969
|
const cmd = new Command("extraction-report").configureHelp(helpStyle).description("Score extracted memories for a session against a built-in extraction eval rubric").option("--session-id <id>", "session ID to evaluate").option("--batch-id <id>", "raw-event flush batch ID to evaluate").requiredOption("--scenario <id>", "built-in extraction eval scenario ID").option("--inactive", "include inactive memories");
|
|
4659
4970
|
addDbOption(cmd);
|
|
@@ -5036,6 +5347,7 @@ memoryCommand.addCommand(createRememberMemoryCommand());
|
|
|
5036
5347
|
memoryCommand.addCommand(createInjectMemoryCommand());
|
|
5037
5348
|
memoryCommand.addCommand(createMemoryRoleReportCommand());
|
|
5038
5349
|
memoryCommand.addCommand(createMemoryRoleCompareCommand());
|
|
5350
|
+
memoryCommand.addCommand(createMemoryArtifactReportCommand());
|
|
5039
5351
|
memoryCommand.addCommand(createMemoryExtractionReportCommand());
|
|
5040
5352
|
memoryCommand.addCommand(createMemoryExtractionReplayCommand());
|
|
5041
5353
|
memoryCommand.addCommand(createMemoryExtractionBenchmarkCommand());
|
|
@@ -7408,6 +7720,7 @@ completion.on("command", ({ reply }) => {
|
|
|
7408
7720
|
"config",
|
|
7409
7721
|
"coordinator",
|
|
7410
7722
|
"db",
|
|
7723
|
+
"distill",
|
|
7411
7724
|
"embed",
|
|
7412
7725
|
"enqueue-raw-event",
|
|
7413
7726
|
"export-memories",
|
|
@@ -7489,6 +7802,7 @@ program.addCommand(claudeHookFileContextCommand);
|
|
|
7489
7802
|
program.addCommand(codexHookInjectCommand);
|
|
7490
7803
|
program.addCommand(codexHookIngestCommand);
|
|
7491
7804
|
program.addCommand(dbCommand);
|
|
7805
|
+
program.addCommand(distillCommand);
|
|
7492
7806
|
program.addCommand(exportMemoriesCommand);
|
|
7493
7807
|
program.addCommand(importMemoriesCommand);
|
|
7494
7808
|
program.addCommand(statsCommand);
|