@a-company/paradigm 3.17.2 → 3.19.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-3DYYXGDC.js +403 -0
- package/dist/{chunk-ZRPEI35Q.js → chunk-BKMNLROM.js} +533 -5
- package/dist/{chunk-IWDLTLZH.js → chunk-BRILIG7Z.js} +155 -32
- package/dist/{chunk-D4VBBKGV.js → chunk-EZ6XW6FB.js} +150 -409
- package/dist/{delete-KBKPTIMU.js → delete-YTASL4SM.js} +3 -3
- package/dist/{dist-YHDSIZQD.js → dist-IKBGY7FQ.js} +3 -1
- package/dist/{edit-Y6SKWVHI.js → edit-S7NZD7H7.js} +1 -1
- package/dist/index.js +18 -10
- package/dist/{list-SLAH7X7N.js → list-CAL7KS7B.js} +3 -3
- package/dist/lore-loader-S5BXMH27.js +21 -0
- package/dist/{lore-server-WFU4H5DI.js → lore-server-2NYDLGCJ.js} +102 -17
- package/dist/mcp.js +503 -147
- package/dist/migrate-assessments-FPR6C35Z.js +97 -0
- package/dist/{record-PLZ2OQAN.js → record-UGN75GTB.js} +10 -7
- package/dist/{reindex-T4N3NG73.js → reindex-CMZARW5K.js} +2 -1
- package/dist/retag-URLJLMSK.js +62 -0
- package/dist/{review-Z4Z37PD5.js → review-725ZKA7U.js} +1 -1
- package/dist/{serve-BU43NO7D.js → serve-GUJ3L3IG.js} +1 -1
- package/dist/{show-WGDIK56Q.js → show-GEVVQWWG.js} +54 -5
- package/dist/{timeline-X3CZM7MW.js → timeline-B6TMGWRU.js} +9 -8
- package/dist/university-content/courses/para-501.json +30 -30
- package/dist/university-content/plsat/v3.0.json +26 -26
- package/lore-ui/dist/assets/{index-CB4RregB.js → index-CDr7Tr1E.js} +10 -10
- package/lore-ui/dist/index.html +1 -1
- package/package.json +1 -1
- package/dist/assessment-loader-C5EOUM47.js +0 -23
- package/dist/chunk-DSXS42FY.js +0 -283
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
deleteLoreEntry,
|
|
4
4
|
loadLoreEntry
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BRILIG7Z.js";
|
|
6
6
|
import "./chunk-ZXMDA7VB.js";
|
|
7
7
|
|
|
8
8
|
// src/commands/lore/delete.ts
|
|
@@ -21,7 +21,7 @@ async function loreDeleteCommand(id, options) {
|
|
|
21
21
|
console.log(chalk.cyan(`
|
|
22
22
|
[dry-run] Would delete lore entry:`));
|
|
23
23
|
console.log(chalk.white(` ${entry.id} - ${entry.title}`));
|
|
24
|
-
console.log(chalk.gray(` Type: ${entry.type} | Author: ${entry.author
|
|
24
|
+
console.log(chalk.gray(` Type: ${entry.type} | Author: ${entry.author} | ${entry.timestamp}`));
|
|
25
25
|
console.log(chalk.gray(` Symbols: ${(entry.symbols_touched || []).join(", ")}`));
|
|
26
26
|
console.log(chalk.cyan(`
|
|
27
27
|
[dry-run] No changes made.
|
|
@@ -32,7 +32,7 @@ async function loreDeleteCommand(id, options) {
|
|
|
32
32
|
console.log(chalk.yellow(`
|
|
33
33
|
Will delete lore entry:`));
|
|
34
34
|
console.log(chalk.white(` ${entry.id} - ${entry.title}`));
|
|
35
|
-
console.log(chalk.gray(` Type: ${entry.type} | Author: ${entry.author
|
|
35
|
+
console.log(chalk.gray(` Type: ${entry.type} | Author: ${entry.author} | ${entry.timestamp}`));
|
|
36
36
|
console.log(chalk.gray(` Symbols: ${(entry.symbols_touched || []).join(", ")}`));
|
|
37
37
|
console.log(chalk.gray(`
|
|
38
38
|
Use --yes to confirm deletion.
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
DEFAULT_SERVER_CONFIG,
|
|
7
7
|
FlowTracker,
|
|
8
8
|
IncidentGrouper,
|
|
9
|
+
PARADIGM_SCHEMA,
|
|
9
10
|
PatternImporter,
|
|
10
11
|
PatternMatcher,
|
|
11
12
|
PatternSuggester,
|
|
@@ -26,7 +27,7 @@ import {
|
|
|
26
27
|
loadServerConfig,
|
|
27
28
|
loadUniversalPatterns,
|
|
28
29
|
writeConfig
|
|
29
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-BKMNLROM.js";
|
|
30
31
|
export {
|
|
31
32
|
ContextEnricher,
|
|
32
33
|
DEFAULT_AUTH_CONFIG,
|
|
@@ -34,6 +35,7 @@ export {
|
|
|
34
35
|
DEFAULT_SERVER_CONFIG,
|
|
35
36
|
FlowTracker,
|
|
36
37
|
IncidentGrouper,
|
|
38
|
+
PARADIGM_SCHEMA,
|
|
37
39
|
PatternImporter,
|
|
38
40
|
PatternMatcher,
|
|
39
41
|
PatternSuggester,
|
package/dist/index.js
CHANGED
|
@@ -620,36 +620,44 @@ triageCmd.option("-l, --limit <number>", "Maximum incidents to show", "10").opti
|
|
|
620
620
|
await triageListCommand(options);
|
|
621
621
|
});
|
|
622
622
|
var loreCmd = program.command("lore").description("Project lore - timeline of everything that happened to this project");
|
|
623
|
-
loreCmd.command("list").alias("ls").description("List recent lore entries").option("--author <author>", "Filter by author").option("--type <type>", "Filter by type: agent-session, human-note, decision, review, incident, milestone").option("--symbol <symbol>", "Filter by symbol").option("--tags <tags>", "Filter by tags (comma-separated)").option("--from <date>", "Filter from date (ISO format, e.g., 2026-02-20)").option("--to <date>", "Filter to date (ISO format)").option("-l, --limit <number>", "Number of entries", "20").option("--json", "Output as JSON").action(async (options) => {
|
|
624
|
-
const { loreListCommand } = await import("./list-
|
|
623
|
+
loreCmd.command("list").alias("ls").description("List recent lore entries").option("--author <author>", "Filter by author").option("--type <type>", "Filter by type: agent-session, human-note, decision, review, incident, milestone, retro, insight").option("--symbol <symbol>", "Filter by symbol").option("--tags <tags>", "Filter by tags (comma-separated)").option("--from <date>", "Filter from date (ISO format, e.g., 2026-02-20)").option("--to <date>", "Filter to date (ISO format)").option("-l, --limit <number>", "Number of entries", "20").option("--json", "Output as JSON").action(async (options) => {
|
|
624
|
+
const { loreListCommand } = await import("./list-CAL7KS7B.js");
|
|
625
625
|
await loreListCommand(options);
|
|
626
626
|
});
|
|
627
627
|
loreCmd.command("show <id>").description("Show full detail for a lore entry").option("--json", "Output as JSON").action(async (id, options) => {
|
|
628
|
-
const { loreShowCommand } = await import("./show-
|
|
628
|
+
const { loreShowCommand } = await import("./show-GEVVQWWG.js");
|
|
629
629
|
await loreShowCommand(id, options);
|
|
630
630
|
});
|
|
631
|
-
loreCmd.command("record").description("Record a new lore entry (human note, milestone, etc.)").option("--type <type>", "Entry type: human-note, decision, milestone", "human-note").option("--author <author>", "Author name").option("--title <title>", "Entry title").option("--summary <summary>", "Entry summary").option("--symbols <symbols>", "Comma-separated symbols").option("--tags <tags>", "Comma-separated tags").option("--files-modified <files>", "Comma-separated files modified").option("--files-created <files>", "Comma-separated files created").option("--commit <hash>", "Git commit hash").option("--learnings <items>", "Comma-separated learnings").option("--duration <minutes>", "Duration in minutes").action(async (options) => {
|
|
632
|
-
const { loreRecordCommand } = await import("./record-
|
|
631
|
+
loreCmd.command("record").description("Record a new lore entry (human note, milestone, etc.)").option("--type <type>", "Entry type: human-note, decision, milestone, retro, insight", "human-note").option("--author <author>", "Author name").option("--title <title>", "Entry title").option("--summary <summary>", "Entry summary").option("--symbols <symbols>", "Comma-separated symbols").option("--tags <tags>", "Comma-separated tags").option("--files-modified <files>", "Comma-separated files modified").option("--files-created <files>", "Comma-separated files created").option("--commit <hash>", "Git commit hash").option("--learnings <items>", "Comma-separated learnings").option("--duration <minutes>", "Duration in minutes").option("--meta <json>", `Project-defined metadata as JSON (e.g., '{"sprint": 12}')`).option("--body <text>", "Long-form content (detailed notes, rationale, etc.)").option("--link-lore <ids>", "Comma-separated lore entry IDs to link").option("--link-commits <shas>", "Comma-separated git commit SHAs to link").action(async (options) => {
|
|
632
|
+
const { loreRecordCommand } = await import("./record-UGN75GTB.js");
|
|
633
633
|
await loreRecordCommand(options);
|
|
634
634
|
});
|
|
635
635
|
loreCmd.command("review <id>").description("Add a review to a lore entry").option("--reviewer <name>", "Reviewer name").option("--completeness <n>", "Completeness score (1-5)", "3").option("--quality <n>", "Quality score (1-5)", "3").option("--notes <text>", "Review notes").action(async (id, options) => {
|
|
636
|
-
const { loreReviewCommand } = await import("./review-
|
|
636
|
+
const { loreReviewCommand } = await import("./review-725ZKA7U.js");
|
|
637
637
|
await loreReviewCommand(id, options);
|
|
638
638
|
});
|
|
639
639
|
loreCmd.command("edit <id>").description("Edit an existing lore entry").option("--title <title>", "New title").option("--summary <summary>", "New summary").option("--type <type>", "New type: agent-session, human-note, decision, review, incident, milestone").option("--symbols <symbols>", "Comma-separated symbols").option("--tags <tags>", "Comma-separated tags").option("--learnings <items>", "Comma-separated learnings").action(async (id, options) => {
|
|
640
|
-
const { loreEditCommand } = await import("./edit-
|
|
640
|
+
const { loreEditCommand } = await import("./edit-S7NZD7H7.js");
|
|
641
641
|
await loreEditCommand(id, options);
|
|
642
642
|
});
|
|
643
643
|
loreCmd.command("delete <id>").description("Delete a lore entry").option("-y, --yes", "Skip confirmation").option("--dry-run", "Show what would be deleted without making changes").action(async (id, options) => {
|
|
644
|
-
const { loreDeleteCommand } = await import("./delete-
|
|
644
|
+
const { loreDeleteCommand } = await import("./delete-YTASL4SM.js");
|
|
645
645
|
await loreDeleteCommand(id, options);
|
|
646
646
|
});
|
|
647
|
+
loreCmd.command("migrate-assessments").description("Migrate assessment entries to lore with arc: tags").option("--dry-run", "Show what would be migrated without making changes").action(async (options) => {
|
|
648
|
+
const { loreMigrateAssessmentsCommand } = await import("./migrate-assessments-FPR6C35Z.js");
|
|
649
|
+
await loreMigrateAssessmentsCommand(options);
|
|
650
|
+
});
|
|
651
|
+
loreCmd.command("retag").description("Add or remove tags from matching lore entries").option("--add <tag>", "Tag to add").option("--remove <tag>", "Tag to remove").option("--type <type>", "Filter by entry type").option("--symbol <symbol>", "Filter by symbol").option("--author <author>", "Filter by author").option("--from <date>", "Filter from date").option("--to <date>", "Filter to date").option("--tags <tags>", "Filter by existing tags (comma-separated)").option("--dry-run", "Show what would change without making changes").action(async (options) => {
|
|
652
|
+
const { loreRetagCommand } = await import("./retag-URLJLMSK.js");
|
|
653
|
+
await loreRetagCommand(options);
|
|
654
|
+
});
|
|
647
655
|
loreCmd.command("timeline").description("Show lore timeline grouped by date with hot symbols and authors").option("-l, --limit <number>", "Number of entries", "20").option("--json", "Output as JSON").action(async (options) => {
|
|
648
|
-
const { loreTimelineCommand } = await import("./timeline-
|
|
656
|
+
const { loreTimelineCommand } = await import("./timeline-B6TMGWRU.js");
|
|
649
657
|
await loreTimelineCommand(options);
|
|
650
658
|
});
|
|
651
659
|
loreCmd.option("-p, --port <port>", "Port to run on", "3840").option("--no-open", "Don't open browser automatically").action(async (options) => {
|
|
652
|
-
const { loreServeCommand } = await import("./serve-
|
|
660
|
+
const { loreServeCommand } = await import("./serve-GUJ3L3IG.js");
|
|
653
661
|
await loreServeCommand(void 0, options);
|
|
654
662
|
});
|
|
655
663
|
var habitsCmd = program.command("habits").description("Behavioral habits - practice tracking and compliance");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadLoreEntries
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BRILIG7Z.js";
|
|
5
5
|
import "./chunk-ZXMDA7VB.js";
|
|
6
6
|
|
|
7
7
|
// src/commands/lore/list.ts
|
|
@@ -42,11 +42,11 @@ async function loreListCommand(options) {
|
|
|
42
42
|
const date = new Date(entry.timestamp);
|
|
43
43
|
const dateStr = date.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
44
44
|
const timeStr = date.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" });
|
|
45
|
-
const authorIcon = entry.
|
|
45
|
+
const authorIcon = entry.agent ? "\u{1F916}" : "\u{1F464}";
|
|
46
46
|
const verifyIcon = entry.verification?.status === "pass" ? chalk.green("\u2713") : entry.verification?.status === "fail" ? chalk.red("\u2717") : entry.verification?.status === "partial" ? chalk.yellow("\u26A0") : chalk.gray("\xB7");
|
|
47
47
|
const reviewStr = entry.review ? chalk.yellow("\u2605".repeat(entry.review.quality) + "\u2606".repeat(5 - entry.review.quality)) : "";
|
|
48
48
|
console.log(` ${chalk.gray(entry.id)} ${colorFn(entry.type.padEnd(14))} ${verifyIcon} ${chalk.white(entry.title)}`);
|
|
49
|
-
console.log(` ${chalk.gray(dateStr + " " + timeStr)} ${authorIcon} ${chalk.gray(entry.author
|
|
49
|
+
console.log(` ${chalk.gray(dateStr + " " + timeStr)} ${authorIcon} ${chalk.gray(entry.author)} ${(entry.symbols_touched || []).map((s) => chalk.cyan(s)).join(" ")} ${reviewStr}`);
|
|
50
50
|
console.log();
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
addLoreReview,
|
|
4
|
+
deleteLoreEntry,
|
|
5
|
+
loadLoreEntries,
|
|
6
|
+
loadLoreEntry,
|
|
7
|
+
loadLoreTimeline,
|
|
8
|
+
rebuildTimeline,
|
|
9
|
+
recordLoreEntry,
|
|
10
|
+
updateLoreEntry
|
|
11
|
+
} from "./chunk-3DYYXGDC.js";
|
|
12
|
+
export {
|
|
13
|
+
addLoreReview,
|
|
14
|
+
deleteLoreEntry,
|
|
15
|
+
loadLoreEntries,
|
|
16
|
+
loadLoreEntry,
|
|
17
|
+
loadLoreTimeline,
|
|
18
|
+
rebuildTimeline,
|
|
19
|
+
recordLoreEntry,
|
|
20
|
+
updateLoreEntry
|
|
21
|
+
};
|
|
@@ -15,6 +15,36 @@ import * as path from "path";
|
|
|
15
15
|
import * as yaml from "js-yaml";
|
|
16
16
|
var LORE_DIR = ".paradigm/lore";
|
|
17
17
|
var ENTRIES_DIR = "entries";
|
|
18
|
+
function isLoreFile(filename) {
|
|
19
|
+
return filename.endsWith(".yaml") || filename.endsWith(".lore");
|
|
20
|
+
}
|
|
21
|
+
function normalizeEntry(raw) {
|
|
22
|
+
const author = raw.author;
|
|
23
|
+
if (typeof author === "object" && author && !Array.isArray(author)) {
|
|
24
|
+
const old = author;
|
|
25
|
+
if (old.type === "agent") {
|
|
26
|
+
raw.author = "unknown";
|
|
27
|
+
const model = old.model || old.id || "unknown";
|
|
28
|
+
const lower = model.toLowerCase();
|
|
29
|
+
let provider = "unknown";
|
|
30
|
+
if (lower.includes("claude") || lower.includes("anthropic")) provider = "anthropic";
|
|
31
|
+
else if (lower.includes("gpt") || lower.includes("openai")) provider = "openai";
|
|
32
|
+
raw.agent = { provider, model };
|
|
33
|
+
} else {
|
|
34
|
+
raw.author = old.id || "unknown";
|
|
35
|
+
}
|
|
36
|
+
delete raw.assistedBy;
|
|
37
|
+
}
|
|
38
|
+
return raw;
|
|
39
|
+
}
|
|
40
|
+
function resolveEntryPath(projectDir, dateStr, entryId) {
|
|
41
|
+
const dirPath = path.join(projectDir, LORE_DIR, ENTRIES_DIR, dateStr);
|
|
42
|
+
const lorePath = path.join(dirPath, `${entryId}.lore`);
|
|
43
|
+
if (fs.existsSync(lorePath)) return lorePath;
|
|
44
|
+
const yamlPath = path.join(dirPath, `${entryId}.yaml`);
|
|
45
|
+
if (fs.existsSync(yamlPath)) return yamlPath;
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
18
48
|
function loadAllEntries(projectDir) {
|
|
19
49
|
const entriesPath = path.join(projectDir, LORE_DIR, ENTRIES_DIR);
|
|
20
50
|
if (!fs.existsSync(entriesPath)) {
|
|
@@ -24,12 +54,12 @@ function loadAllEntries(projectDir) {
|
|
|
24
54
|
const dateDirs = fs.readdirSync(entriesPath).filter((d) => /^\d{4}-\d{2}-\d{2}$/.test(d)).sort().reverse();
|
|
25
55
|
for (const dateDir of dateDirs) {
|
|
26
56
|
const dirPath = path.join(entriesPath, dateDir);
|
|
27
|
-
const files = fs.readdirSync(dirPath).filter(
|
|
57
|
+
const files = fs.readdirSync(dirPath).filter(isLoreFile).sort();
|
|
28
58
|
for (const file of files) {
|
|
29
59
|
try {
|
|
30
60
|
const content = fs.readFileSync(path.join(dirPath, file), "utf8");
|
|
31
|
-
const
|
|
32
|
-
entries.push(
|
|
61
|
+
const raw = yaml.load(content);
|
|
62
|
+
entries.push(normalizeEntry(raw));
|
|
33
63
|
} catch {
|
|
34
64
|
}
|
|
35
65
|
}
|
|
@@ -40,12 +70,18 @@ function createLoreRouter(projectDir) {
|
|
|
40
70
|
const router = Router();
|
|
41
71
|
router.get("/", (req, res) => {
|
|
42
72
|
let entries = loadAllEntries(projectDir);
|
|
43
|
-
const { author, authorType, symbol, type, from, to, tags, hasReview, limit, offset } = req.query;
|
|
73
|
+
const { author, authorType, hasAgent, symbol, type, tag, from, to, tags, hasReview, hasBody, limit, offset } = req.query;
|
|
44
74
|
if (author) {
|
|
45
|
-
entries = entries.filter((e) => e.author
|
|
75
|
+
entries = entries.filter((e) => e.author === author);
|
|
46
76
|
}
|
|
47
|
-
if (
|
|
48
|
-
entries = entries.filter(
|
|
77
|
+
if (hasAgent !== void 0) {
|
|
78
|
+
entries = entries.filter(
|
|
79
|
+
(e) => hasAgent === "true" ? e.agent != null : e.agent == null
|
|
80
|
+
);
|
|
81
|
+
} else if (authorType) {
|
|
82
|
+
entries = entries.filter(
|
|
83
|
+
(e) => authorType === "agent" ? e.agent != null : e.agent == null
|
|
84
|
+
);
|
|
49
85
|
}
|
|
50
86
|
if (symbol) {
|
|
51
87
|
entries = entries.filter(
|
|
@@ -55,6 +91,17 @@ function createLoreRouter(projectDir) {
|
|
|
55
91
|
if (type) {
|
|
56
92
|
entries = entries.filter((e) => e.type === type);
|
|
57
93
|
}
|
|
94
|
+
if (tag) {
|
|
95
|
+
const prefix = tag;
|
|
96
|
+
entries = entries.filter(
|
|
97
|
+
(e) => e.tags?.some((t) => t === prefix || t.startsWith(prefix + ":") || prefix.includes(":") && t === prefix)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
if (hasBody === "true") {
|
|
101
|
+
entries = entries.filter((e) => e.body != null && e.body.length > 0);
|
|
102
|
+
} else if (hasBody === "false") {
|
|
103
|
+
entries = entries.filter((e) => !e.body || e.body.length === 0);
|
|
104
|
+
}
|
|
58
105
|
if (from) {
|
|
59
106
|
const fromDate = new Date(from).getTime();
|
|
60
107
|
entries = entries.filter((e) => new Date(e.timestamp).getTime() >= fromDate);
|
|
@@ -110,15 +157,29 @@ function createLoreRouter(projectDir) {
|
|
|
110
157
|
const symbols = Object.entries(symbolCounts).map(([symbol, count]) => ({ symbol, count })).sort((a, b) => b.count - a.count);
|
|
111
158
|
res.json({ symbols });
|
|
112
159
|
});
|
|
160
|
+
router.get("/tags", (_req, res) => {
|
|
161
|
+
const entries = loadAllEntries(projectDir);
|
|
162
|
+
const tagCounts = {};
|
|
163
|
+
for (const entry of entries) {
|
|
164
|
+
if (entry.tags) {
|
|
165
|
+
for (const tag of entry.tags) {
|
|
166
|
+
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const tags = Object.entries(tagCounts).map(([tag, count]) => ({ tag, count })).sort((a, b) => b.count - a.count);
|
|
171
|
+
res.json({ tags });
|
|
172
|
+
});
|
|
113
173
|
router.get("/authors", (_req, res) => {
|
|
114
174
|
const entries = loadAllEntries(projectDir);
|
|
115
175
|
const authorMap = {};
|
|
116
176
|
for (const entry of entries) {
|
|
117
|
-
const aid = entry.author
|
|
177
|
+
const aid = entry.author;
|
|
118
178
|
if (!authorMap[aid]) {
|
|
119
|
-
authorMap[aid] = {
|
|
179
|
+
authorMap[aid] = { hasAgent: entry.agent != null, count: 0, lastActive: entry.timestamp };
|
|
120
180
|
}
|
|
121
181
|
authorMap[aid].count++;
|
|
182
|
+
if (entry.agent != null) authorMap[aid].hasAgent = true;
|
|
122
183
|
if (entry.timestamp > authorMap[aid].lastActive) {
|
|
123
184
|
authorMap[aid].lastActive = entry.timestamp;
|
|
124
185
|
}
|
|
@@ -144,8 +205,8 @@ function createLoreRouter(projectDir) {
|
|
|
144
205
|
return;
|
|
145
206
|
}
|
|
146
207
|
const dateStr = entry.timestamp.slice(0, 10);
|
|
147
|
-
const entryPath =
|
|
148
|
-
if (!
|
|
208
|
+
const entryPath = resolveEntryPath(projectDir, dateStr, entryId);
|
|
209
|
+
if (!entryPath) {
|
|
149
210
|
res.status(404).json({ error: "Entry file not found" });
|
|
150
211
|
return;
|
|
151
212
|
}
|
|
@@ -197,6 +258,28 @@ import * as os from "os";
|
|
|
197
258
|
var LORE_DIR2 = ".paradigm/lore";
|
|
198
259
|
var ENTRIES_DIR2 = "entries";
|
|
199
260
|
var SESSION_GAP_MS = 4 * 60 * 60 * 1e3;
|
|
261
|
+
function isLoreFile2(filename) {
|
|
262
|
+
return filename.endsWith(".yaml") || filename.endsWith(".lore");
|
|
263
|
+
}
|
|
264
|
+
function normalizeEntry2(raw) {
|
|
265
|
+
const author = raw.author;
|
|
266
|
+
if (typeof author === "object" && author && !Array.isArray(author)) {
|
|
267
|
+
const old = author;
|
|
268
|
+
if (old.type === "agent") {
|
|
269
|
+
raw.author = "unknown";
|
|
270
|
+
const model = old.model || old.id || "unknown";
|
|
271
|
+
const lower = model.toLowerCase();
|
|
272
|
+
let provider = "unknown";
|
|
273
|
+
if (lower.includes("claude") || lower.includes("anthropic")) provider = "anthropic";
|
|
274
|
+
else if (lower.includes("gpt") || lower.includes("openai")) provider = "openai";
|
|
275
|
+
raw.agent = { provider, model };
|
|
276
|
+
} else {
|
|
277
|
+
raw.author = old.id || "unknown";
|
|
278
|
+
}
|
|
279
|
+
delete raw.assistedBy;
|
|
280
|
+
}
|
|
281
|
+
return raw;
|
|
282
|
+
}
|
|
200
283
|
function loadAllEntries2(projectDir) {
|
|
201
284
|
const entriesPath = path3.join(projectDir, LORE_DIR2, ENTRIES_DIR2);
|
|
202
285
|
if (!fs3.existsSync(entriesPath)) {
|
|
@@ -206,12 +289,12 @@ function loadAllEntries2(projectDir) {
|
|
|
206
289
|
const dateDirs = fs3.readdirSync(entriesPath).filter((d) => /^\d{4}-\d{2}-\d{2}$/.test(d)).sort().reverse();
|
|
207
290
|
for (const dateDir of dateDirs) {
|
|
208
291
|
const dirPath = path3.join(entriesPath, dateDir);
|
|
209
|
-
const files = fs3.readdirSync(dirPath).filter(
|
|
292
|
+
const files = fs3.readdirSync(dirPath).filter(isLoreFile2).sort();
|
|
210
293
|
for (const file of files) {
|
|
211
294
|
try {
|
|
212
295
|
const content = fs3.readFileSync(path3.join(dirPath, file), "utf8");
|
|
213
|
-
const
|
|
214
|
-
entries.push(
|
|
296
|
+
const raw = yaml3.load(content);
|
|
297
|
+
entries.push(normalizeEntry2(raw));
|
|
215
298
|
} catch {
|
|
216
299
|
}
|
|
217
300
|
}
|
|
@@ -252,7 +335,7 @@ function deriveSessionsFromEntries(entries, breadcrumbs) {
|
|
|
252
335
|
const prev = sorted[i - 1];
|
|
253
336
|
const curr = sorted[i];
|
|
254
337
|
const gap = new Date(curr.timestamp).getTime() - new Date(prev.timestamp).getTime();
|
|
255
|
-
const sameAuthor = curr.author
|
|
338
|
+
const sameAuthor = curr.author === prev.author;
|
|
256
339
|
if (gap <= SESSION_GAP_MS && sameAuthor) {
|
|
257
340
|
currentGroup.push(curr);
|
|
258
341
|
} else {
|
|
@@ -269,6 +352,7 @@ function deriveSessionsFromEntries(entries, breadcrumbs) {
|
|
|
269
352
|
}
|
|
270
353
|
function groupToSession(group) {
|
|
271
354
|
const allSymbols = /* @__PURE__ */ new Set();
|
|
355
|
+
let hasAgent = false;
|
|
272
356
|
for (const entry of group) {
|
|
273
357
|
if (entry.symbols_touched) {
|
|
274
358
|
for (const sym of entry.symbols_touched) allSymbols.add(sym);
|
|
@@ -276,14 +360,15 @@ function groupToSession(group) {
|
|
|
276
360
|
if (entry.symbols_created) {
|
|
277
361
|
for (const sym of entry.symbols_created) allSymbols.add(sym);
|
|
278
362
|
}
|
|
363
|
+
if (entry.agent) hasAgent = true;
|
|
279
364
|
}
|
|
280
365
|
const startTime = group[0].timestamp;
|
|
281
366
|
const endTime = group[group.length - 1].timestamp;
|
|
282
367
|
const date = startTime.slice(0, 10);
|
|
283
368
|
return {
|
|
284
|
-
id: `session-${date}-${group[0].author
|
|
369
|
+
id: `session-${date}-${group[0].author}-${group[0].id.slice(0, 8)}`,
|
|
285
370
|
date,
|
|
286
|
-
author: {
|
|
371
|
+
author: { name: group[0].author, hasAgent },
|
|
287
372
|
startTime,
|
|
288
373
|
endTime,
|
|
289
374
|
entryCount: group.length,
|