@a-company/paradigm 3.17.1 → 3.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-ZRPEI35Q.js → chunk-BKMNLROM.js} +533 -5
- package/dist/{chunk-D4VBBKGV.js → chunk-TUW27EIC.js} +137 -37
- package/dist/{chunk-6GWRQWQB.js → chunk-YHRRJM6J.js} +137 -33
- package/dist/{delete-OINCSDQH.js → delete-2PX6DDAY.js} +5 -5
- package/dist/{dist-YHDSIZQD.js → dist-IKBGY7FQ.js} +3 -1
- package/dist/{edit-7FSQNAPE.js → edit-GJYLJYDU.js} +1 -1
- package/dist/index.js +9 -9
- package/dist/{list-Q4R7L7WJ.js → list-RHYZPKG3.js} +3 -3
- package/dist/{lore-server-BLJWN7PY.js → lore-server-XEW7EG62.js} +83 -20
- package/dist/mcp.js +52 -18
- package/dist/{record-YJ3D3462.js → record-PGVYYZFU.js} +7 -7
- package/dist/{reindex-T4N3NG73.js → reindex-UAYAEF7M.js} +1 -1
- package/dist/{review-3OW3KVW7.js → review-BRY5R45L.js} +1 -1
- package/dist/{serve-GCCMOIHR.js → serve-KBMKF4KG.js} +1 -1
- package/dist/{show-CJGHREFS.js → show-6CHTSR33.js} +19 -4
- package/dist/{timeline-ELO5JTQO.js → timeline-HC527YXE.js} +11 -10
- package/lore-ui/dist/assets/{index-BMWob_U9.js → index-CDr7Tr1E.js} +10 -10
- package/lore-ui/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -5,12 +5,12 @@ import * as fs9 from "fs";
|
|
|
5
5
|
import * as path10 from "path";
|
|
6
6
|
import * as yaml8 from "js-yaml";
|
|
7
7
|
|
|
8
|
-
// ../
|
|
8
|
+
// ../premise/core/dist/index.js
|
|
9
9
|
import * as yaml3 from "js-yaml";
|
|
10
10
|
import { z as z2 } from "zod";
|
|
11
11
|
import * as path3 from "path";
|
|
12
12
|
|
|
13
|
-
// ../
|
|
13
|
+
// ../purpose/core/dist/index.js
|
|
14
14
|
import * as fs from "fs";
|
|
15
15
|
import * as yaml from "js-yaml";
|
|
16
16
|
import { z } from "zod";
|
|
@@ -617,7 +617,7 @@ function validatePurposeItem(id, item, itemType, prefix, issues) {
|
|
|
617
617
|
}
|
|
618
618
|
}
|
|
619
619
|
|
|
620
|
-
// ../
|
|
620
|
+
// ../portal/core/dist/index.js
|
|
621
621
|
import * as fs2 from "fs";
|
|
622
622
|
import * as path2 from "path";
|
|
623
623
|
import * as yaml2 from "js-yaml";
|
|
@@ -761,7 +761,7 @@ async function findGateFiles(rootDir) {
|
|
|
761
761
|
return files;
|
|
762
762
|
}
|
|
763
763
|
|
|
764
|
-
// ../
|
|
764
|
+
// ../premise/core/dist/index.js
|
|
765
765
|
var PositionSchema = z2.object({
|
|
766
766
|
x: z2.number(),
|
|
767
767
|
y: z2.number()
|
|
@@ -926,7 +926,9 @@ async function aggregateFromPremise(premiseFile, rootDir) {
|
|
|
926
926
|
data: item,
|
|
927
927
|
description: item.description,
|
|
928
928
|
anchors: item.anchors?.map((a) => parseAnchorString(a)),
|
|
929
|
-
appliesTo: item["applies-to"]
|
|
929
|
+
appliesTo: item["applies-to"],
|
|
930
|
+
tags: item.tags,
|
|
931
|
+
enforcement: item.enforcement
|
|
930
932
|
}));
|
|
931
933
|
}
|
|
932
934
|
const symbolRefs = extractSymbolReferences(parsed);
|
|
@@ -1218,7 +1220,7 @@ function getAllSymbols(index) {
|
|
|
1218
1220
|
return Array.from(index.entries.values());
|
|
1219
1221
|
}
|
|
1220
1222
|
|
|
1221
|
-
// ../
|
|
1223
|
+
// ../probe/core/dist/generator.js
|
|
1222
1224
|
var PARADIGM_VERSION = "0.1.0";
|
|
1223
1225
|
var SCHEMA_VERSION = "1.0.0";
|
|
1224
1226
|
function generateScanIndex(input, options) {
|
|
@@ -3403,9 +3405,72 @@ function inferSeverity(data, entry) {
|
|
|
3403
3405
|
import * as fs6 from "fs";
|
|
3404
3406
|
import * as path7 from "path";
|
|
3405
3407
|
import * as yaml5 from "js-yaml";
|
|
3408
|
+
import { execSync as execSync2 } from "child_process";
|
|
3409
|
+
import * as os2 from "os";
|
|
3406
3410
|
var LORE_DIR = ".paradigm/lore";
|
|
3407
3411
|
var ENTRIES_DIR = "entries";
|
|
3408
3412
|
var TIMELINE_FILE = "timeline.yaml";
|
|
3413
|
+
function inferProvider(model) {
|
|
3414
|
+
const lower = model.toLowerCase();
|
|
3415
|
+
if (lower.includes("claude") || lower.includes("anthropic")) return "anthropic";
|
|
3416
|
+
if (lower.includes("gpt") || lower.includes("openai") || lower.includes("o1") || lower.includes("o3")) return "openai";
|
|
3417
|
+
if (lower.includes("gemini") || lower.includes("google") || lower.includes("palm")) return "google";
|
|
3418
|
+
if (lower.includes("llama") || lower.includes("meta")) return "meta";
|
|
3419
|
+
if (lower.includes("mistral") || lower.includes("mixtral")) return "mistral";
|
|
3420
|
+
if (lower.includes("deepseek")) return "deepseek";
|
|
3421
|
+
if (lower.includes("cohere") || lower.includes("command")) return "cohere";
|
|
3422
|
+
return "unknown";
|
|
3423
|
+
}
|
|
3424
|
+
function normalizeLoreEntry(raw) {
|
|
3425
|
+
const entry = raw;
|
|
3426
|
+
const author = entry.author;
|
|
3427
|
+
if (typeof author === "string") {
|
|
3428
|
+
return raw;
|
|
3429
|
+
}
|
|
3430
|
+
if (author && typeof author === "object" && !Array.isArray(author)) {
|
|
3431
|
+
const old = author;
|
|
3432
|
+
if (old.type === "agent") {
|
|
3433
|
+
entry.author = "unknown";
|
|
3434
|
+
entry.agent = {
|
|
3435
|
+
provider: old.model ? inferProvider(old.model) : inferProvider(old.id),
|
|
3436
|
+
model: old.model || old.id
|
|
3437
|
+
};
|
|
3438
|
+
} else {
|
|
3439
|
+
entry.author = old.id || "unknown";
|
|
3440
|
+
}
|
|
3441
|
+
delete entry.assistedBy;
|
|
3442
|
+
}
|
|
3443
|
+
return entry;
|
|
3444
|
+
}
|
|
3445
|
+
function sanitizeAuthor(name) {
|
|
3446
|
+
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 20) || "unknown";
|
|
3447
|
+
}
|
|
3448
|
+
function resolveAuthor() {
|
|
3449
|
+
const envAuthor = process.env.PARADIGM_AUTHOR;
|
|
3450
|
+
if (envAuthor) return sanitizeAuthor(envAuthor);
|
|
3451
|
+
try {
|
|
3452
|
+
const gitName = execSync2("git config user.name", { encoding: "utf-8", timeout: 3e3 }).trim();
|
|
3453
|
+
if (gitName) return sanitizeAuthor(gitName);
|
|
3454
|
+
} catch {
|
|
3455
|
+
}
|
|
3456
|
+
try {
|
|
3457
|
+
const username = os2.userInfo().username;
|
|
3458
|
+
if (username) return sanitizeAuthor(username);
|
|
3459
|
+
} catch {
|
|
3460
|
+
}
|
|
3461
|
+
return "unknown";
|
|
3462
|
+
}
|
|
3463
|
+
function isLoreFile(filename) {
|
|
3464
|
+
return filename.endsWith(".yaml") || filename.endsWith(".lore");
|
|
3465
|
+
}
|
|
3466
|
+
function resolveEntryPath(rootDir, dateStr, entryId) {
|
|
3467
|
+
const dirPath = path7.join(rootDir, LORE_DIR, ENTRIES_DIR, dateStr);
|
|
3468
|
+
const lorePath = path7.join(dirPath, `${entryId}.lore`);
|
|
3469
|
+
if (fs6.existsSync(lorePath)) return lorePath;
|
|
3470
|
+
const yamlPath = path7.join(dirPath, `${entryId}.yaml`);
|
|
3471
|
+
if (fs6.existsSync(yamlPath)) return yamlPath;
|
|
3472
|
+
return null;
|
|
3473
|
+
}
|
|
3409
3474
|
async function loadLoreEntries(rootDir, filter) {
|
|
3410
3475
|
const entriesPath = path7.join(rootDir, LORE_DIR, ENTRIES_DIR);
|
|
3411
3476
|
if (!fs6.existsSync(entriesPath)) {
|
|
@@ -3418,12 +3483,12 @@ async function loadLoreEntries(rootDir, filter) {
|
|
|
3418
3483
|
if (filter?.dateFrom && dateDir < filter.dateFrom.slice(0, 10)) continue;
|
|
3419
3484
|
if (filter?.dateTo && dateDir > filter.dateTo.slice(0, 10)) continue;
|
|
3420
3485
|
const dirPath = path7.join(entriesPath, dateDir);
|
|
3421
|
-
const files = fs6.readdirSync(dirPath).filter(
|
|
3486
|
+
const files = fs6.readdirSync(dirPath).filter(isLoreFile).sort();
|
|
3422
3487
|
for (const file of files) {
|
|
3423
3488
|
try {
|
|
3424
3489
|
const content = fs6.readFileSync(path7.join(dirPath, file), "utf8");
|
|
3425
|
-
const
|
|
3426
|
-
entries.push(
|
|
3490
|
+
const raw = yaml5.load(content);
|
|
3491
|
+
entries.push(normalizeLoreEntry(raw));
|
|
3427
3492
|
} catch {
|
|
3428
3493
|
}
|
|
3429
3494
|
}
|
|
@@ -3434,11 +3499,12 @@ async function loadLoreEntry(rootDir, entryId) {
|
|
|
3434
3499
|
const dateMatch = entryId.match(/^L-(\d{4}-\d{2}-\d{2})-/);
|
|
3435
3500
|
if (dateMatch) {
|
|
3436
3501
|
const dateStr = dateMatch[1];
|
|
3437
|
-
const entryPath =
|
|
3438
|
-
if (
|
|
3502
|
+
const entryPath = resolveEntryPath(rootDir, dateStr, entryId);
|
|
3503
|
+
if (entryPath) {
|
|
3439
3504
|
try {
|
|
3440
3505
|
const content = fs6.readFileSync(entryPath, "utf8");
|
|
3441
|
-
|
|
3506
|
+
const raw = yaml5.load(content);
|
|
3507
|
+
return normalizeLoreEntry(raw);
|
|
3442
3508
|
} catch {
|
|
3443
3509
|
return null;
|
|
3444
3510
|
}
|
|
@@ -3459,6 +3525,16 @@ async function loadLoreTimeline(rootDir) {
|
|
|
3459
3525
|
return null;
|
|
3460
3526
|
}
|
|
3461
3527
|
}
|
|
3528
|
+
function captureGitContext(cwd) {
|
|
3529
|
+
try {
|
|
3530
|
+
const ref = execSync2("git rev-parse HEAD", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
3531
|
+
const branch = execSync2("git rev-parse --abbrev-ref HEAD", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
3532
|
+
const status = execSync2("git status --porcelain", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
3533
|
+
return { ref, branch, dirty: status.length > 0 };
|
|
3534
|
+
} catch {
|
|
3535
|
+
return void 0;
|
|
3536
|
+
}
|
|
3537
|
+
}
|
|
3462
3538
|
async function recordLoreEntry(rootDir, entry) {
|
|
3463
3539
|
const lorePath = path7.join(rootDir, LORE_DIR);
|
|
3464
3540
|
const dateStr = entry.timestamp.slice(0, 10);
|
|
@@ -3466,10 +3542,16 @@ async function recordLoreEntry(rootDir, entry) {
|
|
|
3466
3542
|
if (!fs6.existsSync(datePath)) {
|
|
3467
3543
|
fs6.mkdirSync(datePath, { recursive: true });
|
|
3468
3544
|
}
|
|
3545
|
+
if (!entry.author) {
|
|
3546
|
+
entry.author = resolveAuthor();
|
|
3547
|
+
}
|
|
3548
|
+
if (!entry.git_context) {
|
|
3549
|
+
entry.git_context = captureGitContext(rootDir);
|
|
3550
|
+
}
|
|
3469
3551
|
if (!entry.id) {
|
|
3470
|
-
entry.id = generateLoreId(rootDir, dateStr);
|
|
3552
|
+
entry.id = generateLoreId(rootDir, dateStr, entry.author, entry.timestamp);
|
|
3471
3553
|
}
|
|
3472
|
-
const entryPath = path7.join(datePath, `${entry.id}.
|
|
3554
|
+
const entryPath = path7.join(datePath, `${entry.id}.lore`);
|
|
3473
3555
|
fs6.writeFileSync(entryPath, yaml5.dump(entry, { lineWidth: -1, noRefs: true }));
|
|
3474
3556
|
await rebuildTimeline(rootDir);
|
|
3475
3557
|
return entry.id;
|
|
@@ -3485,12 +3567,13 @@ async function rebuildTimeline(rootDir) {
|
|
|
3485
3567
|
const dateDirs = fs6.readdirSync(entriesPath).filter((d) => /^\d{4}-\d{2}-\d{2}$/.test(d));
|
|
3486
3568
|
for (const dateDir of dateDirs) {
|
|
3487
3569
|
const dirPath = path7.join(entriesPath, dateDir);
|
|
3488
|
-
const files = fs6.readdirSync(dirPath).filter(
|
|
3570
|
+
const files = fs6.readdirSync(dirPath).filter(isLoreFile);
|
|
3489
3571
|
for (const file of files) {
|
|
3490
3572
|
try {
|
|
3491
3573
|
const content = fs6.readFileSync(path7.join(dirPath, file), "utf8");
|
|
3492
|
-
const
|
|
3493
|
-
|
|
3574
|
+
const raw = yaml5.load(content);
|
|
3575
|
+
const entry = normalizeLoreEntry(raw);
|
|
3576
|
+
authors.add(entry.author);
|
|
3494
3577
|
entryCount++;
|
|
3495
3578
|
if (!lastUpdated || entry.timestamp > lastUpdated) {
|
|
3496
3579
|
lastUpdated = entry.timestamp;
|
|
@@ -3526,7 +3609,7 @@ async function rebuildTimeline(rootDir) {
|
|
|
3526
3609
|
function migrateLegacyEntries(rootDir) {
|
|
3527
3610
|
const entriesPath = path7.join(rootDir, LORE_DIR, ENTRIES_DIR);
|
|
3528
3611
|
if (!fs6.existsSync(entriesPath)) return 0;
|
|
3529
|
-
const rootFiles = fs6.readdirSync(entriesPath).filter((f) => f
|
|
3612
|
+
const rootFiles = fs6.readdirSync(entriesPath).filter((f) => isLoreFile(f) && !f.startsWith("."));
|
|
3530
3613
|
let migrated = 0;
|
|
3531
3614
|
for (const file of rootFiles) {
|
|
3532
3615
|
const filePath = path7.join(entriesPath, file);
|
|
@@ -3536,12 +3619,15 @@ function migrateLegacyEntries(rootDir) {
|
|
|
3536
3619
|
const content = fs6.readFileSync(filePath, "utf8");
|
|
3537
3620
|
const raw = yaml5.load(content);
|
|
3538
3621
|
if (raw.author && typeof raw.author === "object") continue;
|
|
3622
|
+
if (typeof raw.author === "string" && raw.timestamp) continue;
|
|
3539
3623
|
const dateStr = typeof raw.date === "string" ? raw.date.slice(0, 10) : (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3540
3624
|
const datePath = path7.join(entriesPath, dateStr);
|
|
3541
3625
|
if (!fs6.existsSync(datePath)) {
|
|
3542
3626
|
fs6.mkdirSync(datePath, { recursive: true });
|
|
3543
3627
|
}
|
|
3544
|
-
const
|
|
3628
|
+
const author = resolveAuthor();
|
|
3629
|
+
const timestamp = `${dateStr}T00:00:00.000Z`;
|
|
3630
|
+
const id = generateLoreId(rootDir, dateStr, author, timestamp);
|
|
3545
3631
|
const oldType = String(raw.type || "agent-session");
|
|
3546
3632
|
const v2Type = ["agent-session", "human-note", "decision", "review", "incident", "milestone"].includes(oldType) ? oldType : "agent-session";
|
|
3547
3633
|
let verification;
|
|
@@ -3555,9 +3641,10 @@ function migrateLegacyEntries(rootDir) {
|
|
|
3555
3641
|
const v2Entry = {
|
|
3556
3642
|
id,
|
|
3557
3643
|
type: v2Type,
|
|
3558
|
-
timestamp
|
|
3559
|
-
author:
|
|
3560
|
-
|
|
3644
|
+
timestamp,
|
|
3645
|
+
author: "unknown",
|
|
3646
|
+
agent: { provider: "unknown", model: "unknown" },
|
|
3647
|
+
title: String(raw.title || file.replace(/\.(yaml|lore)$/, "")),
|
|
3561
3648
|
summary: String(raw.summary || ""),
|
|
3562
3649
|
symbols_touched: Array.isArray(raw.symbols_touched) ? raw.symbols_touched : [],
|
|
3563
3650
|
files_modified: Array.isArray(raw.files_modified) ? raw.files_modified : void 0,
|
|
@@ -3565,7 +3652,7 @@ function migrateLegacyEntries(rootDir) {
|
|
|
3565
3652
|
tags: ["migrated", oldType]
|
|
3566
3653
|
};
|
|
3567
3654
|
fs6.writeFileSync(
|
|
3568
|
-
path7.join(datePath, `${id}.
|
|
3655
|
+
path7.join(datePath, `${id}.lore`),
|
|
3569
3656
|
yaml5.dump(v2Entry, { lineWidth: -1, noRefs: true })
|
|
3570
3657
|
);
|
|
3571
3658
|
fs6.unlinkSync(filePath);
|
|
@@ -3579,8 +3666,8 @@ async function updateLoreEntry(rootDir, entryId, partial) {
|
|
|
3579
3666
|
const entry = await loadLoreEntry(rootDir, entryId);
|
|
3580
3667
|
if (!entry) return false;
|
|
3581
3668
|
const dateStr = entry.timestamp.slice(0, 10);
|
|
3582
|
-
const entryPath =
|
|
3583
|
-
if (!
|
|
3669
|
+
const entryPath = resolveEntryPath(rootDir, dateStr, entryId);
|
|
3670
|
+
if (!entryPath) return false;
|
|
3584
3671
|
if (partial.title !== void 0) entry.title = partial.title;
|
|
3585
3672
|
if (partial.summary !== void 0) entry.summary = partial.summary;
|
|
3586
3673
|
if (partial.type !== void 0) entry.type = partial.type;
|
|
@@ -3605,11 +3692,11 @@ async function deleteLoreEntry(rootDir, entryId) {
|
|
|
3605
3692
|
const entry = await loadLoreEntry(rootDir, entryId);
|
|
3606
3693
|
if (!entry) return false;
|
|
3607
3694
|
const dateStr = entry.timestamp.slice(0, 10);
|
|
3608
|
-
const entryPath =
|
|
3609
|
-
if (!
|
|
3695
|
+
const entryPath = resolveEntryPath(rootDir, dateStr, entryId);
|
|
3696
|
+
if (!entryPath) return false;
|
|
3610
3697
|
fs6.unlinkSync(entryPath);
|
|
3611
3698
|
const dateDir = path7.dirname(entryPath);
|
|
3612
|
-
const remaining = fs6.readdirSync(dateDir).filter(
|
|
3699
|
+
const remaining = fs6.readdirSync(dateDir).filter(isLoreFile);
|
|
3613
3700
|
if (remaining.length === 0) {
|
|
3614
3701
|
fs6.rmdirSync(dateDir);
|
|
3615
3702
|
}
|
|
@@ -3619,10 +3706,16 @@ async function deleteLoreEntry(rootDir, entryId) {
|
|
|
3619
3706
|
function applyFilter(entries, filter) {
|
|
3620
3707
|
let result = entries;
|
|
3621
3708
|
if (filter.author) {
|
|
3622
|
-
result = result.filter((e) => e.author
|
|
3709
|
+
result = result.filter((e) => e.author === filter.author);
|
|
3623
3710
|
}
|
|
3624
|
-
if (filter.
|
|
3625
|
-
result = result.filter(
|
|
3711
|
+
if (filter.hasAgent !== void 0) {
|
|
3712
|
+
result = result.filter(
|
|
3713
|
+
(e) => filter.hasAgent ? e.agent != null : e.agent == null
|
|
3714
|
+
);
|
|
3715
|
+
} else if (filter.authorType) {
|
|
3716
|
+
result = result.filter(
|
|
3717
|
+
(e) => filter.authorType === "agent" ? e.agent != null : e.agent == null
|
|
3718
|
+
);
|
|
3626
3719
|
}
|
|
3627
3720
|
if (filter.symbol) {
|
|
3628
3721
|
result = result.filter(
|
|
@@ -3651,17 +3744,24 @@ function applyFilter(entries, filter) {
|
|
|
3651
3744
|
if (filter.limit) result = result.slice(0, filter.limit);
|
|
3652
3745
|
return result;
|
|
3653
3746
|
}
|
|
3654
|
-
function generateLoreId(rootDir, dateStr) {
|
|
3747
|
+
function generateLoreId(rootDir, dateStr, author, timestamp) {
|
|
3748
|
+
const sanitized = sanitizeAuthor(author);
|
|
3749
|
+
const ts = new Date(timestamp);
|
|
3750
|
+
const hh = String(ts.getUTCHours()).padStart(2, "0");
|
|
3751
|
+
const mm = String(ts.getUTCMinutes()).padStart(2, "0");
|
|
3752
|
+
const ss = String(ts.getUTCSeconds()).padStart(2, "0");
|
|
3753
|
+
const timeStr = `${hh}${mm}${ss}`;
|
|
3754
|
+
const prefix = `L-${dateStr}-${sanitized}-${timeStr}`;
|
|
3655
3755
|
const datePath = path7.join(rootDir, LORE_DIR, ENTRIES_DIR, dateStr);
|
|
3656
3756
|
if (!fs6.existsSync(datePath)) {
|
|
3657
|
-
return
|
|
3757
|
+
return `${prefix}-001`;
|
|
3658
3758
|
}
|
|
3659
|
-
const existing = fs6.readdirSync(datePath).filter((f) => f.startsWith(
|
|
3660
|
-
const match = f.match(
|
|
3759
|
+
const existing = fs6.readdirSync(datePath).filter((f) => f.startsWith(prefix) && isLoreFile(f)).map((f) => {
|
|
3760
|
+
const match = f.match(/-(\d{3})\.(yaml|lore)$/);
|
|
3661
3761
|
return match ? parseInt(match[1], 10) : 0;
|
|
3662
3762
|
});
|
|
3663
3763
|
const next = existing.length > 0 ? Math.max(...existing) + 1 : 1;
|
|
3664
|
-
return
|
|
3764
|
+
return `${prefix}-${String(next).padStart(3, "0")}`;
|
|
3665
3765
|
}
|
|
3666
3766
|
|
|
3667
3767
|
// ../paradigm-mcp/src/utils/aspect-lore-bridge.ts
|
|
@@ -4470,7 +4570,7 @@ function assertStep(step, event) {
|
|
|
4470
4570
|
async function validateAgainstSentinel(persona, options = {}) {
|
|
4471
4571
|
const steps = [];
|
|
4472
4572
|
try {
|
|
4473
|
-
const { SentinelStorage } = await import("./dist-
|
|
4573
|
+
const { SentinelStorage } = await import("./dist-IKBGY7FQ.js");
|
|
4474
4574
|
const storage = new SentinelStorage();
|
|
4475
4575
|
const events = storage.queryEvents?.({
|
|
4476
4576
|
schemaId: "paradigm-personas",
|
|
@@ -3,23 +3,52 @@ import {
|
|
|
3
3
|
__require
|
|
4
4
|
} from "./chunk-ZXMDA7VB.js";
|
|
5
5
|
|
|
6
|
+
// src/core/lore/resolve-author.ts
|
|
7
|
+
import { execSync } from "child_process";
|
|
8
|
+
import * as os from "os";
|
|
9
|
+
function sanitizeAuthor(name) {
|
|
10
|
+
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 20) || "unknown";
|
|
11
|
+
}
|
|
12
|
+
function resolveAuthor() {
|
|
13
|
+
const envAuthor = process.env.PARADIGM_AUTHOR;
|
|
14
|
+
if (envAuthor) return sanitizeAuthor(envAuthor);
|
|
15
|
+
try {
|
|
16
|
+
const gitName = execSync("git config user.name", { encoding: "utf-8", timeout: 3e3 }).trim();
|
|
17
|
+
if (gitName) return sanitizeAuthor(gitName);
|
|
18
|
+
} catch {
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const username = os.userInfo().username;
|
|
22
|
+
if (username) return sanitizeAuthor(username);
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
return "unknown";
|
|
26
|
+
}
|
|
27
|
+
|
|
6
28
|
// src/core/lore/storage.ts
|
|
7
29
|
import * as fs from "fs";
|
|
8
30
|
import * as path from "path";
|
|
9
31
|
import * as yaml from "js-yaml";
|
|
32
|
+
import { execSync as execSync2 } from "child_process";
|
|
10
33
|
|
|
11
34
|
// src/core/lore/filter.ts
|
|
12
35
|
function applyLoreFilter(entries, filter) {
|
|
13
36
|
let result = entries;
|
|
14
37
|
if (filter.author) {
|
|
15
|
-
result = result.filter((e) => e.author
|
|
38
|
+
result = result.filter((e) => e.author === filter.author);
|
|
16
39
|
}
|
|
17
|
-
if (filter.
|
|
18
|
-
result = result.filter(
|
|
40
|
+
if (filter.hasAgent !== void 0) {
|
|
41
|
+
result = result.filter(
|
|
42
|
+
(e) => filter.hasAgent ? e.agent != null : e.agent == null
|
|
43
|
+
);
|
|
44
|
+
} else if (filter.authorType) {
|
|
45
|
+
result = result.filter(
|
|
46
|
+
(e) => filter.authorType === "agent" ? e.agent != null : e.agent == null
|
|
47
|
+
);
|
|
19
48
|
}
|
|
20
49
|
if (filter.symbol) {
|
|
21
50
|
result = result.filter(
|
|
22
|
-
(e) => e.symbols_touched
|
|
51
|
+
(e) => e.symbols_touched?.includes(filter.symbol) || e.symbols_created?.includes(filter.symbol)
|
|
23
52
|
);
|
|
24
53
|
}
|
|
25
54
|
if (filter.dateFrom) {
|
|
@@ -58,10 +87,65 @@ function applyLoreFilter(entries, filter) {
|
|
|
58
87
|
return result;
|
|
59
88
|
}
|
|
60
89
|
|
|
90
|
+
// src/core/lore/normalize.ts
|
|
91
|
+
function inferProvider(model) {
|
|
92
|
+
const lower = model.toLowerCase();
|
|
93
|
+
if (lower.includes("claude") || lower.includes("anthropic")) return "anthropic";
|
|
94
|
+
if (lower.includes("gpt") || lower.includes("openai") || lower.includes("o1") || lower.includes("o3")) return "openai";
|
|
95
|
+
if (lower.includes("gemini") || lower.includes("google") || lower.includes("palm")) return "google";
|
|
96
|
+
if (lower.includes("llama") || lower.includes("meta")) return "meta";
|
|
97
|
+
if (lower.includes("mistral") || lower.includes("mixtral")) return "mistral";
|
|
98
|
+
if (lower.includes("deepseek")) return "deepseek";
|
|
99
|
+
if (lower.includes("cohere") || lower.includes("command")) return "cohere";
|
|
100
|
+
return "unknown";
|
|
101
|
+
}
|
|
102
|
+
function normalizeLoreEntry(raw) {
|
|
103
|
+
const entry = raw;
|
|
104
|
+
const author = entry.author;
|
|
105
|
+
if (typeof author === "string") {
|
|
106
|
+
return raw;
|
|
107
|
+
}
|
|
108
|
+
if (author && typeof author === "object" && !Array.isArray(author)) {
|
|
109
|
+
const old = author;
|
|
110
|
+
if (old.type === "agent") {
|
|
111
|
+
entry.author = "unknown";
|
|
112
|
+
entry.agent = {
|
|
113
|
+
provider: old.model ? inferProvider(old.model) : inferProvider(old.id),
|
|
114
|
+
model: old.model || old.id
|
|
115
|
+
};
|
|
116
|
+
} else {
|
|
117
|
+
entry.author = old.id || "unknown";
|
|
118
|
+
}
|
|
119
|
+
delete entry.assistedBy;
|
|
120
|
+
}
|
|
121
|
+
return entry;
|
|
122
|
+
}
|
|
123
|
+
|
|
61
124
|
// src/core/lore/storage.ts
|
|
62
125
|
var LORE_DIR = ".paradigm/lore";
|
|
63
126
|
var ENTRIES_DIR = "entries";
|
|
64
127
|
var TIMELINE_FILE = "timeline.yaml";
|
|
128
|
+
function isLoreFile(filename) {
|
|
129
|
+
return filename.endsWith(".yaml") || filename.endsWith(".lore");
|
|
130
|
+
}
|
|
131
|
+
function resolveEntryPath(rootDir, dateStr, entryId) {
|
|
132
|
+
const dirPath = path.join(rootDir, LORE_DIR, ENTRIES_DIR, dateStr);
|
|
133
|
+
const lorePath = path.join(dirPath, `${entryId}.lore`);
|
|
134
|
+
if (fs.existsSync(lorePath)) return lorePath;
|
|
135
|
+
const yamlPath = path.join(dirPath, `${entryId}.yaml`);
|
|
136
|
+
if (fs.existsSync(yamlPath)) return yamlPath;
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
function captureGitContext(cwd) {
|
|
140
|
+
try {
|
|
141
|
+
const ref = execSync2("git rev-parse HEAD", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
142
|
+
const branch = execSync2("git rev-parse --abbrev-ref HEAD", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
143
|
+
const status = execSync2("git status --porcelain", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
144
|
+
return { ref, branch, dirty: status.length > 0 };
|
|
145
|
+
} catch {
|
|
146
|
+
return void 0;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
65
149
|
function validateLoreSymbols(rootDir, symbols) {
|
|
66
150
|
const result = { unregistered: [], warnings: [] };
|
|
67
151
|
if (symbols.length === 0) return result;
|
|
@@ -129,10 +213,16 @@ async function recordLore(rootDir, entry, options) {
|
|
|
129
213
|
if (!fs.existsSync(datePath)) {
|
|
130
214
|
fs.mkdirSync(datePath, { recursive: true });
|
|
131
215
|
}
|
|
216
|
+
if (!entry.author) {
|
|
217
|
+
entry.author = resolveAuthor();
|
|
218
|
+
}
|
|
219
|
+
if (!entry.git_context) {
|
|
220
|
+
entry.git_context = captureGitContext(rootDir);
|
|
221
|
+
}
|
|
132
222
|
if (!entry.id) {
|
|
133
|
-
entry.id = generateLoreId(rootDir, dateStr);
|
|
223
|
+
entry.id = generateLoreId(rootDir, dateStr, entry.author, entry.timestamp);
|
|
134
224
|
}
|
|
135
|
-
const entryPath = path.join(datePath, `${entry.id}.
|
|
225
|
+
const entryPath = path.join(datePath, `${entry.id}.lore`);
|
|
136
226
|
fs.writeFileSync(entryPath, yaml.dump(entry, { lineWidth: -1, noRefs: true }));
|
|
137
227
|
await rebuildTimeline(rootDir);
|
|
138
228
|
return { validation };
|
|
@@ -149,12 +239,12 @@ async function loadLoreEntries(rootDir, filter) {
|
|
|
149
239
|
if (filter?.dateFrom && dateDir < filter.dateFrom.slice(0, 10)) continue;
|
|
150
240
|
if (filter?.dateTo && dateDir > filter.dateTo.slice(0, 10)) continue;
|
|
151
241
|
const dirPath = path.join(entriesPath, dateDir);
|
|
152
|
-
const files = fs.readdirSync(dirPath).filter(
|
|
242
|
+
const files = fs.readdirSync(dirPath).filter(isLoreFile).sort();
|
|
153
243
|
for (const file of files) {
|
|
154
244
|
try {
|
|
155
245
|
const content = fs.readFileSync(path.join(dirPath, file), "utf8");
|
|
156
|
-
const
|
|
157
|
-
entries.push(
|
|
246
|
+
const raw = yaml.load(content);
|
|
247
|
+
entries.push(normalizeLoreEntry(raw));
|
|
158
248
|
} catch {
|
|
159
249
|
}
|
|
160
250
|
}
|
|
@@ -174,12 +264,13 @@ async function rebuildTimeline(rootDir) {
|
|
|
174
264
|
const dateDirs = fs.readdirSync(entriesPath).filter((d) => /^\d{4}-\d{2}-\d{2}$/.test(d));
|
|
175
265
|
for (const dateDir of dateDirs) {
|
|
176
266
|
const dirPath = path.join(entriesPath, dateDir);
|
|
177
|
-
const files = fs.readdirSync(dirPath).filter(
|
|
267
|
+
const files = fs.readdirSync(dirPath).filter(isLoreFile);
|
|
178
268
|
for (const file of files) {
|
|
179
269
|
try {
|
|
180
270
|
const content = fs.readFileSync(path.join(dirPath, file), "utf8");
|
|
181
|
-
const
|
|
182
|
-
|
|
271
|
+
const raw = yaml.load(content);
|
|
272
|
+
const entry = normalizeLoreEntry(raw);
|
|
273
|
+
authors.add(entry.author);
|
|
183
274
|
entryCount++;
|
|
184
275
|
if (!lastUpdated || entry.timestamp > lastUpdated) {
|
|
185
276
|
lastUpdated = entry.timestamp;
|
|
@@ -219,8 +310,8 @@ async function addReview(rootDir, entryId, review) {
|
|
|
219
310
|
return false;
|
|
220
311
|
}
|
|
221
312
|
const dateStr = entry.timestamp.slice(0, 10);
|
|
222
|
-
const entryPath =
|
|
223
|
-
if (!
|
|
313
|
+
const entryPath = resolveEntryPath(rootDir, dateStr, entryId);
|
|
314
|
+
if (!entryPath) {
|
|
224
315
|
return false;
|
|
225
316
|
}
|
|
226
317
|
entry.review = review;
|
|
@@ -231,11 +322,12 @@ async function loadLoreEntry(rootDir, entryId) {
|
|
|
231
322
|
const dateMatch = entryId.match(/^L-(\d{4}-\d{2}-\d{2})-/);
|
|
232
323
|
if (dateMatch) {
|
|
233
324
|
const dateStr = dateMatch[1];
|
|
234
|
-
const entryPath =
|
|
235
|
-
if (
|
|
325
|
+
const entryPath = resolveEntryPath(rootDir, dateStr, entryId);
|
|
326
|
+
if (entryPath) {
|
|
236
327
|
try {
|
|
237
328
|
const content = fs.readFileSync(entryPath, "utf8");
|
|
238
|
-
|
|
329
|
+
const raw = yaml.load(content);
|
|
330
|
+
return normalizeLoreEntry(raw);
|
|
239
331
|
} catch {
|
|
240
332
|
return null;
|
|
241
333
|
}
|
|
@@ -248,8 +340,8 @@ async function updateLoreEntry(rootDir, entryId, partial) {
|
|
|
248
340
|
const entry = await loadLoreEntry(rootDir, entryId);
|
|
249
341
|
if (!entry) return false;
|
|
250
342
|
const dateStr = entry.timestamp.slice(0, 10);
|
|
251
|
-
const entryPath =
|
|
252
|
-
if (!
|
|
343
|
+
const entryPath = resolveEntryPath(rootDir, dateStr, entryId);
|
|
344
|
+
if (!entryPath) return false;
|
|
253
345
|
if (partial.title !== void 0) entry.title = partial.title;
|
|
254
346
|
if (partial.summary !== void 0) entry.summary = partial.summary;
|
|
255
347
|
if (partial.type !== void 0) entry.type = partial.type;
|
|
@@ -274,11 +366,11 @@ async function deleteLoreEntry(rootDir, entryId) {
|
|
|
274
366
|
const entry = await loadLoreEntry(rootDir, entryId);
|
|
275
367
|
if (!entry) return false;
|
|
276
368
|
const dateStr = entry.timestamp.slice(0, 10);
|
|
277
|
-
const entryPath =
|
|
278
|
-
if (!
|
|
369
|
+
const entryPath = resolveEntryPath(rootDir, dateStr, entryId);
|
|
370
|
+
if (!entryPath) return false;
|
|
279
371
|
fs.unlinkSync(entryPath);
|
|
280
372
|
const dateDir = path.dirname(entryPath);
|
|
281
|
-
const remaining = fs.readdirSync(dateDir).filter(
|
|
373
|
+
const remaining = fs.readdirSync(dateDir).filter(isLoreFile);
|
|
282
374
|
if (remaining.length === 0) {
|
|
283
375
|
fs.rmdirSync(dateDir);
|
|
284
376
|
}
|
|
@@ -288,7 +380,7 @@ async function deleteLoreEntry(rootDir, entryId) {
|
|
|
288
380
|
function migrateLegacyEntries(rootDir) {
|
|
289
381
|
const entriesPath = path.join(rootDir, LORE_DIR, ENTRIES_DIR);
|
|
290
382
|
if (!fs.existsSync(entriesPath)) return 0;
|
|
291
|
-
const rootFiles = fs.readdirSync(entriesPath).filter((f) => f
|
|
383
|
+
const rootFiles = fs.readdirSync(entriesPath).filter((f) => isLoreFile(f) && !f.startsWith("."));
|
|
292
384
|
let migrated = 0;
|
|
293
385
|
for (const file of rootFiles) {
|
|
294
386
|
const filePath = path.join(entriesPath, file);
|
|
@@ -298,12 +390,15 @@ function migrateLegacyEntries(rootDir) {
|
|
|
298
390
|
const content = fs.readFileSync(filePath, "utf8");
|
|
299
391
|
const raw = yaml.load(content);
|
|
300
392
|
if (raw.author && typeof raw.author === "object") continue;
|
|
393
|
+
if (typeof raw.author === "string" && raw.timestamp) continue;
|
|
301
394
|
const dateStr = typeof raw.date === "string" ? raw.date.slice(0, 10) : (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
302
395
|
const datePath = path.join(entriesPath, dateStr);
|
|
303
396
|
if (!fs.existsSync(datePath)) {
|
|
304
397
|
fs.mkdirSync(datePath, { recursive: true });
|
|
305
398
|
}
|
|
306
|
-
const
|
|
399
|
+
const author = resolveAuthor();
|
|
400
|
+
const timestamp = `${dateStr}T00:00:00.000Z`;
|
|
401
|
+
const id = generateLoreId(rootDir, dateStr, author, timestamp);
|
|
307
402
|
const oldType = String(raw.type || "agent-session");
|
|
308
403
|
const v2Type = ["agent-session", "human-note", "decision", "review", "incident", "milestone"].includes(oldType) ? oldType : "agent-session";
|
|
309
404
|
let verification;
|
|
@@ -317,9 +412,10 @@ function migrateLegacyEntries(rootDir) {
|
|
|
317
412
|
const v2Entry = {
|
|
318
413
|
id,
|
|
319
414
|
type: v2Type,
|
|
320
|
-
timestamp
|
|
321
|
-
author:
|
|
322
|
-
|
|
415
|
+
timestamp,
|
|
416
|
+
author: "unknown",
|
|
417
|
+
agent: { provider: "unknown", model: "unknown" },
|
|
418
|
+
title: String(raw.title || file.replace(/\.(yaml|lore)$/, "")),
|
|
323
419
|
summary: String(raw.summary || ""),
|
|
324
420
|
symbols_touched: Array.isArray(raw.symbols_touched) ? raw.symbols_touched : [],
|
|
325
421
|
files_modified: Array.isArray(raw.files_modified) ? raw.files_modified : void 0,
|
|
@@ -327,7 +423,7 @@ function migrateLegacyEntries(rootDir) {
|
|
|
327
423
|
tags: ["migrated", oldType]
|
|
328
424
|
};
|
|
329
425
|
fs.writeFileSync(
|
|
330
|
-
path.join(datePath, `${id}.
|
|
426
|
+
path.join(datePath, `${id}.lore`),
|
|
331
427
|
yaml.dump(v2Entry, { lineWidth: -1, noRefs: true })
|
|
332
428
|
);
|
|
333
429
|
fs.unlinkSync(filePath);
|
|
@@ -337,20 +433,28 @@ function migrateLegacyEntries(rootDir) {
|
|
|
337
433
|
}
|
|
338
434
|
return migrated;
|
|
339
435
|
}
|
|
340
|
-
function generateLoreId(rootDir, dateStr) {
|
|
436
|
+
function generateLoreId(rootDir, dateStr, author, timestamp) {
|
|
437
|
+
const sanitized = sanitizeAuthor(author);
|
|
438
|
+
const ts = new Date(timestamp);
|
|
439
|
+
const hh = String(ts.getUTCHours()).padStart(2, "0");
|
|
440
|
+
const mm = String(ts.getUTCMinutes()).padStart(2, "0");
|
|
441
|
+
const ss = String(ts.getUTCSeconds()).padStart(2, "0");
|
|
442
|
+
const timeStr = `${hh}${mm}${ss}`;
|
|
443
|
+
const prefix = `L-${dateStr}-${sanitized}-${timeStr}`;
|
|
341
444
|
const datePath = path.join(rootDir, LORE_DIR, ENTRIES_DIR, dateStr);
|
|
342
445
|
if (!fs.existsSync(datePath)) {
|
|
343
|
-
return
|
|
446
|
+
return `${prefix}-001`;
|
|
344
447
|
}
|
|
345
|
-
const existing = fs.readdirSync(datePath).filter((f) => f.startsWith(
|
|
346
|
-
const match = f.match(
|
|
448
|
+
const existing = fs.readdirSync(datePath).filter((f) => f.startsWith(prefix) && isLoreFile(f)).map((f) => {
|
|
449
|
+
const match = f.match(/-(\d{3})\.(yaml|lore)$/);
|
|
347
450
|
return match ? parseInt(match[1], 10) : 0;
|
|
348
451
|
});
|
|
349
452
|
const next = existing.length > 0 ? Math.max(...existing) + 1 : 1;
|
|
350
|
-
return
|
|
453
|
+
return `${prefix}-${String(next).padStart(3, "0")}`;
|
|
351
454
|
}
|
|
352
455
|
|
|
353
456
|
export {
|
|
457
|
+
resolveAuthor,
|
|
354
458
|
recordLore,
|
|
355
459
|
loadLoreEntries,
|
|
356
460
|
addReview,
|