@a-company/paradigm 3.18.0 → 3.19.1
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-3DYYXGDC.js +403 -0
- package/dist/{chunk-YHRRJM6J.js → chunk-BRILIG7Z.js} +53 -34
- package/dist/{chunk-TUW27EIC.js → chunk-EZ6XW6FB.js} +141 -500
- package/dist/{delete-2PX6DDAY.js → delete-YTASL4SM.js} +1 -1
- package/dist/{edit-GJYLJYDU.js → edit-S7NZD7H7.js} +1 -1
- package/dist/index.js +18 -10
- package/dist/{list-RHYZPKG3.js → list-CAL7KS7B.js} +1 -1
- package/dist/lore-loader-S5BXMH27.js +21 -0
- package/dist/{lore-server-XEW7EG62.js → lore-server-2NYDLGCJ.js} +25 -1
- package/dist/mcp.js +458 -136
- package/dist/migrate-assessments-FPR6C35Z.js +97 -0
- package/dist/{record-PGVYYZFU.js → record-UGN75GTB.js} +5 -2
- package/dist/{reindex-UAYAEF7M.js → reindex-CMZARW5K.js} +2 -1
- package/dist/retag-URLJLMSK.js +62 -0
- package/dist/{review-BRY5R45L.js → review-725ZKA7U.js} +1 -1
- package/dist/{serve-KBMKF4KG.js → serve-GUJ3L3IG.js} +1 -1
- package/dist/{show-6CHTSR33.js → show-GEVVQWWG.js} +37 -3
- package/dist/{timeline-HC527YXE.js → timeline-B6TMGWRU.js} +1 -1
- package/dist/university-content/courses/para-501.json +30 -30
- package/dist/university-content/plsat/v3.0.json +26 -26
- package/dist/university-ui/assets/{index-B9LrQbxw.js → index-CB2i_7JO.js} +14 -14
- package/dist/university-ui/assets/{index-B9LrQbxw.js.map → index-CB2i_7JO.js.map} +1 -1
- package/dist/university-ui/assets/{index-DW2N5NTk.css → index-Dwp5QYqE.css} +1 -1
- package/dist/university-ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/assessment-loader-C5EOUM47.js +0 -23
- package/dist/chunk-DSXS42FY.js +0 -283
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadLoreEntries,
|
|
4
|
+
loadLoreEntry
|
|
5
|
+
} from "./chunk-3DYYXGDC.js";
|
|
2
6
|
|
|
3
7
|
// ../paradigm-mcp/src/tools/reindex.ts
|
|
4
|
-
import * as
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
8
|
+
import * as fs8 from "fs";
|
|
9
|
+
import * as path9 from "path";
|
|
10
|
+
import * as yaml7 from "js-yaml";
|
|
7
11
|
|
|
8
12
|
// ../premise/core/dist/index.js
|
|
9
13
|
import * as yaml3 from "js-yaml";
|
|
@@ -1993,8 +1997,8 @@ var SessionTracker = class {
|
|
|
1993
1997
|
* Extract resource type from URI
|
|
1994
1998
|
*/
|
|
1995
1999
|
extractResourceType(uri) {
|
|
1996
|
-
const
|
|
1997
|
-
const firstPart =
|
|
2000
|
+
const path10 = uri.replace("paradigm://", "");
|
|
2001
|
+
const firstPart = path10.split("/")[0];
|
|
1998
2002
|
return firstPart || "unknown";
|
|
1999
2003
|
}
|
|
2000
2004
|
/**
|
|
@@ -2748,16 +2752,22 @@ async function buildRecoveryPreamble(rootDir) {
|
|
|
2748
2752
|
} catch {
|
|
2749
2753
|
}
|
|
2750
2754
|
try {
|
|
2751
|
-
const {
|
|
2752
|
-
const
|
|
2753
|
-
|
|
2755
|
+
const { loadLoreEntries: loadLoreEntries2 } = await import("./lore-loader-S5BXMH27.js");
|
|
2756
|
+
const arcEntries = await loadLoreEntries2(rootDir, { limit: 10 });
|
|
2757
|
+
const entriesWithArcs = arcEntries.filter((e) => e.tags?.some((t) => t.startsWith("arc:")));
|
|
2758
|
+
if (entriesWithArcs.length > 0) {
|
|
2759
|
+
const arcGroups = /* @__PURE__ */ new Map();
|
|
2760
|
+
for (const e of entriesWithArcs) {
|
|
2761
|
+
const arcTag = e.tags?.find((t) => t.startsWith("arc:")) || "";
|
|
2762
|
+
arcGroups.set(arcTag, (arcGroups.get(arcTag) || 0) + 1);
|
|
2763
|
+
}
|
|
2754
2764
|
const checkpointSymbols = checkpoint?.symbolsTouched || [];
|
|
2755
|
-
const relevantArcs = checkpointSymbols.length > 0 ?
|
|
2756
|
-
if (relevantArcs.length > 0) {
|
|
2765
|
+
const relevantArcs = checkpointSymbols.length > 0 ? entriesWithArcs.filter((e) => e.symbols_touched?.some((s) => checkpointSymbols.includes(s))) : entriesWithArcs.slice(0, 3);
|
|
2766
|
+
if (relevantArcs.length > 0 || arcGroups.size > 0) {
|
|
2757
2767
|
lines.push("");
|
|
2758
|
-
lines.push("Active
|
|
2759
|
-
for (const
|
|
2760
|
-
lines.push(` ${
|
|
2768
|
+
lines.push("Active lore arcs:");
|
|
2769
|
+
for (const [arcTag, count] of arcGroups) {
|
|
2770
|
+
lines.push(` ${arcTag} (${count} entries)`);
|
|
2761
2771
|
}
|
|
2762
2772
|
}
|
|
2763
2773
|
}
|
|
@@ -3401,369 +3411,6 @@ function inferSeverity(data, entry) {
|
|
|
3401
3411
|
return "medium";
|
|
3402
3412
|
}
|
|
3403
3413
|
|
|
3404
|
-
// ../paradigm-mcp/src/utils/lore-loader.ts
|
|
3405
|
-
import * as fs6 from "fs";
|
|
3406
|
-
import * as path7 from "path";
|
|
3407
|
-
import * as yaml5 from "js-yaml";
|
|
3408
|
-
import { execSync as execSync2 } from "child_process";
|
|
3409
|
-
import * as os2 from "os";
|
|
3410
|
-
var LORE_DIR = ".paradigm/lore";
|
|
3411
|
-
var ENTRIES_DIR = "entries";
|
|
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
|
-
}
|
|
3474
|
-
async function loadLoreEntries(rootDir, filter) {
|
|
3475
|
-
const entriesPath = path7.join(rootDir, LORE_DIR, ENTRIES_DIR);
|
|
3476
|
-
if (!fs6.existsSync(entriesPath)) {
|
|
3477
|
-
return [];
|
|
3478
|
-
}
|
|
3479
|
-
migrateLegacyEntries(rootDir);
|
|
3480
|
-
const entries = [];
|
|
3481
|
-
const dateDirs = fs6.readdirSync(entriesPath).filter((d) => /^\d{4}-\d{2}-\d{2}$/.test(d)).sort().reverse();
|
|
3482
|
-
for (const dateDir of dateDirs) {
|
|
3483
|
-
if (filter?.dateFrom && dateDir < filter.dateFrom.slice(0, 10)) continue;
|
|
3484
|
-
if (filter?.dateTo && dateDir > filter.dateTo.slice(0, 10)) continue;
|
|
3485
|
-
const dirPath = path7.join(entriesPath, dateDir);
|
|
3486
|
-
const files = fs6.readdirSync(dirPath).filter(isLoreFile).sort();
|
|
3487
|
-
for (const file of files) {
|
|
3488
|
-
try {
|
|
3489
|
-
const content = fs6.readFileSync(path7.join(dirPath, file), "utf8");
|
|
3490
|
-
const raw = yaml5.load(content);
|
|
3491
|
-
entries.push(normalizeLoreEntry(raw));
|
|
3492
|
-
} catch {
|
|
3493
|
-
}
|
|
3494
|
-
}
|
|
3495
|
-
}
|
|
3496
|
-
return filter ? applyFilter(entries, filter) : entries;
|
|
3497
|
-
}
|
|
3498
|
-
async function loadLoreEntry(rootDir, entryId) {
|
|
3499
|
-
const dateMatch = entryId.match(/^L-(\d{4}-\d{2}-\d{2})-/);
|
|
3500
|
-
if (dateMatch) {
|
|
3501
|
-
const dateStr = dateMatch[1];
|
|
3502
|
-
const entryPath = resolveEntryPath(rootDir, dateStr, entryId);
|
|
3503
|
-
if (entryPath) {
|
|
3504
|
-
try {
|
|
3505
|
-
const content = fs6.readFileSync(entryPath, "utf8");
|
|
3506
|
-
const raw = yaml5.load(content);
|
|
3507
|
-
return normalizeLoreEntry(raw);
|
|
3508
|
-
} catch {
|
|
3509
|
-
return null;
|
|
3510
|
-
}
|
|
3511
|
-
}
|
|
3512
|
-
}
|
|
3513
|
-
const entries = await loadLoreEntries(rootDir);
|
|
3514
|
-
return entries.find((e) => e.id === entryId) || null;
|
|
3515
|
-
}
|
|
3516
|
-
async function loadLoreTimeline(rootDir) {
|
|
3517
|
-
const timelinePath = path7.join(rootDir, LORE_DIR, TIMELINE_FILE);
|
|
3518
|
-
if (!fs6.existsSync(timelinePath)) {
|
|
3519
|
-
return null;
|
|
3520
|
-
}
|
|
3521
|
-
try {
|
|
3522
|
-
const content = fs6.readFileSync(timelinePath, "utf8");
|
|
3523
|
-
return yaml5.load(content);
|
|
3524
|
-
} catch {
|
|
3525
|
-
return null;
|
|
3526
|
-
}
|
|
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
|
-
}
|
|
3538
|
-
async function recordLoreEntry(rootDir, entry) {
|
|
3539
|
-
const lorePath = path7.join(rootDir, LORE_DIR);
|
|
3540
|
-
const dateStr = entry.timestamp.slice(0, 10);
|
|
3541
|
-
const datePath = path7.join(lorePath, ENTRIES_DIR, dateStr);
|
|
3542
|
-
if (!fs6.existsSync(datePath)) {
|
|
3543
|
-
fs6.mkdirSync(datePath, { recursive: true });
|
|
3544
|
-
}
|
|
3545
|
-
if (!entry.author) {
|
|
3546
|
-
entry.author = resolveAuthor();
|
|
3547
|
-
}
|
|
3548
|
-
if (!entry.git_context) {
|
|
3549
|
-
entry.git_context = captureGitContext(rootDir);
|
|
3550
|
-
}
|
|
3551
|
-
if (!entry.id) {
|
|
3552
|
-
entry.id = generateLoreId(rootDir, dateStr, entry.author, entry.timestamp);
|
|
3553
|
-
}
|
|
3554
|
-
const entryPath = path7.join(datePath, `${entry.id}.lore`);
|
|
3555
|
-
fs6.writeFileSync(entryPath, yaml5.dump(entry, { lineWidth: -1, noRefs: true }));
|
|
3556
|
-
await rebuildTimeline(rootDir);
|
|
3557
|
-
return entry.id;
|
|
3558
|
-
}
|
|
3559
|
-
async function rebuildTimeline(rootDir) {
|
|
3560
|
-
const lorePath = path7.join(rootDir, LORE_DIR);
|
|
3561
|
-
const entriesPath = path7.join(lorePath, ENTRIES_DIR);
|
|
3562
|
-
if (!fs6.existsSync(entriesPath)) return;
|
|
3563
|
-
migrateLegacyEntries(rootDir);
|
|
3564
|
-
const authors = /* @__PURE__ */ new Set();
|
|
3565
|
-
let entryCount = 0;
|
|
3566
|
-
let lastUpdated = "";
|
|
3567
|
-
const dateDirs = fs6.readdirSync(entriesPath).filter((d) => /^\d{4}-\d{2}-\d{2}$/.test(d));
|
|
3568
|
-
for (const dateDir of dateDirs) {
|
|
3569
|
-
const dirPath = path7.join(entriesPath, dateDir);
|
|
3570
|
-
const files = fs6.readdirSync(dirPath).filter(isLoreFile);
|
|
3571
|
-
for (const file of files) {
|
|
3572
|
-
try {
|
|
3573
|
-
const content = fs6.readFileSync(path7.join(dirPath, file), "utf8");
|
|
3574
|
-
const raw = yaml5.load(content);
|
|
3575
|
-
const entry = normalizeLoreEntry(raw);
|
|
3576
|
-
authors.add(entry.author);
|
|
3577
|
-
entryCount++;
|
|
3578
|
-
if (!lastUpdated || entry.timestamp > lastUpdated) {
|
|
3579
|
-
lastUpdated = entry.timestamp;
|
|
3580
|
-
}
|
|
3581
|
-
} catch {
|
|
3582
|
-
}
|
|
3583
|
-
}
|
|
3584
|
-
}
|
|
3585
|
-
let project = "unknown";
|
|
3586
|
-
const configPath = path7.join(rootDir, ".paradigm", "config.yaml");
|
|
3587
|
-
if (fs6.existsSync(configPath)) {
|
|
3588
|
-
try {
|
|
3589
|
-
const config = yaml5.load(fs6.readFileSync(configPath, "utf8"));
|
|
3590
|
-
project = config.project || config.name || "unknown";
|
|
3591
|
-
} catch {
|
|
3592
|
-
}
|
|
3593
|
-
}
|
|
3594
|
-
const timeline = {
|
|
3595
|
-
version: "1.0",
|
|
3596
|
-
project,
|
|
3597
|
-
entries: entryCount,
|
|
3598
|
-
last_updated: lastUpdated || (/* @__PURE__ */ new Date()).toISOString(),
|
|
3599
|
-
authors: Array.from(authors)
|
|
3600
|
-
};
|
|
3601
|
-
if (!fs6.existsSync(lorePath)) {
|
|
3602
|
-
fs6.mkdirSync(lorePath, { recursive: true });
|
|
3603
|
-
}
|
|
3604
|
-
fs6.writeFileSync(
|
|
3605
|
-
path7.join(lorePath, TIMELINE_FILE),
|
|
3606
|
-
yaml5.dump(timeline, { lineWidth: -1, noRefs: true })
|
|
3607
|
-
);
|
|
3608
|
-
}
|
|
3609
|
-
function migrateLegacyEntries(rootDir) {
|
|
3610
|
-
const entriesPath = path7.join(rootDir, LORE_DIR, ENTRIES_DIR);
|
|
3611
|
-
if (!fs6.existsSync(entriesPath)) return 0;
|
|
3612
|
-
const rootFiles = fs6.readdirSync(entriesPath).filter((f) => isLoreFile(f) && !f.startsWith("."));
|
|
3613
|
-
let migrated = 0;
|
|
3614
|
-
for (const file of rootFiles) {
|
|
3615
|
-
const filePath = path7.join(entriesPath, file);
|
|
3616
|
-
const stat = fs6.statSync(filePath);
|
|
3617
|
-
if (!stat.isFile()) continue;
|
|
3618
|
-
try {
|
|
3619
|
-
const content = fs6.readFileSync(filePath, "utf8");
|
|
3620
|
-
const raw = yaml5.load(content);
|
|
3621
|
-
if (raw.author && typeof raw.author === "object") continue;
|
|
3622
|
-
if (typeof raw.author === "string" && raw.timestamp) continue;
|
|
3623
|
-
const dateStr = typeof raw.date === "string" ? raw.date.slice(0, 10) : (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3624
|
-
const datePath = path7.join(entriesPath, dateStr);
|
|
3625
|
-
if (!fs6.existsSync(datePath)) {
|
|
3626
|
-
fs6.mkdirSync(datePath, { recursive: true });
|
|
3627
|
-
}
|
|
3628
|
-
const author = resolveAuthor();
|
|
3629
|
-
const timestamp = `${dateStr}T00:00:00.000Z`;
|
|
3630
|
-
const id = generateLoreId(rootDir, dateStr, author, timestamp);
|
|
3631
|
-
const oldType = String(raw.type || "agent-session");
|
|
3632
|
-
const v2Type = ["agent-session", "human-note", "decision", "review", "incident", "milestone"].includes(oldType) ? oldType : "agent-session";
|
|
3633
|
-
let verification;
|
|
3634
|
-
if (raw.test_results && typeof raw.test_results === "object") {
|
|
3635
|
-
const tr = raw.test_results;
|
|
3636
|
-
verification = {
|
|
3637
|
-
status: tr.total === tr.passed ? "pass" : "partial",
|
|
3638
|
-
details: { tests: tr.total === tr.passed ? "pass" : "fail" }
|
|
3639
|
-
};
|
|
3640
|
-
}
|
|
3641
|
-
const v2Entry = {
|
|
3642
|
-
id,
|
|
3643
|
-
type: v2Type,
|
|
3644
|
-
timestamp,
|
|
3645
|
-
author: "unknown",
|
|
3646
|
-
agent: { provider: "unknown", model: "unknown" },
|
|
3647
|
-
title: String(raw.title || file.replace(/\.(yaml|lore)$/, "")),
|
|
3648
|
-
summary: String(raw.summary || ""),
|
|
3649
|
-
symbols_touched: Array.isArray(raw.symbols_touched) ? raw.symbols_touched : [],
|
|
3650
|
-
files_modified: Array.isArray(raw.files_modified) ? raw.files_modified : void 0,
|
|
3651
|
-
...verification ? { verification } : {},
|
|
3652
|
-
tags: ["migrated", oldType]
|
|
3653
|
-
};
|
|
3654
|
-
fs6.writeFileSync(
|
|
3655
|
-
path7.join(datePath, `${id}.lore`),
|
|
3656
|
-
yaml5.dump(v2Entry, { lineWidth: -1, noRefs: true })
|
|
3657
|
-
);
|
|
3658
|
-
fs6.unlinkSync(filePath);
|
|
3659
|
-
migrated++;
|
|
3660
|
-
} catch {
|
|
3661
|
-
}
|
|
3662
|
-
}
|
|
3663
|
-
return migrated;
|
|
3664
|
-
}
|
|
3665
|
-
async function updateLoreEntry(rootDir, entryId, partial) {
|
|
3666
|
-
const entry = await loadLoreEntry(rootDir, entryId);
|
|
3667
|
-
if (!entry) return false;
|
|
3668
|
-
const dateStr = entry.timestamp.slice(0, 10);
|
|
3669
|
-
const entryPath = resolveEntryPath(rootDir, dateStr, entryId);
|
|
3670
|
-
if (!entryPath) return false;
|
|
3671
|
-
if (partial.title !== void 0) entry.title = partial.title;
|
|
3672
|
-
if (partial.summary !== void 0) entry.summary = partial.summary;
|
|
3673
|
-
if (partial.type !== void 0) entry.type = partial.type;
|
|
3674
|
-
if (partial.duration_minutes !== void 0) entry.duration_minutes = partial.duration_minutes;
|
|
3675
|
-
if (partial.symbols_touched !== void 0) entry.symbols_touched = partial.symbols_touched;
|
|
3676
|
-
if (partial.symbols_created !== void 0) entry.symbols_created = partial.symbols_created;
|
|
3677
|
-
if (partial.files_created !== void 0) entry.files_created = partial.files_created;
|
|
3678
|
-
if (partial.files_modified !== void 0) entry.files_modified = partial.files_modified;
|
|
3679
|
-
if (partial.lines_added !== void 0) entry.lines_added = partial.lines_added;
|
|
3680
|
-
if (partial.lines_removed !== void 0) entry.lines_removed = partial.lines_removed;
|
|
3681
|
-
if (partial.commit !== void 0) entry.commit = partial.commit;
|
|
3682
|
-
if (partial.decisions !== void 0) entry.decisions = partial.decisions;
|
|
3683
|
-
if (partial.errors_encountered !== void 0) entry.errors_encountered = partial.errors_encountered;
|
|
3684
|
-
if (partial.learnings !== void 0) entry.learnings = partial.learnings;
|
|
3685
|
-
if (partial.verification !== void 0) entry.verification = partial.verification;
|
|
3686
|
-
if (partial.tags !== void 0) entry.tags = partial.tags;
|
|
3687
|
-
fs6.writeFileSync(entryPath, yaml5.dump(entry, { lineWidth: -1, noRefs: true }));
|
|
3688
|
-
await rebuildTimeline(rootDir);
|
|
3689
|
-
return true;
|
|
3690
|
-
}
|
|
3691
|
-
async function deleteLoreEntry(rootDir, entryId) {
|
|
3692
|
-
const entry = await loadLoreEntry(rootDir, entryId);
|
|
3693
|
-
if (!entry) return false;
|
|
3694
|
-
const dateStr = entry.timestamp.slice(0, 10);
|
|
3695
|
-
const entryPath = resolveEntryPath(rootDir, dateStr, entryId);
|
|
3696
|
-
if (!entryPath) return false;
|
|
3697
|
-
fs6.unlinkSync(entryPath);
|
|
3698
|
-
const dateDir = path7.dirname(entryPath);
|
|
3699
|
-
const remaining = fs6.readdirSync(dateDir).filter(isLoreFile);
|
|
3700
|
-
if (remaining.length === 0) {
|
|
3701
|
-
fs6.rmdirSync(dateDir);
|
|
3702
|
-
}
|
|
3703
|
-
await rebuildTimeline(rootDir);
|
|
3704
|
-
return true;
|
|
3705
|
-
}
|
|
3706
|
-
function applyFilter(entries, filter) {
|
|
3707
|
-
let result = entries;
|
|
3708
|
-
if (filter.author) {
|
|
3709
|
-
result = result.filter((e) => e.author === filter.author);
|
|
3710
|
-
}
|
|
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
|
-
);
|
|
3719
|
-
}
|
|
3720
|
-
if (filter.symbol) {
|
|
3721
|
-
result = result.filter(
|
|
3722
|
-
(e) => e.symbols_touched.includes(filter.symbol) || e.symbols_created?.includes(filter.symbol)
|
|
3723
|
-
);
|
|
3724
|
-
}
|
|
3725
|
-
if (filter.dateFrom) {
|
|
3726
|
-
const from = new Date(filter.dateFrom).getTime();
|
|
3727
|
-
result = result.filter((e) => new Date(e.timestamp).getTime() >= from);
|
|
3728
|
-
}
|
|
3729
|
-
if (filter.dateTo) {
|
|
3730
|
-
const to = new Date(filter.dateTo).getTime();
|
|
3731
|
-
result = result.filter((e) => new Date(e.timestamp).getTime() <= to);
|
|
3732
|
-
}
|
|
3733
|
-
if (filter.type) {
|
|
3734
|
-
result = result.filter((e) => e.type === filter.type);
|
|
3735
|
-
}
|
|
3736
|
-
if (filter.tags && filter.tags.length > 0) {
|
|
3737
|
-
result = result.filter((e) => filter.tags.some((tag) => e.tags?.includes(tag)));
|
|
3738
|
-
}
|
|
3739
|
-
if (filter.hasReview !== void 0) {
|
|
3740
|
-
result = result.filter((e) => filter.hasReview ? e.review != null : e.review == null);
|
|
3741
|
-
}
|
|
3742
|
-
result.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
3743
|
-
if (filter.offset) result = result.slice(filter.offset);
|
|
3744
|
-
if (filter.limit) result = result.slice(0, filter.limit);
|
|
3745
|
-
return result;
|
|
3746
|
-
}
|
|
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}`;
|
|
3755
|
-
const datePath = path7.join(rootDir, LORE_DIR, ENTRIES_DIR, dateStr);
|
|
3756
|
-
if (!fs6.existsSync(datePath)) {
|
|
3757
|
-
return `${prefix}-001`;
|
|
3758
|
-
}
|
|
3759
|
-
const existing = fs6.readdirSync(datePath).filter((f) => f.startsWith(prefix) && isLoreFile(f)).map((f) => {
|
|
3760
|
-
const match = f.match(/-(\d{3})\.(yaml|lore)$/);
|
|
3761
|
-
return match ? parseInt(match[1], 10) : 0;
|
|
3762
|
-
});
|
|
3763
|
-
const next = existing.length > 0 ? Math.max(...existing) + 1 : 1;
|
|
3764
|
-
return `${prefix}-${String(next).padStart(3, "0")}`;
|
|
3765
|
-
}
|
|
3766
|
-
|
|
3767
3414
|
// ../paradigm-mcp/src/utils/aspect-lore-bridge.ts
|
|
3768
3415
|
var LORE_ID_PATTERN = /L-\d{4}-\d{2}-\d{2}-\d{3}/g;
|
|
3769
3416
|
async function materializeLoreLinks(db, rootDir) {
|
|
@@ -3960,38 +3607,38 @@ function toLoreSummary(entry) {
|
|
|
3960
3607
|
}
|
|
3961
3608
|
|
|
3962
3609
|
// ../paradigm-mcp/src/utils/personas-loader.ts
|
|
3963
|
-
import * as
|
|
3964
|
-
import * as
|
|
3965
|
-
import * as
|
|
3610
|
+
import * as fs6 from "fs";
|
|
3611
|
+
import * as path7 from "path";
|
|
3612
|
+
import * as yaml5 from "js-yaml";
|
|
3966
3613
|
var PERSONAS_ROOT = ".paradigm/personas";
|
|
3967
3614
|
var INDEX_FILE = "index.yaml";
|
|
3968
3615
|
async function loadPersonas(rootDir, filter) {
|
|
3969
|
-
const personasDir =
|
|
3970
|
-
if (!
|
|
3971
|
-
const files =
|
|
3616
|
+
const personasDir = path7.join(rootDir, PERSONAS_ROOT);
|
|
3617
|
+
if (!fs6.existsSync(personasDir)) return [];
|
|
3618
|
+
const files = fs6.readdirSync(personasDir).filter((f) => f.endsWith(".persona"));
|
|
3972
3619
|
const personas = [];
|
|
3973
3620
|
for (const file of files) {
|
|
3974
3621
|
try {
|
|
3975
|
-
const content =
|
|
3976
|
-
const persona =
|
|
3622
|
+
const content = fs6.readFileSync(path7.join(personasDir, file), "utf8");
|
|
3623
|
+
const persona = yaml5.load(content);
|
|
3977
3624
|
if (persona && persona.id) {
|
|
3978
3625
|
personas.push(persona);
|
|
3979
3626
|
}
|
|
3980
3627
|
} catch {
|
|
3981
3628
|
}
|
|
3982
3629
|
}
|
|
3983
|
-
return
|
|
3630
|
+
return applyFilter(personas, filter);
|
|
3984
3631
|
}
|
|
3985
3632
|
async function loadPersona(rootDir, id) {
|
|
3986
|
-
const filePath =
|
|
3987
|
-
if (!
|
|
3633
|
+
const filePath = path7.join(rootDir, PERSONAS_ROOT, `${id}.persona`);
|
|
3634
|
+
if (!fs6.existsSync(filePath)) return null;
|
|
3988
3635
|
try {
|
|
3989
|
-
return
|
|
3636
|
+
return yaml5.load(fs6.readFileSync(filePath, "utf8"));
|
|
3990
3637
|
} catch {
|
|
3991
3638
|
return null;
|
|
3992
3639
|
}
|
|
3993
3640
|
}
|
|
3994
|
-
function
|
|
3641
|
+
function applyFilter(personas, filter) {
|
|
3995
3642
|
if (!filter) return personas;
|
|
3996
3643
|
let result = personas;
|
|
3997
3644
|
if (filter.tag) {
|
|
@@ -4016,10 +3663,10 @@ function applyFilter2(personas, filter) {
|
|
|
4016
3663
|
return result;
|
|
4017
3664
|
}
|
|
4018
3665
|
async function createPersona(rootDir, data) {
|
|
4019
|
-
const personasDir =
|
|
4020
|
-
|
|
4021
|
-
const filePath =
|
|
4022
|
-
if (
|
|
3666
|
+
const personasDir = path7.join(rootDir, PERSONAS_ROOT);
|
|
3667
|
+
fs6.mkdirSync(personasDir, { recursive: true });
|
|
3668
|
+
const filePath = path7.join(personasDir, `${data.id}.persona`);
|
|
3669
|
+
if (fs6.existsSync(filePath)) {
|
|
4023
3670
|
throw new Error(`Persona ${data.id} already exists`);
|
|
4024
3671
|
}
|
|
4025
3672
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -4036,14 +3683,14 @@ async function createPersona(rootDir, data) {
|
|
|
4036
3683
|
created: now,
|
|
4037
3684
|
updated: now
|
|
4038
3685
|
};
|
|
4039
|
-
|
|
3686
|
+
fs6.writeFileSync(filePath, yaml5.dump(persona, { indent: 2, lineWidth: 120, noRefs: true, sortKeys: false }));
|
|
4040
3687
|
await rebuildPersonaIndex(rootDir);
|
|
4041
3688
|
return data.id;
|
|
4042
3689
|
}
|
|
4043
3690
|
async function updatePersona(rootDir, id, partial) {
|
|
4044
3691
|
const persona = await loadPersona(rootDir, id);
|
|
4045
3692
|
if (!persona) return false;
|
|
4046
|
-
const filePath =
|
|
3693
|
+
const filePath = path7.join(rootDir, PERSONAS_ROOT, `${id}.persona`);
|
|
4047
3694
|
const updated = {
|
|
4048
3695
|
...persona,
|
|
4049
3696
|
...partial,
|
|
@@ -4055,13 +3702,13 @@ async function updatePersona(rootDir, id, partial) {
|
|
|
4055
3702
|
// immutable
|
|
4056
3703
|
updated: (/* @__PURE__ */ new Date()).toISOString()
|
|
4057
3704
|
};
|
|
4058
|
-
|
|
3705
|
+
fs6.writeFileSync(filePath, yaml5.dump(updated, { indent: 2, lineWidth: 120, noRefs: true, sortKeys: false }));
|
|
4059
3706
|
await rebuildPersonaIndex(rootDir);
|
|
4060
3707
|
return true;
|
|
4061
3708
|
}
|
|
4062
3709
|
async function deletePersona(rootDir, id) {
|
|
4063
|
-
const filePath =
|
|
4064
|
-
if (!
|
|
3710
|
+
const filePath = path7.join(rootDir, PERSONAS_ROOT, `${id}.persona`);
|
|
3711
|
+
if (!fs6.existsSync(filePath)) {
|
|
4065
3712
|
return { deleted: false, warnings: [] };
|
|
4066
3713
|
}
|
|
4067
3714
|
const warnings = [];
|
|
@@ -4077,7 +3724,7 @@ async function deletePersona(rootDir, id) {
|
|
|
4077
3724
|
}
|
|
4078
3725
|
}
|
|
4079
3726
|
}
|
|
4080
|
-
|
|
3727
|
+
fs6.unlinkSync(filePath);
|
|
4081
3728
|
await rebuildPersonaIndex(rootDir);
|
|
4082
3729
|
return { deleted: true, warnings };
|
|
4083
3730
|
}
|
|
@@ -4179,12 +3826,12 @@ async function validatePersona(rootDir, persona, deep = false) {
|
|
|
4179
3826
|
}
|
|
4180
3827
|
}
|
|
4181
3828
|
if (deep) {
|
|
4182
|
-
const portalPath =
|
|
3829
|
+
const portalPath = path7.join(rootDir, "portal.yaml");
|
|
4183
3830
|
let portalGates = [];
|
|
4184
3831
|
let portalRoutes = [];
|
|
4185
|
-
if (
|
|
3832
|
+
if (fs6.existsSync(portalPath)) {
|
|
4186
3833
|
try {
|
|
4187
|
-
const portal =
|
|
3834
|
+
const portal = yaml5.load(fs6.readFileSync(portalPath, "utf8"));
|
|
4188
3835
|
if (portal.gates && typeof portal.gates === "object") {
|
|
4189
3836
|
portalGates = Object.keys(portal.gates);
|
|
4190
3837
|
}
|
|
@@ -4235,10 +3882,10 @@ async function validatePersona(rootDir, persona, deep = false) {
|
|
|
4235
3882
|
}
|
|
4236
3883
|
}
|
|
4237
3884
|
let allFlows = [];
|
|
4238
|
-
const flowIndexPath =
|
|
4239
|
-
if (
|
|
3885
|
+
const flowIndexPath = path7.join(rootDir, ".paradigm", "flow-index.json");
|
|
3886
|
+
if (fs6.existsSync(flowIndexPath)) {
|
|
4240
3887
|
try {
|
|
4241
|
-
const flowIndex = JSON.parse(
|
|
3888
|
+
const flowIndex = JSON.parse(fs6.readFileSync(flowIndexPath, "utf8"));
|
|
4242
3889
|
allFlows = Object.keys(flowIndex.flows || {});
|
|
4243
3890
|
} catch {
|
|
4244
3891
|
}
|
|
@@ -4315,8 +3962,8 @@ async function detectSpawnCycle(rootDir, startId) {
|
|
|
4315
3962
|
return visit(startId);
|
|
4316
3963
|
}
|
|
4317
3964
|
async function rebuildPersonaIndex(rootDir) {
|
|
4318
|
-
const personasDir =
|
|
4319
|
-
|
|
3965
|
+
const personasDir = path7.join(rootDir, PERSONAS_ROOT);
|
|
3966
|
+
fs6.mkdirSync(personasDir, { recursive: true });
|
|
4320
3967
|
const personas = await loadPersonas(rootDir);
|
|
4321
3968
|
const entries = {};
|
|
4322
3969
|
const gateCoverage = {};
|
|
@@ -4355,10 +4002,10 @@ async function rebuildPersonaIndex(rootDir) {
|
|
|
4355
4002
|
}
|
|
4356
4003
|
}
|
|
4357
4004
|
let uncoveredRoutes = [];
|
|
4358
|
-
const portalPath =
|
|
4359
|
-
if (
|
|
4005
|
+
const portalPath = path7.join(rootDir, "portal.yaml");
|
|
4006
|
+
if (fs6.existsSync(portalPath)) {
|
|
4360
4007
|
try {
|
|
4361
|
-
const portal =
|
|
4008
|
+
const portal = yaml5.load(fs6.readFileSync(portalPath, "utf8"));
|
|
4362
4009
|
if (portal.routes && typeof portal.routes === "object") {
|
|
4363
4010
|
const portalRoutes = Object.keys(portal.routes);
|
|
4364
4011
|
uncoveredRoutes = portalRoutes.filter((pr) => {
|
|
@@ -4369,13 +4016,13 @@ async function rebuildPersonaIndex(rootDir) {
|
|
|
4369
4016
|
}
|
|
4370
4017
|
}
|
|
4371
4018
|
const chains = {};
|
|
4372
|
-
const chainsDir =
|
|
4373
|
-
if (
|
|
4374
|
-
const chainFiles =
|
|
4019
|
+
const chainsDir = path7.join(personasDir, "chains");
|
|
4020
|
+
if (fs6.existsSync(chainsDir)) {
|
|
4021
|
+
const chainFiles = fs6.readdirSync(chainsDir).filter((f) => f.endsWith(".yaml"));
|
|
4375
4022
|
for (const file of chainFiles) {
|
|
4376
4023
|
try {
|
|
4377
|
-
const content =
|
|
4378
|
-
const chain =
|
|
4024
|
+
const content = fs6.readFileSync(path7.join(chainsDir, file), "utf8");
|
|
4025
|
+
const chain = yaml5.load(content);
|
|
4379
4026
|
if (chain && chain.id) {
|
|
4380
4027
|
const orderIds = chain.order.map((o) => o.persona);
|
|
4381
4028
|
let totalSteps = 0;
|
|
@@ -4407,9 +4054,9 @@ async function rebuildPersonaIndex(rootDir) {
|
|
|
4407
4054
|
route_coverage: routeCoverage,
|
|
4408
4055
|
uncovered_routes: uncoveredRoutes
|
|
4409
4056
|
};
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4057
|
+
fs6.writeFileSync(
|
|
4058
|
+
path7.join(personasDir, INDEX_FILE),
|
|
4059
|
+
yaml5.dump(index, { indent: 2, lineWidth: 120, noRefs: true, sortKeys: false })
|
|
4413
4060
|
);
|
|
4414
4061
|
return index;
|
|
4415
4062
|
}
|
|
@@ -4427,20 +4074,20 @@ async function getPersonaCoverage(rootDir) {
|
|
|
4427
4074
|
}
|
|
4428
4075
|
let portalGates = [];
|
|
4429
4076
|
let portalRoutes = [];
|
|
4430
|
-
const portalPath =
|
|
4431
|
-
if (
|
|
4077
|
+
const portalPath = path7.join(rootDir, "portal.yaml");
|
|
4078
|
+
if (fs6.existsSync(portalPath)) {
|
|
4432
4079
|
try {
|
|
4433
|
-
const portal =
|
|
4080
|
+
const portal = yaml5.load(fs6.readFileSync(portalPath, "utf8"));
|
|
4434
4081
|
if (portal.gates && typeof portal.gates === "object") portalGates = Object.keys(portal.gates);
|
|
4435
4082
|
if (portal.routes && typeof portal.routes === "object") portalRoutes = Object.keys(portal.routes);
|
|
4436
4083
|
} catch {
|
|
4437
4084
|
}
|
|
4438
4085
|
}
|
|
4439
4086
|
let allFlows = [];
|
|
4440
|
-
const flowIndexPath =
|
|
4441
|
-
if (
|
|
4087
|
+
const flowIndexPath = path7.join(rootDir, ".paradigm", "flow-index.json");
|
|
4088
|
+
if (fs6.existsSync(flowIndexPath)) {
|
|
4442
4089
|
try {
|
|
4443
|
-
const flowIndex = JSON.parse(
|
|
4090
|
+
const flowIndex = JSON.parse(fs6.readFileSync(flowIndexPath, "utf8"));
|
|
4444
4091
|
allFlows = Object.keys(flowIndex.flows || {});
|
|
4445
4092
|
} catch {
|
|
4446
4093
|
}
|
|
@@ -4489,8 +4136,8 @@ async function getAffectedPersonas(rootDir, symbol) {
|
|
|
4489
4136
|
}
|
|
4490
4137
|
return results;
|
|
4491
4138
|
}
|
|
4492
|
-
function deepGet(obj,
|
|
4493
|
-
const parts =
|
|
4139
|
+
function deepGet(obj, path10) {
|
|
4140
|
+
const parts = path10.split(/[.\[\]]+/).filter(Boolean);
|
|
4494
4141
|
let current = obj;
|
|
4495
4142
|
for (const part of parts) {
|
|
4496
4143
|
if (current == null || typeof current !== "object") return void 0;
|
|
@@ -4659,22 +4306,22 @@ async function validateAgainstSentinel(persona, options = {}) {
|
|
|
4659
4306
|
}
|
|
4660
4307
|
|
|
4661
4308
|
// ../paradigm-mcp/src/utils/protocol-loader.ts
|
|
4662
|
-
import * as
|
|
4663
|
-
import * as
|
|
4664
|
-
import * as
|
|
4309
|
+
import * as fs7 from "fs";
|
|
4310
|
+
import * as path8 from "path";
|
|
4311
|
+
import * as yaml6 from "js-yaml";
|
|
4665
4312
|
var PROTOCOLS_DIR = ".paradigm/protocols";
|
|
4666
4313
|
var INDEX_FILE2 = "index.yaml";
|
|
4667
4314
|
async function loadProtocols(rootDir) {
|
|
4668
|
-
const protocolsDir =
|
|
4669
|
-
if (!
|
|
4315
|
+
const protocolsDir = path8.join(rootDir, PROTOCOLS_DIR);
|
|
4316
|
+
if (!fs7.existsSync(protocolsDir)) {
|
|
4670
4317
|
return [];
|
|
4671
4318
|
}
|
|
4672
|
-
const files =
|
|
4319
|
+
const files = fs7.readdirSync(protocolsDir).filter((f) => f.endsWith(".protocol")).sort();
|
|
4673
4320
|
const protocols = [];
|
|
4674
4321
|
for (const file of files) {
|
|
4675
4322
|
try {
|
|
4676
|
-
const content =
|
|
4677
|
-
const protocol =
|
|
4323
|
+
const content = fs7.readFileSync(path8.join(protocolsDir, file), "utf8");
|
|
4324
|
+
const protocol = yaml6.load(content);
|
|
4678
4325
|
if (protocol?.id && protocol?.name) {
|
|
4679
4326
|
protocols.push(protocol);
|
|
4680
4327
|
}
|
|
@@ -4685,11 +4332,11 @@ async function loadProtocols(rootDir) {
|
|
|
4685
4332
|
}
|
|
4686
4333
|
async function loadProtocol(rootDir, id) {
|
|
4687
4334
|
const slug = id.replace(/^P-/, "");
|
|
4688
|
-
const filePath =
|
|
4689
|
-
if (
|
|
4335
|
+
const filePath = path8.join(rootDir, PROTOCOLS_DIR, `${slug}.protocol`);
|
|
4336
|
+
if (fs7.existsSync(filePath)) {
|
|
4690
4337
|
try {
|
|
4691
|
-
const content =
|
|
4692
|
-
return
|
|
4338
|
+
const content = fs7.readFileSync(filePath, "utf8");
|
|
4339
|
+
return yaml6.load(content);
|
|
4693
4340
|
} catch {
|
|
4694
4341
|
return null;
|
|
4695
4342
|
}
|
|
@@ -4698,13 +4345,13 @@ async function loadProtocol(rootDir, id) {
|
|
|
4698
4345
|
return protocols.find((p) => p.id === id) || null;
|
|
4699
4346
|
}
|
|
4700
4347
|
async function loadProtocolIndex(rootDir) {
|
|
4701
|
-
const indexPath =
|
|
4702
|
-
if (!
|
|
4348
|
+
const indexPath = path8.join(rootDir, PROTOCOLS_DIR, INDEX_FILE2);
|
|
4349
|
+
if (!fs7.existsSync(indexPath)) {
|
|
4703
4350
|
return null;
|
|
4704
4351
|
}
|
|
4705
4352
|
try {
|
|
4706
|
-
const content =
|
|
4707
|
-
return
|
|
4353
|
+
const content = fs7.readFileSync(indexPath, "utf8");
|
|
4354
|
+
return yaml6.load(content);
|
|
4708
4355
|
} catch {
|
|
4709
4356
|
return null;
|
|
4710
4357
|
}
|
|
@@ -4755,9 +4402,9 @@ async function searchProtocols(rootDir, task, limit = 3) {
|
|
|
4755
4402
|
return scored.slice(0, limit);
|
|
4756
4403
|
}
|
|
4757
4404
|
async function recordProtocol(rootDir, protocol) {
|
|
4758
|
-
const protocolsDir =
|
|
4759
|
-
if (!
|
|
4760
|
-
|
|
4405
|
+
const protocolsDir = path8.join(rootDir, PROTOCOLS_DIR);
|
|
4406
|
+
if (!fs7.existsSync(protocolsDir)) {
|
|
4407
|
+
fs7.mkdirSync(protocolsDir, { recursive: true });
|
|
4761
4408
|
}
|
|
4762
4409
|
const slug = slugify(protocol.name);
|
|
4763
4410
|
const id = `P-${slug}`;
|
|
@@ -4777,8 +4424,8 @@ async function recordProtocol(rootDir, protocol) {
|
|
|
4777
4424
|
verified_by: protocol.verified_by || "claude-opus-4-6",
|
|
4778
4425
|
status: "current"
|
|
4779
4426
|
};
|
|
4780
|
-
const filePath =
|
|
4781
|
-
|
|
4427
|
+
const filePath = path8.join(protocolsDir, `${slug}.protocol`);
|
|
4428
|
+
fs7.writeFileSync(filePath, yaml6.dump(full, { lineWidth: -1, noRefs: true }), "utf8");
|
|
4782
4429
|
return id;
|
|
4783
4430
|
}
|
|
4784
4431
|
async function updateProtocol(rootDir, id, partial, refresh = false) {
|
|
@@ -4798,20 +4445,20 @@ async function updateProtocol(rootDir, id, partial, refresh = false) {
|
|
|
4798
4445
|
protocol.verified_by = partial.verified_by || "claude-opus-4-6";
|
|
4799
4446
|
}
|
|
4800
4447
|
const slug = id.replace(/^P-/, "");
|
|
4801
|
-
const filePath =
|
|
4802
|
-
|
|
4448
|
+
const filePath = path8.join(rootDir, PROTOCOLS_DIR, `${slug}.protocol`);
|
|
4449
|
+
fs7.writeFileSync(filePath, yaml6.dump(protocol, { lineWidth: -1, noRefs: true }), "utf8");
|
|
4803
4450
|
return true;
|
|
4804
4451
|
}
|
|
4805
4452
|
function validateProtocol(rootDir, protocol) {
|
|
4806
4453
|
const issues = [];
|
|
4807
4454
|
let status = "current";
|
|
4808
4455
|
if (protocol.exemplar) {
|
|
4809
|
-
const exemplarPath =
|
|
4810
|
-
if (!
|
|
4456
|
+
const exemplarPath = path8.join(rootDir, protocol.exemplar);
|
|
4457
|
+
if (!fs7.existsSync(exemplarPath)) {
|
|
4811
4458
|
issues.push(`Exemplar missing: ${protocol.exemplar}`);
|
|
4812
4459
|
status = "broken";
|
|
4813
4460
|
} else {
|
|
4814
|
-
const stat =
|
|
4461
|
+
const stat = fs7.statSync(exemplarPath);
|
|
4815
4462
|
if (stat.mtime.toISOString() > protocol.last_verified) {
|
|
4816
4463
|
issues.push(`Exemplar modified since last verified: ${protocol.exemplar}`);
|
|
4817
4464
|
if (status !== "broken") status = "stale";
|
|
@@ -4820,15 +4467,15 @@ function validateProtocol(rootDir, protocol) {
|
|
|
4820
4467
|
}
|
|
4821
4468
|
for (const step of protocol.steps) {
|
|
4822
4469
|
if (step.template_from) {
|
|
4823
|
-
const templatePath =
|
|
4824
|
-
if (!
|
|
4470
|
+
const templatePath = path8.join(rootDir, step.template_from);
|
|
4471
|
+
if (!fs7.existsSync(templatePath)) {
|
|
4825
4472
|
issues.push(`Template file missing: ${step.template_from}`);
|
|
4826
4473
|
status = "broken";
|
|
4827
4474
|
}
|
|
4828
4475
|
}
|
|
4829
4476
|
if (step.action === "modify" && step.target) {
|
|
4830
|
-
const targetPath =
|
|
4831
|
-
if (!step.target.includes("{") && !
|
|
4477
|
+
const targetPath = path8.join(rootDir, step.target);
|
|
4478
|
+
if (!step.target.includes("{") && !fs7.existsSync(targetPath)) {
|
|
4832
4479
|
issues.push(`Modify target missing: ${step.target}`);
|
|
4833
4480
|
status = "broken";
|
|
4834
4481
|
}
|
|
@@ -4847,9 +4494,9 @@ async function rebuildProtocolIndex(rootDir) {
|
|
|
4847
4494
|
if (protocol.status !== validation.status) {
|
|
4848
4495
|
protocol.status = validation.status;
|
|
4849
4496
|
const slug = protocol.id.replace(/^P-/, "");
|
|
4850
|
-
const filePath =
|
|
4851
|
-
if (
|
|
4852
|
-
|
|
4497
|
+
const filePath = path8.join(rootDir, PROTOCOLS_DIR, `${slug}.protocol`);
|
|
4498
|
+
if (fs7.existsSync(filePath)) {
|
|
4499
|
+
fs7.writeFileSync(filePath, yaml6.dump(protocol, { lineWidth: -1, noRefs: true }), "utf8");
|
|
4853
4500
|
}
|
|
4854
4501
|
}
|
|
4855
4502
|
switch (validation.status) {
|
|
@@ -4883,13 +4530,13 @@ async function rebuildProtocolIndex(rootDir) {
|
|
|
4883
4530
|
broken
|
|
4884
4531
|
}
|
|
4885
4532
|
};
|
|
4886
|
-
const protocolsDir =
|
|
4533
|
+
const protocolsDir = path8.join(rootDir, PROTOCOLS_DIR);
|
|
4887
4534
|
if (protocols.length > 0) {
|
|
4888
|
-
if (!
|
|
4889
|
-
|
|
4535
|
+
if (!fs7.existsSync(protocolsDir)) {
|
|
4536
|
+
fs7.mkdirSync(protocolsDir, { recursive: true });
|
|
4890
4537
|
}
|
|
4891
|
-
const indexPath =
|
|
4892
|
-
|
|
4538
|
+
const indexPath = path8.join(protocolsDir, INDEX_FILE2);
|
|
4539
|
+
fs7.writeFileSync(indexPath, yaml6.dump(index, { lineWidth: -1, noRefs: true }), "utf8");
|
|
4893
4540
|
}
|
|
4894
4541
|
return index;
|
|
4895
4542
|
}
|
|
@@ -4897,21 +4544,21 @@ function detectProtocolSuggestion(rootDir, filesCreated, filesModified) {
|
|
|
4897
4544
|
if (!filesCreated || filesCreated.length < 2) return null;
|
|
4898
4545
|
const dirGroups = {};
|
|
4899
4546
|
for (const file of filesCreated) {
|
|
4900
|
-
const dir =
|
|
4547
|
+
const dir = path8.dirname(file);
|
|
4901
4548
|
if (!dirGroups[dir]) dirGroups[dir] = [];
|
|
4902
4549
|
dirGroups[dir].push(file);
|
|
4903
4550
|
}
|
|
4904
4551
|
for (const [dir, created] of Object.entries(dirGroups)) {
|
|
4905
4552
|
if (created.length < 2) continue;
|
|
4906
|
-
const absDir =
|
|
4907
|
-
if (!
|
|
4908
|
-
const existing =
|
|
4909
|
-
const ext =
|
|
4553
|
+
const absDir = path8.join(rootDir, dir);
|
|
4554
|
+
if (!fs7.existsSync(absDir)) continue;
|
|
4555
|
+
const existing = fs7.readdirSync(absDir).filter((f) => {
|
|
4556
|
+
const ext = path8.extname(f);
|
|
4910
4557
|
return [".ts", ".tsx", ".js", ".jsx", ".rs", ".py"].includes(ext);
|
|
4911
4558
|
});
|
|
4912
|
-
const preExisting = existing.filter((f) => !created.some((c) =>
|
|
4559
|
+
const preExisting = existing.filter((f) => !created.some((c) => path8.basename(c) === f));
|
|
4913
4560
|
if (preExisting.length > 0) {
|
|
4914
|
-
const exemplar =
|
|
4561
|
+
const exemplar = path8.join(dir, preExisting[0]);
|
|
4915
4562
|
const steps = [
|
|
4916
4563
|
...created.map((f) => ({ action: "create", target: f })),
|
|
4917
4564
|
...filesModified.map((f) => ({ action: "modify", target: f }))
|
|
@@ -4919,7 +4566,7 @@ function detectProtocolSuggestion(rootDir, filesCreated, filesModified) {
|
|
|
4919
4566
|
return {
|
|
4920
4567
|
hint: `This session created ${created.length} new files in ${dir}/ following existing patterns. Consider recording a protocol.`,
|
|
4921
4568
|
draft: {
|
|
4922
|
-
name: `Add a ${
|
|
4569
|
+
name: `Add a ${path8.basename(dir).replace(/s$/, "")}`,
|
|
4923
4570
|
exemplar,
|
|
4924
4571
|
steps
|
|
4925
4572
|
}
|
|
@@ -5081,10 +4728,10 @@ async function rebuildStaticFiles(rootDir, ctx) {
|
|
|
5081
4728
|
} else {
|
|
5082
4729
|
aggregation = await aggregateFromDirectory(rootDir);
|
|
5083
4730
|
}
|
|
5084
|
-
const projectName = ctx?.projectName ||
|
|
5085
|
-
const paradigmDir =
|
|
5086
|
-
if (!
|
|
5087
|
-
|
|
4731
|
+
const projectName = ctx?.projectName || path9.basename(rootDir);
|
|
4732
|
+
const paradigmDir = path9.join(rootDir, ".paradigm");
|
|
4733
|
+
if (!fs8.existsSync(paradigmDir)) {
|
|
4734
|
+
fs8.mkdirSync(paradigmDir, { recursive: true });
|
|
5088
4735
|
}
|
|
5089
4736
|
const scanIndex = generateScanIndex(
|
|
5090
4737
|
{
|
|
@@ -5094,22 +4741,22 @@ async function rebuildStaticFiles(rootDir, ctx) {
|
|
|
5094
4741
|
},
|
|
5095
4742
|
{ projectName }
|
|
5096
4743
|
);
|
|
5097
|
-
const scanIndexPath =
|
|
5098
|
-
|
|
4744
|
+
const scanIndexPath = path9.join(paradigmDir, "scan-index.json");
|
|
4745
|
+
fs8.writeFileSync(scanIndexPath, serializeScanIndex(scanIndex), "utf8");
|
|
5099
4746
|
filesWritten.push(".paradigm/scan-index.json");
|
|
5100
4747
|
const navigatorData = buildNavigatorData(rootDir, aggregation);
|
|
5101
|
-
const navigatorPath =
|
|
5102
|
-
|
|
4748
|
+
const navigatorPath = path9.join(paradigmDir, "navigator.yaml");
|
|
4749
|
+
fs8.writeFileSync(
|
|
5103
4750
|
navigatorPath,
|
|
5104
|
-
|
|
4751
|
+
yaml7.dump(navigatorData, { indent: 2, lineWidth: 120, noRefs: true, sortKeys: false }),
|
|
5105
4752
|
"utf8"
|
|
5106
4753
|
);
|
|
5107
4754
|
filesWritten.push(".paradigm/navigator.yaml");
|
|
5108
4755
|
const flowIndex = generateFlowIndex(rootDir, aggregation.purposeFiles);
|
|
5109
4756
|
let flowCount = 0;
|
|
5110
4757
|
if (flowIndex && Object.keys(flowIndex.flows).length > 0) {
|
|
5111
|
-
const flowIndexPath =
|
|
5112
|
-
|
|
4758
|
+
const flowIndexPath = path9.join(paradigmDir, "flow-index.json");
|
|
4759
|
+
fs8.writeFileSync(flowIndexPath, JSON.stringify(flowIndex, null, 2), "utf8");
|
|
5113
4760
|
filesWritten.push(".paradigm/flow-index.json");
|
|
5114
4761
|
flowCount = Object.keys(flowIndex.flows).length;
|
|
5115
4762
|
}
|
|
@@ -5178,7 +4825,7 @@ function buildNavigatorData(rootDir, aggregation) {
|
|
|
5178
4825
|
function buildStructure(rootDir) {
|
|
5179
4826
|
const structure = {};
|
|
5180
4827
|
for (const [category, patterns] of Object.entries(DIRECTORY_PATTERNS)) {
|
|
5181
|
-
const existingPaths = patterns.filter((p) =>
|
|
4828
|
+
const existingPaths = patterns.filter((p) => fs8.existsSync(path9.join(rootDir, p)));
|
|
5182
4829
|
if (existingPaths.length > 0) {
|
|
5183
4830
|
const symbolInfo = Object.values(SYMBOL_CATEGORIES).find((s) => s.category === category);
|
|
5184
4831
|
structure[category] = { paths: existingPaths, symbol: symbolInfo?.prefix || "@" };
|
|
@@ -5189,7 +4836,7 @@ function buildStructure(rootDir) {
|
|
|
5189
4836
|
function buildKeyFiles(rootDir) {
|
|
5190
4837
|
const keyFiles = {};
|
|
5191
4838
|
for (const [category, patterns] of Object.entries(KEY_FILE_PATTERNS)) {
|
|
5192
|
-
const existingPaths = patterns.filter((p) =>
|
|
4839
|
+
const existingPaths = patterns.filter((p) => fs8.existsSync(path9.join(rootDir, p)));
|
|
5193
4840
|
if (existingPaths.length > 0) {
|
|
5194
4841
|
keyFiles[category] = existingPaths;
|
|
5195
4842
|
}
|
|
@@ -5205,10 +4852,10 @@ function buildSkipPatterns(rootDir) {
|
|
|
5205
4852
|
unless_testing: [...DEFAULT_SKIP_PATTERNS.unless_testing],
|
|
5206
4853
|
unless_docs: [...DEFAULT_SKIP_PATTERNS.unless_docs]
|
|
5207
4854
|
};
|
|
5208
|
-
const gitignorePath =
|
|
5209
|
-
if (
|
|
4855
|
+
const gitignorePath = path9.join(rootDir, ".gitignore");
|
|
4856
|
+
if (fs8.existsSync(gitignorePath)) {
|
|
5210
4857
|
try {
|
|
5211
|
-
const content =
|
|
4858
|
+
const content = fs8.readFileSync(gitignorePath, "utf8");
|
|
5212
4859
|
const gitignorePatterns = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).filter(
|
|
5213
4860
|
(line) => line.endsWith("/") || line.includes("*") || ["node_modules", "dist", "build", ".cache"].some((p) => line.includes(p))
|
|
5214
4861
|
).slice(0, 20);
|
|
@@ -5257,11 +4904,11 @@ function buildSymbolMap(symbols, purposeFiles, _rootDir) {
|
|
|
5257
4904
|
symbolMap[symbolId] = symbol.filePath;
|
|
5258
4905
|
} else {
|
|
5259
4906
|
const matchingPurpose = purposeFiles.find((pf) => {
|
|
5260
|
-
const dir =
|
|
4907
|
+
const dir = path9.dirname(pf);
|
|
5261
4908
|
return dir.toLowerCase().includes(symbol.id.toLowerCase());
|
|
5262
4909
|
});
|
|
5263
4910
|
if (matchingPurpose) {
|
|
5264
|
-
symbolMap[symbolId] =
|
|
4911
|
+
symbolMap[symbolId] = path9.dirname(matchingPurpose) + "/";
|
|
5265
4912
|
}
|
|
5266
4913
|
}
|
|
5267
4914
|
}
|
|
@@ -5272,8 +4919,8 @@ function generateFlowIndex(rootDir, purposeFiles) {
|
|
|
5272
4919
|
const symbolToFlows = {};
|
|
5273
4920
|
for (const filePath of purposeFiles) {
|
|
5274
4921
|
try {
|
|
5275
|
-
const content =
|
|
5276
|
-
const data =
|
|
4922
|
+
const content = fs8.readFileSync(filePath, "utf8");
|
|
4923
|
+
const data = yaml7.load(content);
|
|
5277
4924
|
if (!data?.flows) continue;
|
|
5278
4925
|
if (Array.isArray(data.flows)) {
|
|
5279
4926
|
for (const flowItem of data.flows) {
|
|
@@ -5286,7 +4933,7 @@ function generateFlowIndex(rootDir, purposeFiles) {
|
|
|
5286
4933
|
id: flowId,
|
|
5287
4934
|
description: flow.description || "",
|
|
5288
4935
|
steps,
|
|
5289
|
-
definedIn:
|
|
4936
|
+
definedIn: path9.relative(rootDir, filePath)
|
|
5290
4937
|
};
|
|
5291
4938
|
indexFlowSymbols(flowId, steps, symbolToFlows);
|
|
5292
4939
|
}
|
|
@@ -5302,7 +4949,7 @@ function generateFlowIndex(rootDir, purposeFiles) {
|
|
|
5302
4949
|
trigger: flowDef.trigger,
|
|
5303
4950
|
steps,
|
|
5304
4951
|
validation: flowDef.validation,
|
|
5305
|
-
definedIn:
|
|
4952
|
+
definedIn: path9.relative(rootDir, filePath)
|
|
5306
4953
|
};
|
|
5307
4954
|
indexFlowSymbols(flowId, steps, symbolToFlows);
|
|
5308
4955
|
}
|
|
@@ -5392,12 +5039,6 @@ export {
|
|
|
5392
5039
|
incrementHeatmap,
|
|
5393
5040
|
getHeatmap,
|
|
5394
5041
|
checkDrift,
|
|
5395
|
-
loadLoreEntries,
|
|
5396
|
-
loadLoreEntry,
|
|
5397
|
-
loadLoreTimeline,
|
|
5398
|
-
recordLoreEntry,
|
|
5399
|
-
updateLoreEntry,
|
|
5400
|
-
deleteLoreEntry,
|
|
5401
5042
|
getLoreForAspect,
|
|
5402
5043
|
loadPersonas,
|
|
5403
5044
|
loadPersona,
|