linger-skill 0.2.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/CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/PRIVACY.md +31 -0
- package/README.md +300 -0
- package/README.zh-CN.md +300 -0
- package/SECURITY.md +25 -0
- package/dist/adapter-evidence.d.ts +31 -0
- package/dist/adapter-evidence.js +166 -0
- package/dist/adapter-evidence.js.map +1 -0
- package/dist/adapters.d.ts +20 -0
- package/dist/adapters.js +105 -0
- package/dist/adapters.js.map +1 -0
- package/dist/capture.d.ts +16 -0
- package/dist/capture.js +108 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +217 -0
- package/dist/cli.js.map +1 -0
- package/dist/control.d.ts +9 -0
- package/dist/control.js +38 -0
- package/dist/control.js.map +1 -0
- package/dist/decision-extraction.d.ts +4 -0
- package/dist/decision-extraction.js +63 -0
- package/dist/decision-extraction.js.map +1 -0
- package/dist/decisions.d.ts +60 -0
- package/dist/decisions.js +166 -0
- package/dist/decisions.js.map +1 -0
- package/dist/delete.d.ts +21 -0
- package/dist/delete.js +96 -0
- package/dist/delete.js.map +1 -0
- package/dist/doctor.d.ts +6 -0
- package/dist/doctor.js +208 -0
- package/dist/doctor.js.map +1 -0
- package/dist/enrichment.d.ts +82 -0
- package/dist/enrichment.js +359 -0
- package/dist/enrichment.js.map +1 -0
- package/dist/eval-adversarial.d.ts +2 -0
- package/dist/eval-adversarial.js +20 -0
- package/dist/eval-adversarial.js.map +1 -0
- package/dist/eval-cli.d.ts +2 -0
- package/dist/eval-cli.js +83 -0
- package/dist/eval-cli.js.map +1 -0
- package/dist/eval-generator.d.ts +41 -0
- package/dist/eval-generator.js +36 -0
- package/dist/eval-generator.js.map +1 -0
- package/dist/eval-heldout.d.ts +2 -0
- package/dist/eval-heldout.js +56 -0
- package/dist/eval-heldout.js.map +1 -0
- package/dist/eval-io.d.ts +6 -0
- package/dist/eval-io.js +15 -0
- package/dist/eval-io.js.map +1 -0
- package/dist/eval-runner.d.ts +8 -0
- package/dist/eval-runner.js +56 -0
- package/dist/eval-runner.js.map +1 -0
- package/dist/eval-scorer.d.ts +27 -0
- package/dist/eval-scorer.js +28 -0
- package/dist/eval-scorer.js.map +1 -0
- package/dist/hook-cli.d.ts +2 -0
- package/dist/hook-cli.js +28 -0
- package/dist/hook-cli.js.map +1 -0
- package/dist/hook-command.d.ts +9 -0
- package/dist/hook-command.js +31 -0
- package/dist/hook-command.js.map +1 -0
- package/dist/hook-handler.d.ts +24 -0
- package/dist/hook-handler.js +93 -0
- package/dist/hook-handler.js.map +1 -0
- package/dist/hook-installer.d.ts +4 -0
- package/dist/hook-installer.js +120 -0
- package/dist/hook-installer.js.map +1 -0
- package/dist/hook-ownership.d.ts +8 -0
- package/dist/hook-ownership.js +51 -0
- package/dist/hook-ownership.js.map +1 -0
- package/dist/install-consent.d.ts +4 -0
- package/dist/install-consent.js +20 -0
- package/dist/install-consent.js.map +1 -0
- package/dist/installer.d.ts +33 -0
- package/dist/installer.js +140 -0
- package/dist/installer.js.map +1 -0
- package/dist/io.d.ts +7 -0
- package/dist/io.js +86 -0
- package/dist/io.js.map +1 -0
- package/dist/memory-events.d.ts +31 -0
- package/dist/memory-events.js +109 -0
- package/dist/memory-events.js.map +1 -0
- package/dist/memory-intent.d.ts +1 -0
- package/dist/memory-intent.js +4 -0
- package/dist/memory-intent.js.map +1 -0
- package/dist/paths.d.ts +15 -0
- package/dist/paths.js +24 -0
- package/dist/paths.js.map +1 -0
- package/dist/pending.d.ts +21 -0
- package/dist/pending.js +76 -0
- package/dist/pending.js.map +1 -0
- package/dist/processed-markdown.d.ts +3 -0
- package/dist/processed-markdown.js +29 -0
- package/dist/processed-markdown.js.map +1 -0
- package/dist/processing-policy.d.ts +19 -0
- package/dist/processing-policy.js +79 -0
- package/dist/processing-policy.js.map +1 -0
- package/dist/processing.d.ts +4 -0
- package/dist/processing.js +143 -0
- package/dist/processing.js.map +1 -0
- package/dist/purge.d.ts +7 -0
- package/dist/purge.js +16 -0
- package/dist/purge.js.map +1 -0
- package/dist/recall-sampling.d.ts +53 -0
- package/dist/recall-sampling.js +201 -0
- package/dist/recall-sampling.js.map +1 -0
- package/dist/recall.d.ts +19 -0
- package/dist/recall.js +70 -0
- package/dist/recall.js.map +1 -0
- package/dist/record-paths.d.ts +18 -0
- package/dist/record-paths.js +38 -0
- package/dist/record-paths.js.map +1 -0
- package/dist/repair.d.ts +4 -0
- package/dist/repair.js +83 -0
- package/dist/repair.js.map +1 -0
- package/dist/runtime-identity.d.ts +1 -0
- package/dist/runtime-identity.js +31 -0
- package/dist/runtime-identity.js.map +1 -0
- package/dist/runtime-installer.d.ts +7 -0
- package/dist/runtime-installer.js +43 -0
- package/dist/runtime-installer.js.map +1 -0
- package/dist/schema-validation.d.ts +26 -0
- package/dist/schema-validation.js +222 -0
- package/dist/schema-validation.js.map +1 -0
- package/dist/search.d.ts +16 -0
- package/dist/search.js +192 -0
- package/dist/search.js.map +1 -0
- package/dist/sensitivity.d.ts +6 -0
- package/dist/sensitivity.js +27 -0
- package/dist/sensitivity.js.map +1 -0
- package/dist/tag-registry.d.ts +21 -0
- package/dist/tag-registry.js +70 -0
- package/dist/tag-registry.js.map +1 -0
- package/dist/term-graph.d.ts +18 -0
- package/dist/term-graph.js +63 -0
- package/dist/term-graph.js.map +1 -0
- package/dist/types.d.ts +68 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/vault-candidates.d.ts +1 -0
- package/dist/vault-candidates.js +57 -0
- package/dist/vault-candidates.js.map +1 -0
- package/dist/vault.d.ts +28 -0
- package/dist/vault.js +158 -0
- package/dist/vault.js.map +1 -0
- package/dist/windows-command.d.ts +6 -0
- package/dist/windows-command.js +9 -0
- package/dist/windows-command.js.map +1 -0
- package/package.json +53 -0
- package/scripts/release-readiness.mjs +58 -0
- package/skills/linger/SKILL.md +56 -0
- package/skills/linger/agents/openai.yaml +4 -0
- package/skills/linger/references/protocol.md +84 -0
package/dist/adapters.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { access, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readCodexAdapterEvidence, verifiedCodexLiveSession } from "./adapter-evidence.js";
|
|
4
|
+
import { parseManagedHookCommand } from "./hook-command.js";
|
|
5
|
+
import { runtimeFingerprint } from "./runtime-identity.js";
|
|
6
|
+
import { assertReadableInside } from "./io.js";
|
|
7
|
+
export async function capabilityReport(home) { return [await detectClaudeCode(home), await detectCodex(home)]; }
|
|
8
|
+
export async function detectClaudeCode(home) {
|
|
9
|
+
const root = path.join(home, ".claude");
|
|
10
|
+
const settings = path.join(root, "settings.json");
|
|
11
|
+
const skill = path.join(root, "skills", "linger", "SKILL.md");
|
|
12
|
+
const detected = await exists(root);
|
|
13
|
+
const installed = await exists(skill);
|
|
14
|
+
let hooks = false;
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(await readFile(settings, "utf8"));
|
|
17
|
+
hooks = Boolean(parsed.hooks && Object.keys(parsed.hooks).length);
|
|
18
|
+
}
|
|
19
|
+
catch { /* absent */ }
|
|
20
|
+
const level = hooks && installed ? 2 : installed ? 1 : 0;
|
|
21
|
+
return result("claude-code", detected, installed, level, hooks, [detected ? root : "Claude Code directory not found", hooks ? settings : "No active hooks detected"], ["MVP hook coverage depends on installed Claude Code lifecycle events.", "Background processing remains session-local; no daemon is installed."]);
|
|
22
|
+
}
|
|
23
|
+
export async function detectCodex(home) {
|
|
24
|
+
const root = path.join(home, ".codex");
|
|
25
|
+
const config = path.join(root, "config.toml");
|
|
26
|
+
const hooksFile = path.join(root, "hooks.json");
|
|
27
|
+
const skill = path.join(root, "skills", "linger", "SKILL.md");
|
|
28
|
+
const detected = await exists(root);
|
|
29
|
+
const installed = await exists(skill);
|
|
30
|
+
let hooks = false;
|
|
31
|
+
let lingerHooks = false;
|
|
32
|
+
let runtimeIdentities = [];
|
|
33
|
+
let hookEvidence;
|
|
34
|
+
try {
|
|
35
|
+
hooks = /(^|\n)\s*\[hooks(?:\.|\])/m.test(await readFile(config, "utf8"));
|
|
36
|
+
if (hooks)
|
|
37
|
+
hookEvidence = config;
|
|
38
|
+
}
|
|
39
|
+
catch { /* absent */ }
|
|
40
|
+
if (await exists(hooksFile)) {
|
|
41
|
+
hooks = true;
|
|
42
|
+
hookEvidence = hooksFile;
|
|
43
|
+
try {
|
|
44
|
+
const document = JSON.parse(await readFile(hooksFile, "utf8"));
|
|
45
|
+
runtimeIdentities = await commonCodexRuntimeIdentities(document, home);
|
|
46
|
+
lingerHooks = runtimeIdentities.length > 0;
|
|
47
|
+
}
|
|
48
|
+
catch { /* malformed or unsupported host config */ }
|
|
49
|
+
}
|
|
50
|
+
let liveSession;
|
|
51
|
+
let invalidEvidence = false;
|
|
52
|
+
try {
|
|
53
|
+
const vault = path.join(home, ".linger", "vault");
|
|
54
|
+
liveSession = await verifiedCodexLiveSession(vault, await readCodexAdapterEvidence(vault), runtimeIdentities);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
invalidEvidence = true;
|
|
58
|
+
}
|
|
59
|
+
const live = Boolean(installed && lingerHooks && liveSession);
|
|
60
|
+
const level = live ? 2 : installed ? 1 : 0;
|
|
61
|
+
const evidence = [
|
|
62
|
+
detected ? root : "Codex directory not found",
|
|
63
|
+
hookEvidence ? `${hookEvidence} (configured${live ? "; live lifecycle verified" : "; execution trust unverified"})` : "No hook configuration detected",
|
|
64
|
+
...(liveSession ? [`Observed SessionStart, UserPromptSubmit capture, and Stop capture in Codex session ${liveSession.session_id}`] : [])
|
|
65
|
+
];
|
|
66
|
+
const limitations = [
|
|
67
|
+
...(live ? ["Live lifecycle evidence proves prior execution; changing hooks may require a new Codex session and renewed verification."] : ["Codex hook configuration does not prove execution trust; capability remains L1 until one live session completes the required lifecycle."]),
|
|
68
|
+
...(invalidEvidence ? ["Codex live evidence is invalid and was ignored."] : []),
|
|
69
|
+
"When lifecycle coverage is incomplete, use rule-driven explicit CLI capture."
|
|
70
|
+
];
|
|
71
|
+
return result("codex", detected, installed, level, live, evidence, limitations);
|
|
72
|
+
}
|
|
73
|
+
function result(adapter, detected, installed, level, hooks, evidence, limitations) {
|
|
74
|
+
return { adapter, detected, installed, level, capabilities: { rules: installed, file_access: installed, lifecycle_hooks: hooks, async_processing: false, recovery: hooks }, evidence, limitations };
|
|
75
|
+
}
|
|
76
|
+
async function exists(file) { try {
|
|
77
|
+
await access(file);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return false;
|
|
82
|
+
} }
|
|
83
|
+
async function commonCodexRuntimeIdentities(document, home) {
|
|
84
|
+
const required = ["SessionStart", "UserPromptSubmit", "Stop"];
|
|
85
|
+
const identities = [];
|
|
86
|
+
for (const event of required) {
|
|
87
|
+
const verified = new Set();
|
|
88
|
+
for (const hook of (document.hooks?.[event] ?? []).flatMap(group => group.hooks ?? [])) {
|
|
89
|
+
const parsed = typeof hook.command === "string" ? parseManagedHookCommand(hook.command, home, "codex") : undefined;
|
|
90
|
+
if (!parsed?.runtime_identity)
|
|
91
|
+
continue;
|
|
92
|
+
const packageRoot = path.dirname(path.dirname(parsed.hook));
|
|
93
|
+
try {
|
|
94
|
+
await assertReadableInside(home, parsed.hook);
|
|
95
|
+
if (await runtimeFingerprint(packageRoot, parsed.node) === parsed.runtime_identity)
|
|
96
|
+
verified.add(parsed.runtime_identity);
|
|
97
|
+
}
|
|
98
|
+
catch { /* invalid or changed runtimes remain untrusted */ }
|
|
99
|
+
}
|
|
100
|
+
identities.push(verified);
|
|
101
|
+
}
|
|
102
|
+
const first = identities[0];
|
|
103
|
+
return first ? [...first].filter(identity => identities.every(values => values.has(identity))) : [];
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RawEvent, Role, SavepointStatus } from "./types.js";
|
|
2
|
+
export interface CaptureInput {
|
|
3
|
+
projectId: string;
|
|
4
|
+
sessionId: string;
|
|
5
|
+
turnId: string;
|
|
6
|
+
role: Role;
|
|
7
|
+
content: string;
|
|
8
|
+
sourceAgent: string;
|
|
9
|
+
sourceModel?: string;
|
|
10
|
+
savepointStatus?: SavepointStatus;
|
|
11
|
+
explicit?: boolean;
|
|
12
|
+
sensitivity?: "normal" | "sensitive" | "secret";
|
|
13
|
+
timestamp?: string;
|
|
14
|
+
reuseRecentHookCapture?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function capture(root: string, input: CaptureInput): Promise<RawEvent | undefined>;
|
package/dist/capture.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { assertWritableInside, atomicJson, readJson, withFileLock } from "./io.js";
|
|
4
|
+
import { completePending, stagePending } from "./pending.js";
|
|
5
|
+
import { assertSafeId, vaultPaths } from "./paths.js";
|
|
6
|
+
import { classifySensitivity, redactSecrets } from "./sensitivity.js";
|
|
7
|
+
import { assertRawEvent, assertSequenceState } from "./schema-validation.js";
|
|
8
|
+
import { assertRawRecordPath } from "./record-paths.js";
|
|
9
|
+
import { initVault } from "./vault.js";
|
|
10
|
+
import { findRecentEquivalentHookEvent } from "./hook-ownership.js";
|
|
11
|
+
const ROLES = new Set(["user", "assistant", "system"]);
|
|
12
|
+
const SAVEPOINT_STATUSES = new Set(["pending", "complete", "partial"]);
|
|
13
|
+
const SENSITIVITIES = new Set(["normal", "sensitive", "secret"]);
|
|
14
|
+
export async function capture(root, input) {
|
|
15
|
+
if (!input.content.trim())
|
|
16
|
+
throw new Error("Content must not be empty");
|
|
17
|
+
if (!ROLES.has(input.role))
|
|
18
|
+
throw new Error("Role must be user, assistant, or system");
|
|
19
|
+
if (input.savepointStatus !== undefined && !SAVEPOINT_STATUSES.has(input.savepointStatus))
|
|
20
|
+
throw new Error("Savepoint status must be pending, complete, or partial");
|
|
21
|
+
if (input.sensitivity !== undefined && !SENSITIVITIES.has(input.sensitivity))
|
|
22
|
+
throw new Error("Sensitivity must be normal, sensitive, or secret");
|
|
23
|
+
const project = assertSafeId(input.projectId, "project id");
|
|
24
|
+
const session = assertSafeId(input.sessionId, "session id");
|
|
25
|
+
const turn = assertSafeId(input.turnId, "turn id");
|
|
26
|
+
const config = await initVault(root);
|
|
27
|
+
if (config.paused)
|
|
28
|
+
return undefined;
|
|
29
|
+
const detected = classifySensitivity(input.content);
|
|
30
|
+
const sensitivity = strongerSensitivity(input.sensitivity ?? "normal", detected.level);
|
|
31
|
+
const storedContent = detected.level === "secret" ? redactSecrets(input.content) : input.content;
|
|
32
|
+
if (input.reuseRecentHookCapture) {
|
|
33
|
+
const owned = await findRecentEquivalentHookEvent(root, { projectId: project, role: input.role, content: storedContent });
|
|
34
|
+
if (owned)
|
|
35
|
+
return owned;
|
|
36
|
+
}
|
|
37
|
+
const p = vaultPaths(root);
|
|
38
|
+
const contentHash = createHash("sha256").update(storedContent).digest("hex");
|
|
39
|
+
const dedupe = createHash("sha256").update(`${project}\0${session}\0${turn}\0${input.role}\0${contentHash}`).digest("hex").slice(0, 24);
|
|
40
|
+
const eventId = `evt_${dedupe}`;
|
|
41
|
+
const rawFile = path.join(p.raw, project, session, `${eventId}.json`);
|
|
42
|
+
const expected = { eventId, project, session, turn, role: input.role, contentHash };
|
|
43
|
+
const existing = await readExistingRaw(p, rawFile, expected);
|
|
44
|
+
if (existing)
|
|
45
|
+
return existing;
|
|
46
|
+
return await withFileLock(path.join(p.tmp, `${project}.capture.lock`), async () => {
|
|
47
|
+
const raced = await readExistingRaw(p, rawFile, expected);
|
|
48
|
+
if (raced)
|
|
49
|
+
return raced;
|
|
50
|
+
const sequenceFile = path.join(p.registry, `${project}.sequence.json`);
|
|
51
|
+
await assertWritableInside(p.root, sequenceFile);
|
|
52
|
+
let current = 0;
|
|
53
|
+
try {
|
|
54
|
+
const state = await readJson(sequenceFile);
|
|
55
|
+
assertSequenceState(state);
|
|
56
|
+
current = state.value;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (error.code !== "ENOENT")
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
const timestamp = input.timestamp ?? new Date().toISOString();
|
|
63
|
+
const event = {
|
|
64
|
+
schema_version: 1, event_id: eventId, session_id: session, project_id: project, seq_id: current + 1, turn_id: turn,
|
|
65
|
+
role: input.role, timestamp, source_agent: input.sourceAgent, source_model: input.sourceModel, content: storedContent,
|
|
66
|
+
content_hash: contentHash, savepoint_status: input.savepointStatus ?? "complete", capture_status: "captured",
|
|
67
|
+
sensitivity, raw_ref: path.relative(p.root, rawFile)
|
|
68
|
+
};
|
|
69
|
+
const queueItem = {
|
|
70
|
+
schema_version: 1, task_id: `task_${randomUUID()}`, event_id: eventId, project_id: project,
|
|
71
|
+
priority: input.explicit ? "explicit" : "normal", status: "pending", attempts: 0, created_at: timestamp, updated_at: timestamp
|
|
72
|
+
};
|
|
73
|
+
const queueFile = path.join(p.queue, project, `${queueItem.task_id}.json`);
|
|
74
|
+
const pendingFile = await stagePending(root, {
|
|
75
|
+
schema_version: 1, pending_id: eventId, event, queue_item: queueItem, raw_file: rawFile, queue_file: queueFile,
|
|
76
|
+
sequence_file: sequenceFile, sequence_value: current + 1, created_at: timestamp
|
|
77
|
+
});
|
|
78
|
+
await atomicJson(rawFile, event);
|
|
79
|
+
await atomicJson(sequenceFile, { schema_version: 1, value: current + 1 });
|
|
80
|
+
await atomicJson(queueFile, queueItem);
|
|
81
|
+
await completePending(pendingFile);
|
|
82
|
+
return event;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async function readExistingRaw(p, file, expected) {
|
|
86
|
+
await assertWritableInside(p.root, file);
|
|
87
|
+
let value;
|
|
88
|
+
try {
|
|
89
|
+
value = await readJson(file);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (error.code === "ENOENT")
|
|
93
|
+
return undefined;
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
assertRawEvent(value);
|
|
97
|
+
assertRawRecordPath(p, file, value);
|
|
98
|
+
const computed = createHash("sha256").update(value.content).digest("hex");
|
|
99
|
+
if (value.event_id !== expected.eventId || value.project_id !== expected.project || value.session_id !== expected.session || value.turn_id !== expected.turn || value.role !== expected.role || value.content_hash !== expected.contentHash || computed !== value.content_hash) {
|
|
100
|
+
throw new Error("Existing raw event failed integrity check");
|
|
101
|
+
}
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
function strongerSensitivity(left, right) {
|
|
105
|
+
const levels = ["normal", "sensitive", "secret"];
|
|
106
|
+
return levels[Math.max(levels.indexOf(left), levels.indexOf(right))];
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import { readFile, stat } from "node:fs/promises";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { capture } from "./capture.js";
|
|
7
|
+
import { capabilityReport } from "./adapters.js";
|
|
8
|
+
import { correct, forget, inspect } from "./control.js";
|
|
9
|
+
import { appendDecision, getDecisionTrail, listDecisionViews } from "./decisions.js";
|
|
10
|
+
import { deleteLastRecord, deleteRecord } from "./delete.js";
|
|
11
|
+
import { doctor } from "./doctor.js";
|
|
12
|
+
import { commitEnrichment, enrichmentStatus, prepareEnrichmentBatch } from "./enrichment.js";
|
|
13
|
+
import { confirmPrivacyConsent, parseAdapterSelection } from "./install-consent.js";
|
|
14
|
+
import { install, PRIVACY_NOTICE, uninstall } from "./installer.js";
|
|
15
|
+
import { recoverPending } from "./pending.js";
|
|
16
|
+
import { purge } from "./purge.js";
|
|
17
|
+
import { processQueue } from "./processing.js";
|
|
18
|
+
import { rebuildTagRegistry } from "./tag-registry.js";
|
|
19
|
+
import { addTermRelation } from "./term-graph.js";
|
|
20
|
+
import { quarantineInvalidFiles } from "./repair.js";
|
|
21
|
+
import { recall } from "./recall.js";
|
|
22
|
+
import { recallSamplingReport, recordRecallAttempt, recordRecallFeedback } from "./recall-sampling.js";
|
|
23
|
+
import { search } from "./search.js";
|
|
24
|
+
import { initVault, listProjects, registerProject, setPaused, vaultStats } from "./vault.js";
|
|
25
|
+
import { assertDecisionEvidenceNotHookOwned } from "./hook-ownership.js";
|
|
26
|
+
const args = process.argv.slice(2);
|
|
27
|
+
const vault = option("--vault") ?? process.env.LINGER_VAULT ?? path.join(os.homedir(), ".linger", "vault");
|
|
28
|
+
const command = args.shift();
|
|
29
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
30
|
+
function option(name) {
|
|
31
|
+
const index = args.indexOf(name);
|
|
32
|
+
if (index < 0)
|
|
33
|
+
return undefined;
|
|
34
|
+
const value = args[index + 1];
|
|
35
|
+
if (!value || value.startsWith("--"))
|
|
36
|
+
throw new Error(`${name} requires a value`);
|
|
37
|
+
args.splice(index, 2);
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function required(name) { return option(name) ?? throwError(`${name} is required`); }
|
|
41
|
+
function flag(name) { const index = args.indexOf(name); if (index < 0)
|
|
42
|
+
return false; args.splice(index, 1); return true; }
|
|
43
|
+
function numberOption(name, fallback) { const raw = option(name); const value = raw === undefined ? fallback : Number(raw); if (!Number.isFinite(value))
|
|
44
|
+
throw new Error(`${name} must be a number`); return value; }
|
|
45
|
+
async function main() {
|
|
46
|
+
switch (command) {
|
|
47
|
+
case "install": {
|
|
48
|
+
const home = option("--home") ?? os.homedir();
|
|
49
|
+
const adapters = parseAdapterSelection(option("--adapters"));
|
|
50
|
+
if (!flag("--yes")) {
|
|
51
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
52
|
+
throw new Error(`install requires --yes when stdin/stdout are non-interactive. Review privacy boundary first: ${PRIVACY_NOTICE}`);
|
|
53
|
+
if (!await confirmPrivacyConsent(process.stdin, process.stdout))
|
|
54
|
+
throw new Error("install cancelled: privacy consent was not confirmed");
|
|
55
|
+
}
|
|
56
|
+
output(await install({ home, packageRoot, adapters }));
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case "uninstall": {
|
|
60
|
+
if (!flag("--yes"))
|
|
61
|
+
throw new Error("uninstall requires --yes; vault will be preserved");
|
|
62
|
+
output(await uninstall(option("--home") ?? os.homedir()));
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case "purge":
|
|
66
|
+
output(await purge(option("--home") ?? os.homedir(), { yes: flag("--yes"), phrase: required("--confirm") }));
|
|
67
|
+
break;
|
|
68
|
+
case "capabilities":
|
|
69
|
+
output(await capabilityReport(option("--home") ?? os.homedir()));
|
|
70
|
+
break;
|
|
71
|
+
case "init":
|
|
72
|
+
output(await initVault(vault));
|
|
73
|
+
break;
|
|
74
|
+
case "project-id":
|
|
75
|
+
console.log((await registerProject(vault, option("--cwd") ?? process.cwd())).project_id);
|
|
76
|
+
break;
|
|
77
|
+
case "projects":
|
|
78
|
+
output(await listProjects(vault));
|
|
79
|
+
break;
|
|
80
|
+
case "capture": {
|
|
81
|
+
const explicit = flag("--explicit");
|
|
82
|
+
const event = await capture(vault, {
|
|
83
|
+
projectId: option("--project") ?? (await registerProject(vault, process.cwd())).project_id, sessionId: option("--session") ?? "manual",
|
|
84
|
+
turnId: option("--turn") ?? `turn-${Date.now()}`, role: (option("--role") ?? "user"),
|
|
85
|
+
content: required("--content"), sourceAgent: option("--agent") ?? "manual", savepointStatus: flag("--partial") ? "partial" : "complete",
|
|
86
|
+
explicit, reuseRecentHookCapture: true, sensitivity: flag("--secret") ? "secret" : flag("--sensitive") ? "sensitive" : "normal"
|
|
87
|
+
});
|
|
88
|
+
output(event ?? { skipped: "paused" });
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case "recover":
|
|
92
|
+
output(await recoverPending(vault));
|
|
93
|
+
break;
|
|
94
|
+
case "process":
|
|
95
|
+
output(await processQueue(vault, option("--project")));
|
|
96
|
+
break;
|
|
97
|
+
case "enrich-pull": {
|
|
98
|
+
const projectId = option("--project") ?? (await registerProject(vault, process.cwd())).project_id;
|
|
99
|
+
const batch = await prepareEnrichmentBatch(vault, projectId, { limit: numberOption("--limit", 6), maxCharacters: numberOption("--max-characters", 12000) });
|
|
100
|
+
output(batch ?? { pending: false, project_id: projectId });
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case "enrich-commit":
|
|
104
|
+
output(await commitEnrichment(vault, await readSubmission(required("--input"))));
|
|
105
|
+
break;
|
|
106
|
+
case "enrich-status":
|
|
107
|
+
output(await enrichmentStatus(vault, option("--project") ?? (await registerProject(vault, process.cwd())).project_id));
|
|
108
|
+
break;
|
|
109
|
+
case "tags-rebuild":
|
|
110
|
+
output(await rebuildTagRegistry(vault, required("--project")));
|
|
111
|
+
break;
|
|
112
|
+
case "term-add":
|
|
113
|
+
output(await addTermRelation(vault, { project_id: required("--project"), term_a: required("--term-a"), term_b: required("--term-b"), relation_type: required("--relation"), confidence: numberOption("--confidence", 0.8), context_tags: option("--context")?.split(",").filter(Boolean) ?? [], evidence_refs: required("--evidence").split(",").filter(Boolean) }));
|
|
114
|
+
break;
|
|
115
|
+
case "recall": {
|
|
116
|
+
const projectId = option("--project") ?? (await registerProject(vault, process.cwd())).project_id;
|
|
117
|
+
const sample = flag("--sample");
|
|
118
|
+
const includeRaw = flag("--include-raw");
|
|
119
|
+
const maxCharacters = numberOption("--max-characters", 12000);
|
|
120
|
+
const maxFiles = numberOption("--max-files", 5000);
|
|
121
|
+
const maxRawFragmentCharacters = numberOption("--max-raw-fragment-characters", 500);
|
|
122
|
+
const timeoutMs = numberOption("--timeout-ms", 2000);
|
|
123
|
+
const from = option("--from");
|
|
124
|
+
const to = option("--to");
|
|
125
|
+
const query = option("--query") ?? args.join(" ");
|
|
126
|
+
const result = await recall(vault, { projectId, query, includeRaw, maxCharacters, maxFiles, maxRawFragmentCharacters, timeoutMs, from, to });
|
|
127
|
+
if (!sample) {
|
|
128
|
+
output(result);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
const attempt = await recordRecallAttempt(vault, { projectId, query, result });
|
|
132
|
+
output({ ...result, attempt_id: attempt.attempt_id });
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case "recall-feedback":
|
|
136
|
+
output(await recordRecallFeedback(vault, {
|
|
137
|
+
projectId: required("--project"),
|
|
138
|
+
attemptId: required("--attempt"),
|
|
139
|
+
outcome: required("--outcome"),
|
|
140
|
+
rawLocated: (option("--raw-located") ?? "unknown"),
|
|
141
|
+
decisionTrailUsed: flag("--decision-used"),
|
|
142
|
+
note: option("--note")
|
|
143
|
+
}));
|
|
144
|
+
break;
|
|
145
|
+
case "recall-samples":
|
|
146
|
+
output(await recallSamplingReport(vault, required("--project")));
|
|
147
|
+
break;
|
|
148
|
+
case "search":
|
|
149
|
+
output(await search(vault, { projectId: option("--project") ?? (await registerProject(vault, process.cwd())).project_id, query: option("--query") ?? args.join(" "), includeRaw: flag("--include-raw"), maxFiles: numberOption("--max-files", 5000), maxRawFragmentCharacters: numberOption("--max-raw-fragment-characters", 500), timeoutMs: numberOption("--timeout-ms", 2000), from: option("--from"), to: option("--to") }));
|
|
150
|
+
break;
|
|
151
|
+
case "decision-add": {
|
|
152
|
+
const projectId = required("--project");
|
|
153
|
+
const evidenceRefs = required("--evidence").split(",").filter(Boolean);
|
|
154
|
+
await assertDecisionEvidenceNotHookOwned(vault, projectId, evidenceRefs);
|
|
155
|
+
output(await appendDecision(vault, {
|
|
156
|
+
projectId, topic: required("--topic"), kind: (option("--kind") ?? "decision"),
|
|
157
|
+
status: (option("--status") ?? "current"), statement: required("--statement"), rationale: option("--rationale"),
|
|
158
|
+
source: (option("--source") ?? "agent_inferred"), confidence: numberOption("--confidence", 0.8),
|
|
159
|
+
evidenceRefs, supersedes: option("--supersedes")?.split(",").filter(Boolean)
|
|
160
|
+
}));
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case "decision-get":
|
|
164
|
+
output(await getDecisionTrail(vault, required("--project"), required("--topic")) ?? { found: false });
|
|
165
|
+
break;
|
|
166
|
+
case "decision-list":
|
|
167
|
+
output(await listDecisionViews(vault, required("--project")));
|
|
168
|
+
break;
|
|
169
|
+
case "forget":
|
|
170
|
+
output(await forget(vault, required("--project"), required("--memory")));
|
|
171
|
+
break;
|
|
172
|
+
case "correct":
|
|
173
|
+
output(await correct(vault, required("--project"), required("--memory"), required("--summary"), required("--evidence").split(",").filter(Boolean), option("--reason")));
|
|
174
|
+
break;
|
|
175
|
+
case "delete":
|
|
176
|
+
output(await deleteRecord(vault, { projectId: required("--project"), target: required("--type"), id: required("--id"), confirmed: flag("--yes"), reason: option("--reason") }));
|
|
177
|
+
break;
|
|
178
|
+
case "delete-last":
|
|
179
|
+
output(await deleteLastRecord(vault, { projectId: required("--project"), target: required("--type"), confirmed: flag("--yes"), reason: option("--reason") }));
|
|
180
|
+
break;
|
|
181
|
+
case "inspect":
|
|
182
|
+
output(await inspect(vault, required("--project"), required("--memory")));
|
|
183
|
+
break;
|
|
184
|
+
case "pause":
|
|
185
|
+
output(await setPaused(vault, true));
|
|
186
|
+
break;
|
|
187
|
+
case "resume":
|
|
188
|
+
output(await setPaused(vault, false));
|
|
189
|
+
break;
|
|
190
|
+
case "status":
|
|
191
|
+
output(await vaultStats(vault));
|
|
192
|
+
break;
|
|
193
|
+
case "doctor":
|
|
194
|
+
output(await doctor(vault));
|
|
195
|
+
break;
|
|
196
|
+
case "doctor-repair": {
|
|
197
|
+
if (!flag("--yes"))
|
|
198
|
+
throw new Error("doctor-repair requires --yes");
|
|
199
|
+
output(await quarantineInvalidFiles(vault));
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
default:
|
|
203
|
+
console.log("linger <install|uninstall|purge|capabilities|init|project-id|projects|capture|recover|process|enrich-pull|enrich-commit|enrich-status|tags-rebuild|term-add|recall|recall-feedback|recall-samples|search|decision-add|decision-get|decision-list|forget|correct|delete|delete-last|inspect|pause|resume|status|doctor|doctor-repair> [options]");
|
|
204
|
+
if (command)
|
|
205
|
+
process.exitCode = 2;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function output(value) { console.log(JSON.stringify(value, null, 2)); }
|
|
209
|
+
function throwError(message) { throw new Error(message); }
|
|
210
|
+
async function readSubmission(file) {
|
|
211
|
+
const resolved = path.resolve(file);
|
|
212
|
+
if ((await stat(resolved)).size > 512 * 1024)
|
|
213
|
+
throw new Error("Enrichment submission is too large");
|
|
214
|
+
return JSON.parse(await readFile(resolved, "utf8"));
|
|
215
|
+
}
|
|
216
|
+
main().catch(error => { console.error(`linger: ${error.message}`); process.exitCode = 1; });
|
|
217
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAA+D,MAAM,gBAAgB,CAAC;AAClJ,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAqB,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACpF,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAyB,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,oBAAoB,EAA+C,MAAM,sBAAsB,CAAC;AACpJ,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,kCAAkC,EAAE,MAAM,qBAAqB,CAAC;AAEzE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAC3G,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;AAC7B,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAErF,SAAS,MAAM,CAAC,IAAY;IAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,mBAAmB,CAAC,CAAC;IAClF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC;AACf,CAAC;AACD,SAAS,QAAQ,CAAC,IAAY,IAAY,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,GAAG,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC;AACrG,SAAS,IAAI,CAAC,IAAY,IAAa,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC;IAAE,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;AAC3I,SAAS,YAAY,CAAC,IAAY,EAAE,QAAgB,IAAY,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;IAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,mBAAmB,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC;AAE7O,KAAK,UAAU,IAAI;IACjB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;YAC9C,MAAM,QAAQ,GAAG,qBAAqB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;YAC7D,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;oBAAE,MAAM,IAAI,KAAK,CAAC,gGAAgG,cAAc,EAAE,CAAC,CAAC;gBACrL,IAAI,CAAC,MAAM,qBAAqB,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC;oBAAE,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;YAC3I,CAAC;YACD,MAAM,CAAC,MAAM,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;YAAC,MAAM;QAChE,CAAC;QACD,KAAK,WAAW,CAAC,CAAC,CAAC;YAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;YAAC,MAAM,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAAC,MAAM;QAAC,CAAC;QACjL,KAAK,OAAO;YAAE,MAAM,CAAC,MAAM,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;YAAC,MAAM;QAClI,KAAK,cAAc;YAAE,MAAM,CAAC,MAAM,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAAC,MAAM;QAC7F,KAAK,MAAM;YAAE,MAAM,CAAC,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;YAAC,MAAM;QACnD,KAAK,YAAY;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YAAC,MAAM;QACnH,KAAK,UAAU;YAAE,MAAM,CAAC,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;YAAC,MAAM;QAC1D,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC;YACpC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE;gBACjC,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI,QAAQ;gBACtI,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAoC;gBACvH,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,QAAQ,EAAE,eAAe,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU;gBACvI,QAAQ,EAAE,sBAAsB,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ;aAChI,CAAC,CAAC;YACH,MAAM,CAAC,KAAK,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;YAAC,MAAM;QAChD,CAAC;QACD,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;YAAC,MAAM;QAC3D,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM;QAC9E,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;YAClG,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,YAAY,CAAC,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;YAC5J,MAAM,CAAC,KAAK,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;YAAC,MAAM;QACpE,CAAC;QACD,KAAK,eAAe;YAAE,MAAM,CAAC,MAAM,gBAAgB,CAAC,KAAK,EAAE,MAAM,cAAc,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM;QAC9G,KAAK,eAAe;YAAE,MAAM,CAAC,MAAM,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;YAAC,MAAM;QACpJ,KAAK,cAAc;YAAE,MAAM,CAAC,MAAM,kBAAkB,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM;QAC3F,KAAK,UAAU;YAAE,MAAM,CAAC,MAAM,eAAe,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,EAAE,QAAQ,CAAC,YAAY,CAAqB,EAAE,UAAU,EAAE,YAAY,CAAC,cAAc,EAAE,GAAG,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YAAC,MAAM;QACjZ,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;YAClG,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;YAChC,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC;YACzC,MAAM,aAAa,GAAG,YAAY,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;YAC9D,MAAM,QAAQ,GAAG,YAAY,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YACnD,MAAM,wBAAwB,GAAG,YAAY,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;YACpF,MAAM,SAAS,GAAG,YAAY,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;YACrD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9B,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,wBAAwB,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YAC7I,IAAI,CAAC,MAAM,EAAE,CAAC;gBAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAAC,MAAM;YAAC,CAAC;YACvC,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/E,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;YAAC,MAAM;QAC/D,CAAC;QACD,KAAK,iBAAiB;YAAE,MAAM,CAAC,MAAM,oBAAoB,CAAC,KAAK,EAAE;gBAC/D,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC;gBAChC,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC;gBAChC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAA0B;gBACvD,UAAU,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,SAAS,CAAe;gBAChE,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,CAAC;gBAC1C,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC;aACvB,CAAC,CAAC,CAAC;YAAC,MAAM;QACX,KAAK,gBAAgB;YAAE,MAAM,CAAC,MAAM,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM;QAC/F,KAAK,QAAQ;YAAE,MAAM,CAAC,MAAM,MAAM,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,YAAY,CAAC,aAAa,EAAE,IAAI,CAAC,EAAE,wBAAwB,EAAE,YAAY,CAAC,+BAA+B,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,cAAc,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;YAAC,MAAM;QACvb,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;YACxC,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACvE,MAAM,kCAAkC,CAAC,KAAK,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;YACzE,MAAM,CAAC,MAAM,cAAc,CAAC,KAAK,EAAE;gBACnC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAiB;gBAC7F,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,SAAS,CAAmB,EAAE,SAAS,EAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,aAAa,CAAC;gBACjI,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,gBAAgB,CAAmB,EAAE,UAAU,EAAE,YAAY,CAAC,cAAc,EAAE,GAAG,CAAC;gBACjH,YAAY,EAAE,UAAU,EAAE,MAAM,CAAC,cAAc,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;aAC3E,CAAC,CAAC,CAAC;YAAC,MAAM;QACb,CAAC;QACD,KAAK,cAAc;YAAE,MAAM,CAAC,MAAM,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YAAC,MAAM;QAClI,KAAK,eAAe;YAAE,MAAM,CAAC,MAAM,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM;QAC3F,KAAK,QAAQ;YAAE,MAAM,CAAC,MAAM,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM;QAC/F,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM;QAC/L,KAAK,QAAQ;YAAE,MAAM,CAAC,MAAM,YAAY,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAiB,EAAE,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;YAAC,MAAM;QACtN,KAAK,aAAa;YAAE,MAAM,CAAC,MAAM,gBAAgB,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAiB,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;YAAC,MAAM;QACzM,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM;QACjG,KAAK,OAAO;YAAE,MAAM,CAAC,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;YAAC,MAAM;QAC1D,KAAK,QAAQ;YAAE,MAAM,CAAC,MAAM,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;YAAC,MAAM;QAC5D,KAAK,QAAQ;YAAE,MAAM,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;YAAC,MAAM;QACtD,KAAK,QAAQ;YAAE,MAAM,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAAC,MAAM;QAClD,KAAK,eAAe,CAAC,CAAC,CAAC;YAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAAC,MAAM,CAAC,MAAM,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC;YAAC,MAAM;QAAC,CAAC;QAClJ;YACE,OAAO,CAAC,GAAG,CAAC,gVAAgV,CAAC,CAAC;YAC9V,IAAI,OAAO;gBAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,KAAc,IAAU,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtF,SAAS,UAAU,CAAC,OAAe,IAAW,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzE,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,GAAG,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACpG,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAY,CAAC;AACjE,CAAC;AACD,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,WAAY,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { correctMemory, type MemoryControlEvent } from "./memory-events.js";
|
|
2
|
+
import type { ProcessedMemory } from "./types.js";
|
|
3
|
+
export declare function forget(root: string, projectId: string, memoryId: string, reason?: string): Promise<MemoryControlEvent>;
|
|
4
|
+
export declare function correct(root: string, projectId: string, memoryId: string, summary: string, evidenceRefs: string[], reason?: string): Promise<Awaited<ReturnType<typeof correctMemory>>>;
|
|
5
|
+
export declare function inspect(root: string, projectId: string, memoryId: string): Promise<{
|
|
6
|
+
memory: ProcessedMemory;
|
|
7
|
+
effective_status: string;
|
|
8
|
+
control_events: string[];
|
|
9
|
+
}>;
|
package/dist/control.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { assertWritableInside, readJson } from "./io.js";
|
|
3
|
+
import { appendMemoryControl, correctMemory, effectiveMemoryStates } from "./memory-events.js";
|
|
4
|
+
import { vaultPaths, assertSafeId } from "./paths.js";
|
|
5
|
+
import { rebuildTagRegistry } from "./tag-registry.js";
|
|
6
|
+
import { assertProcessedMemory } from "./schema-validation.js";
|
|
7
|
+
import { assertProcessedRecordPath } from "./record-paths.js";
|
|
8
|
+
export async function forget(root, projectId, memoryId, reason) {
|
|
9
|
+
const project = assertSafeId(projectId, "project id");
|
|
10
|
+
const memory = assertSafeId(memoryId, "memory id");
|
|
11
|
+
const p = vaultPaths(root);
|
|
12
|
+
const file = path.join(p.processed, project, `${memory}.json`);
|
|
13
|
+
await assertWritableInside(p.root, file);
|
|
14
|
+
const record = await readJson(file);
|
|
15
|
+
assertProcessedMemory(record);
|
|
16
|
+
assertProcessedRecordPath(p, file, record);
|
|
17
|
+
const event = await appendMemoryControl(root, { kind: "forget", project_id: project, target_memory_id: memory, reason, evidence_refs: [] });
|
|
18
|
+
await rebuildTagRegistry(root, project);
|
|
19
|
+
return event;
|
|
20
|
+
}
|
|
21
|
+
export async function correct(root, projectId, memoryId, summary, evidenceRefs, reason) {
|
|
22
|
+
const result = await correctMemory(root, projectId, memoryId, { summary, evidenceRefs, reason, source: "user_explicit" });
|
|
23
|
+
await rebuildTagRegistry(root, projectId);
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
export async function inspect(root, projectId, memoryId) {
|
|
27
|
+
const project = assertSafeId(projectId, "project id");
|
|
28
|
+
const memory = assertSafeId(memoryId, "memory id");
|
|
29
|
+
const p = vaultPaths(root);
|
|
30
|
+
const file = path.join(p.processed, project, `${memory}.json`);
|
|
31
|
+
await assertWritableInside(p.root, file);
|
|
32
|
+
const record = await readJson(file);
|
|
33
|
+
assertProcessedMemory(record);
|
|
34
|
+
assertProcessedRecordPath(p, file, record);
|
|
35
|
+
const state = (await effectiveMemoryStates(root, project)).get(memory);
|
|
36
|
+
return { memory: record, effective_status: state?.status ?? record.status, control_events: state?.event_ids ?? [] };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.js","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AppendDecisionInput, DecisionKind } from "./decisions.js";
|
|
2
|
+
import type { RawEvent } from "./types.js";
|
|
3
|
+
export declare function decisionFromEvent(event: RawEvent, explicitMemory?: boolean): AppendDecisionInput;
|
|
4
|
+
export declare function decisionKindFromContent(content: string): DecisionKind | undefined;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export function decisionFromEvent(event, explicitMemory = false) {
|
|
2
|
+
const content = event.content.replace(/\s+/g, " ").trim();
|
|
3
|
+
const kind = decisionKindFromContent(content) ?? "decision";
|
|
4
|
+
const current = /(?:当前|现在|目前|决定|选择|采用|current|currently|decided|choose|chosen|adopt)/i.test(content);
|
|
5
|
+
return {
|
|
6
|
+
projectId: event.project_id,
|
|
7
|
+
topic: topic(content),
|
|
8
|
+
kind,
|
|
9
|
+
status: kind === "rejection" ? "rejected" : ["decision", "current_state", "correction"].includes(kind) && current ? "current" : "proposed",
|
|
10
|
+
statement: content,
|
|
11
|
+
source: event.role === "user" ? "user_explicit" : "agent_inferred",
|
|
12
|
+
confidence: event.role === "user" ? (explicitMemory ? 1 : 0.95) : 0.7,
|
|
13
|
+
evidenceRefs: [event.event_id],
|
|
14
|
+
aliases: aliases(content),
|
|
15
|
+
timestamp: event.timestamp
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function decisionKindFromContent(content) {
|
|
19
|
+
if (/(?:不是这个意思|这条不对|纠正|correct(?:ion)?)/i.test(content))
|
|
20
|
+
return "correction";
|
|
21
|
+
if (/(?:拒绝|不做|暂缓|否决|defer|reject)/i.test(content))
|
|
22
|
+
return "rejection";
|
|
23
|
+
if (/(?:提案|建议|proposal|propose|suggest)/i.test(content))
|
|
24
|
+
return "proposal";
|
|
25
|
+
if (/(?:想法|灵感|idea)/i.test(content))
|
|
26
|
+
return "idea";
|
|
27
|
+
if (/(?:偏好|更喜欢|preference|prefer)/i.test(content))
|
|
28
|
+
return "preference";
|
|
29
|
+
if (/(?:待办|要做|todo|to-do)/i.test(content))
|
|
30
|
+
return "todo";
|
|
31
|
+
if (/(?:决定|选择|采用|decision|decided|choose|chosen|adopt)/i.test(content))
|
|
32
|
+
return "decision";
|
|
33
|
+
if (/(?:当前|现在|目前|current|currently)/i.test(content))
|
|
34
|
+
return "current_state";
|
|
35
|
+
if (/(?:约束|限制|必须|不能|constraint|must|cannot|can't)/i.test(content))
|
|
36
|
+
return "constraint";
|
|
37
|
+
if (/(?:理由|原因|因为|由于|rationale|reason|because)/i.test(content))
|
|
38
|
+
return "rationale";
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
function topic(content) {
|
|
42
|
+
if (/(?:缓存|cache)/i.test(content) && /(?:数据库|sqlite|postgres|database|redis)/i.test(content))
|
|
43
|
+
return "database-cache";
|
|
44
|
+
if (/(?:数据库|sqlite|postgres|database)/i.test(content))
|
|
45
|
+
return "database";
|
|
46
|
+
if (/(?:存储|storage|vault|file-native)/i.test(content))
|
|
47
|
+
return "storage";
|
|
48
|
+
if (/(?:adapter|hook|适配器)/i.test(content))
|
|
49
|
+
return "adapter";
|
|
50
|
+
const latin = content.toLowerCase().match(/[a-z][a-z0-9_-]{2,}/)?.[0];
|
|
51
|
+
return latin ?? content.slice(0, 32);
|
|
52
|
+
}
|
|
53
|
+
function aliases(content) {
|
|
54
|
+
const values = [];
|
|
55
|
+
if (/(?:数据库|database)/i.test(content))
|
|
56
|
+
values.push("数据库", "db");
|
|
57
|
+
if (/postgres/i.test(content))
|
|
58
|
+
values.push("postgres", "postgresql", "pg");
|
|
59
|
+
if (/sqlite/i.test(content))
|
|
60
|
+
values.push("sqlite");
|
|
61
|
+
return [...new Set(values)];
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=decision-extraction.js.map
|