@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
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
deleteLoreEntry,
|
|
4
4
|
loadLoreEntry
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-YHRRJM6J.js";
|
|
6
6
|
import "./chunk-ZXMDA7VB.js";
|
|
7
7
|
|
|
8
8
|
// src/commands/lore/delete.ts
|
|
@@ -21,8 +21,8 @@ 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
|
|
25
|
-
console.log(chalk.gray(` Symbols: ${entry.symbols_touched.join(", ")}`));
|
|
24
|
+
console.log(chalk.gray(` Type: ${entry.type} | Author: ${entry.author} | ${entry.timestamp}`));
|
|
25
|
+
console.log(chalk.gray(` Symbols: ${(entry.symbols_touched || []).join(", ")}`));
|
|
26
26
|
console.log(chalk.cyan(`
|
|
27
27
|
[dry-run] No changes made.
|
|
28
28
|
`));
|
|
@@ -32,8 +32,8 @@ 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
|
|
36
|
-
console.log(chalk.gray(` Symbols: ${entry.symbols_touched.join(", ")}`));
|
|
35
|
+
console.log(chalk.gray(` Type: ${entry.type} | Author: ${entry.author} | ${entry.timestamp}`));
|
|
36
|
+
console.log(chalk.gray(` Symbols: ${(entry.symbols_touched || []).join(", ")}`));
|
|
37
37
|
console.log(chalk.gray(`
|
|
38
38
|
Use --yes to confirm deletion.
|
|
39
39
|
`));
|
|
@@ -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
|
@@ -621,35 +621,35 @@ triageCmd.option("-l, --limit <number>", "Maximum incidents to show", "10").opti
|
|
|
621
621
|
});
|
|
622
622
|
var loreCmd = program.command("lore").description("Project lore - timeline of everything that happened to this project");
|
|
623
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-
|
|
624
|
+
const { loreListCommand } = await import("./list-RHYZPKG3.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-6CHTSR33.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", "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}')`).action(async (options) => {
|
|
632
|
+
const { loreRecordCommand } = await import("./record-PGVYYZFU.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-BRY5R45L.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-GJYLJYDU.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-2PX6DDAY.js");
|
|
645
645
|
await loreDeleteCommand(id, options);
|
|
646
646
|
});
|
|
647
647
|
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-
|
|
648
|
+
const { loreTimelineCommand } = await import("./timeline-HC527YXE.js");
|
|
649
649
|
await loreTimelineCommand(options);
|
|
650
650
|
});
|
|
651
651
|
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-
|
|
652
|
+
const { loreServeCommand } = await import("./serve-KBMKF4KG.js");
|
|
653
653
|
await loreServeCommand(void 0, options);
|
|
654
654
|
});
|
|
655
655
|
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-YHRRJM6J.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
|
}
|
|
@@ -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,16 +70,22 @@ 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, from, to, tags, hasReview, 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(
|
|
52
|
-
(e) => e.symbols_touched
|
|
88
|
+
(e) => e.symbols_touched?.includes(symbol) || e.symbols_created?.includes(symbol)
|
|
53
89
|
);
|
|
54
90
|
}
|
|
55
91
|
if (type) {
|
|
@@ -96,8 +132,10 @@ function createLoreRouter(projectDir) {
|
|
|
96
132
|
const entries = loadAllEntries(projectDir);
|
|
97
133
|
const symbolCounts = {};
|
|
98
134
|
for (const entry of entries) {
|
|
99
|
-
|
|
100
|
-
|
|
135
|
+
if (entry.symbols_touched) {
|
|
136
|
+
for (const sym of entry.symbols_touched) {
|
|
137
|
+
symbolCounts[sym] = (symbolCounts[sym] || 0) + 1;
|
|
138
|
+
}
|
|
101
139
|
}
|
|
102
140
|
if (entry.symbols_created) {
|
|
103
141
|
for (const sym of entry.symbols_created) {
|
|
@@ -112,11 +150,12 @@ function createLoreRouter(projectDir) {
|
|
|
112
150
|
const entries = loadAllEntries(projectDir);
|
|
113
151
|
const authorMap = {};
|
|
114
152
|
for (const entry of entries) {
|
|
115
|
-
const aid = entry.author
|
|
153
|
+
const aid = entry.author;
|
|
116
154
|
if (!authorMap[aid]) {
|
|
117
|
-
authorMap[aid] = {
|
|
155
|
+
authorMap[aid] = { hasAgent: entry.agent != null, count: 0, lastActive: entry.timestamp };
|
|
118
156
|
}
|
|
119
157
|
authorMap[aid].count++;
|
|
158
|
+
if (entry.agent != null) authorMap[aid].hasAgent = true;
|
|
120
159
|
if (entry.timestamp > authorMap[aid].lastActive) {
|
|
121
160
|
authorMap[aid].lastActive = entry.timestamp;
|
|
122
161
|
}
|
|
@@ -142,8 +181,8 @@ function createLoreRouter(projectDir) {
|
|
|
142
181
|
return;
|
|
143
182
|
}
|
|
144
183
|
const dateStr = entry.timestamp.slice(0, 10);
|
|
145
|
-
const entryPath =
|
|
146
|
-
if (!
|
|
184
|
+
const entryPath = resolveEntryPath(projectDir, dateStr, entryId);
|
|
185
|
+
if (!entryPath) {
|
|
147
186
|
res.status(404).json({ error: "Entry file not found" });
|
|
148
187
|
return;
|
|
149
188
|
}
|
|
@@ -195,6 +234,28 @@ import * as os from "os";
|
|
|
195
234
|
var LORE_DIR2 = ".paradigm/lore";
|
|
196
235
|
var ENTRIES_DIR2 = "entries";
|
|
197
236
|
var SESSION_GAP_MS = 4 * 60 * 60 * 1e3;
|
|
237
|
+
function isLoreFile2(filename) {
|
|
238
|
+
return filename.endsWith(".yaml") || filename.endsWith(".lore");
|
|
239
|
+
}
|
|
240
|
+
function normalizeEntry2(raw) {
|
|
241
|
+
const author = raw.author;
|
|
242
|
+
if (typeof author === "object" && author && !Array.isArray(author)) {
|
|
243
|
+
const old = author;
|
|
244
|
+
if (old.type === "agent") {
|
|
245
|
+
raw.author = "unknown";
|
|
246
|
+
const model = old.model || old.id || "unknown";
|
|
247
|
+
const lower = model.toLowerCase();
|
|
248
|
+
let provider = "unknown";
|
|
249
|
+
if (lower.includes("claude") || lower.includes("anthropic")) provider = "anthropic";
|
|
250
|
+
else if (lower.includes("gpt") || lower.includes("openai")) provider = "openai";
|
|
251
|
+
raw.agent = { provider, model };
|
|
252
|
+
} else {
|
|
253
|
+
raw.author = old.id || "unknown";
|
|
254
|
+
}
|
|
255
|
+
delete raw.assistedBy;
|
|
256
|
+
}
|
|
257
|
+
return raw;
|
|
258
|
+
}
|
|
198
259
|
function loadAllEntries2(projectDir) {
|
|
199
260
|
const entriesPath = path3.join(projectDir, LORE_DIR2, ENTRIES_DIR2);
|
|
200
261
|
if (!fs3.existsSync(entriesPath)) {
|
|
@@ -204,12 +265,12 @@ function loadAllEntries2(projectDir) {
|
|
|
204
265
|
const dateDirs = fs3.readdirSync(entriesPath).filter((d) => /^\d{4}-\d{2}-\d{2}$/.test(d)).sort().reverse();
|
|
205
266
|
for (const dateDir of dateDirs) {
|
|
206
267
|
const dirPath = path3.join(entriesPath, dateDir);
|
|
207
|
-
const files = fs3.readdirSync(dirPath).filter(
|
|
268
|
+
const files = fs3.readdirSync(dirPath).filter(isLoreFile2).sort();
|
|
208
269
|
for (const file of files) {
|
|
209
270
|
try {
|
|
210
271
|
const content = fs3.readFileSync(path3.join(dirPath, file), "utf8");
|
|
211
|
-
const
|
|
212
|
-
entries.push(
|
|
272
|
+
const raw = yaml3.load(content);
|
|
273
|
+
entries.push(normalizeEntry2(raw));
|
|
213
274
|
} catch {
|
|
214
275
|
}
|
|
215
276
|
}
|
|
@@ -250,7 +311,7 @@ function deriveSessionsFromEntries(entries, breadcrumbs) {
|
|
|
250
311
|
const prev = sorted[i - 1];
|
|
251
312
|
const curr = sorted[i];
|
|
252
313
|
const gap = new Date(curr.timestamp).getTime() - new Date(prev.timestamp).getTime();
|
|
253
|
-
const sameAuthor = curr.author
|
|
314
|
+
const sameAuthor = curr.author === prev.author;
|
|
254
315
|
if (gap <= SESSION_GAP_MS && sameAuthor) {
|
|
255
316
|
currentGroup.push(curr);
|
|
256
317
|
} else {
|
|
@@ -267,6 +328,7 @@ function deriveSessionsFromEntries(entries, breadcrumbs) {
|
|
|
267
328
|
}
|
|
268
329
|
function groupToSession(group) {
|
|
269
330
|
const allSymbols = /* @__PURE__ */ new Set();
|
|
331
|
+
let hasAgent = false;
|
|
270
332
|
for (const entry of group) {
|
|
271
333
|
if (entry.symbols_touched) {
|
|
272
334
|
for (const sym of entry.symbols_touched) allSymbols.add(sym);
|
|
@@ -274,14 +336,15 @@ function groupToSession(group) {
|
|
|
274
336
|
if (entry.symbols_created) {
|
|
275
337
|
for (const sym of entry.symbols_created) allSymbols.add(sym);
|
|
276
338
|
}
|
|
339
|
+
if (entry.agent) hasAgent = true;
|
|
277
340
|
}
|
|
278
341
|
const startTime = group[0].timestamp;
|
|
279
342
|
const endTime = group[group.length - 1].timestamp;
|
|
280
343
|
const date = startTime.slice(0, 10);
|
|
281
344
|
return {
|
|
282
|
-
id: `session-${date}-${group[0].author
|
|
345
|
+
id: `session-${date}-${group[0].author}-${group[0].id.slice(0, 8)}`,
|
|
283
346
|
date,
|
|
284
|
-
author: {
|
|
347
|
+
author: { name: group[0].author, hasAgent },
|
|
285
348
|
startTime,
|
|
286
349
|
endTime,
|
|
287
350
|
entryCount: group.length,
|
package/dist/mcp.js
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
StatsCalculator,
|
|
25
25
|
TimelineBuilder,
|
|
26
26
|
loadAllSeedPatterns
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-BKMNLROM.js";
|
|
28
28
|
import {
|
|
29
29
|
addStep,
|
|
30
30
|
addToolBreadcrumb,
|
|
@@ -92,7 +92,7 @@ import {
|
|
|
92
92
|
validatePersona,
|
|
93
93
|
validateProtocol,
|
|
94
94
|
validatePurposeFile
|
|
95
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-TUW27EIC.js";
|
|
96
96
|
import {
|
|
97
97
|
getPluginUpdateNotice,
|
|
98
98
|
schedulePluginUpdateCheck
|
|
@@ -2033,7 +2033,7 @@ function registerResources(server, getContext2) {
|
|
|
2033
2033
|
}
|
|
2034
2034
|
|
|
2035
2035
|
// ../paradigm-mcp/src/tools/index.ts
|
|
2036
|
-
import * as
|
|
2036
|
+
import * as os2 from "os";
|
|
2037
2037
|
import * as path24 from "path";
|
|
2038
2038
|
import {
|
|
2039
2039
|
ListToolsRequestSchema,
|
|
@@ -8215,6 +8215,26 @@ function runPostflightCheck(filesModified, symbolsTouched, ctx) {
|
|
|
8215
8215
|
}
|
|
8216
8216
|
|
|
8217
8217
|
// ../paradigm-mcp/src/tools/lore.ts
|
|
8218
|
+
import { execSync as execSync2 } from "child_process";
|
|
8219
|
+
import * as os from "os";
|
|
8220
|
+
function resolveAuthorForMcp() {
|
|
8221
|
+
const envAuthor = process.env.PARADIGM_AUTHOR;
|
|
8222
|
+
if (envAuthor) return sanitize(envAuthor);
|
|
8223
|
+
try {
|
|
8224
|
+
const gitName = execSync2("git config user.name", { encoding: "utf-8", timeout: 3e3 }).trim();
|
|
8225
|
+
if (gitName) return sanitize(gitName);
|
|
8226
|
+
} catch {
|
|
8227
|
+
}
|
|
8228
|
+
try {
|
|
8229
|
+
const username = os.userInfo().username;
|
|
8230
|
+
if (username) return sanitize(username);
|
|
8231
|
+
} catch {
|
|
8232
|
+
}
|
|
8233
|
+
return "unknown";
|
|
8234
|
+
}
|
|
8235
|
+
function sanitize(name) {
|
|
8236
|
+
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 20) || "unknown";
|
|
8237
|
+
}
|
|
8218
8238
|
function getLoreToolsList() {
|
|
8219
8239
|
return [
|
|
8220
8240
|
{
|
|
@@ -8229,12 +8249,16 @@ function getLoreToolsList() {
|
|
|
8229
8249
|
},
|
|
8230
8250
|
author: {
|
|
8231
8251
|
type: "string",
|
|
8232
|
-
description: 'Filter by author
|
|
8252
|
+
description: 'Filter by author (human user name, e.g., "ascend")'
|
|
8253
|
+
},
|
|
8254
|
+
hasAgent: {
|
|
8255
|
+
type: "boolean",
|
|
8256
|
+
description: "Filter by AI assistance: true = AI-assisted entries, false = human-only"
|
|
8233
8257
|
},
|
|
8234
8258
|
authorType: {
|
|
8235
8259
|
type: "string",
|
|
8236
8260
|
enum: ["human", "agent"],
|
|
8237
|
-
description: "Filter by author type"
|
|
8261
|
+
description: "(Deprecated, use hasAgent) Filter by old author type"
|
|
8238
8262
|
},
|
|
8239
8263
|
type: {
|
|
8240
8264
|
type: "string",
|
|
@@ -8363,6 +8387,10 @@ function getLoreToolsList() {
|
|
|
8363
8387
|
type: "array",
|
|
8364
8388
|
items: { type: "string" },
|
|
8365
8389
|
description: "Tags for categorization"
|
|
8390
|
+
},
|
|
8391
|
+
meta: {
|
|
8392
|
+
type: "object",
|
|
8393
|
+
description: 'Project-defined metadata (open-ended key-value pairs, e.g., { meeting_type: "design-review", sprint: 12 })'
|
|
8366
8394
|
}
|
|
8367
8395
|
},
|
|
8368
8396
|
required: ["type", "title", "summary", "symbols_touched"]
|
|
@@ -8397,7 +8425,7 @@ function getLoreToolsList() {
|
|
|
8397
8425
|
properties: {
|
|
8398
8426
|
id: {
|
|
8399
8427
|
type: "string",
|
|
8400
|
-
description: 'Lore entry ID (e.g., "L-2026-02-23-001")'
|
|
8428
|
+
description: 'Lore entry ID (e.g., "L-2026-02-23-001" or "L-2026-03-02-ascend-143025-001")'
|
|
8401
8429
|
}
|
|
8402
8430
|
},
|
|
8403
8431
|
required: ["id"]
|
|
@@ -8499,6 +8527,7 @@ async function handleLoreTool(name, args, ctx) {
|
|
|
8499
8527
|
case "paradigm_lore_search": {
|
|
8500
8528
|
const filter = {
|
|
8501
8529
|
author: args.author,
|
|
8530
|
+
hasAgent: args.hasAgent,
|
|
8502
8531
|
authorType: args.authorType,
|
|
8503
8532
|
symbol: args.symbol,
|
|
8504
8533
|
dateFrom: args.dateFrom,
|
|
@@ -8538,7 +8567,8 @@ async function handleLoreTool(name, args, ctx) {
|
|
|
8538
8567
|
errors_encountered,
|
|
8539
8568
|
learnings,
|
|
8540
8569
|
verification,
|
|
8541
|
-
tags
|
|
8570
|
+
tags,
|
|
8571
|
+
meta
|
|
8542
8572
|
} = args;
|
|
8543
8573
|
let habit_compliance;
|
|
8544
8574
|
try {
|
|
@@ -8563,7 +8593,8 @@ async function handleLoreTool(name, args, ctx) {
|
|
|
8563
8593
|
type,
|
|
8564
8594
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8565
8595
|
duration_minutes,
|
|
8566
|
-
author:
|
|
8596
|
+
author: resolveAuthorForMcp(),
|
|
8597
|
+
agent: { provider: "anthropic", model: "claude-opus-4-6" },
|
|
8567
8598
|
title,
|
|
8568
8599
|
summary,
|
|
8569
8600
|
symbols_touched,
|
|
@@ -8578,6 +8609,7 @@ async function handleLoreTool(name, args, ctx) {
|
|
|
8578
8609
|
learnings,
|
|
8579
8610
|
verification,
|
|
8580
8611
|
tags,
|
|
8612
|
+
meta: meta || void 0,
|
|
8581
8613
|
habit_compliance
|
|
8582
8614
|
};
|
|
8583
8615
|
const id = await recordLoreEntry(ctx.rootDir, entry);
|
|
@@ -8618,11 +8650,12 @@ async function handleLoreTool(name, args, ctx) {
|
|
|
8618
8650
|
const hotSymbols = Object.entries(symbolCounts).sort(([, a], [, b]) => b - a).slice(0, 10).map(([symbol, count]) => ({ symbol, count }));
|
|
8619
8651
|
const authorActivity = {};
|
|
8620
8652
|
for (const entry of entries) {
|
|
8621
|
-
const aid = entry.author
|
|
8653
|
+
const aid = entry.author;
|
|
8622
8654
|
if (!authorActivity[aid]) {
|
|
8623
|
-
authorActivity[aid] = { count: 0, lastActive: entry.timestamp,
|
|
8655
|
+
authorActivity[aid] = { count: 0, lastActive: entry.timestamp, hasAgent: entry.agent != null };
|
|
8624
8656
|
}
|
|
8625
8657
|
authorActivity[aid].count++;
|
|
8658
|
+
if (entry.agent) authorActivity[aid].hasAgent = true;
|
|
8626
8659
|
if (entry.timestamp > authorActivity[aid].lastActive) {
|
|
8627
8660
|
authorActivity[aid].lastActive = entry.timestamp;
|
|
8628
8661
|
}
|
|
@@ -8635,7 +8668,7 @@ async function handleLoreTool(name, args, ctx) {
|
|
|
8635
8668
|
hotSymbols,
|
|
8636
8669
|
authors: Object.entries(authorActivity).map(([id, info]) => ({
|
|
8637
8670
|
id,
|
|
8638
|
-
|
|
8671
|
+
hasAgent: info.hasAgent,
|
|
8639
8672
|
entries: info.count,
|
|
8640
8673
|
lastActive: info.lastActive
|
|
8641
8674
|
}))
|
|
@@ -8708,6 +8741,7 @@ function summarizeEntry(entry) {
|
|
|
8708
8741
|
title: entry.title,
|
|
8709
8742
|
summary: entry.summary,
|
|
8710
8743
|
author: entry.author,
|
|
8744
|
+
agent: entry.agent,
|
|
8711
8745
|
timestamp: entry.timestamp,
|
|
8712
8746
|
duration_minutes: entry.duration_minutes,
|
|
8713
8747
|
symbols_touched: entry.symbols_touched,
|
|
@@ -8723,7 +8757,7 @@ function summarizeEntry(entry) {
|
|
|
8723
8757
|
// ../paradigm-mcp/src/tools/habits.ts
|
|
8724
8758
|
import * as fs19 from "fs";
|
|
8725
8759
|
import * as path21 from "path";
|
|
8726
|
-
import { execSync as
|
|
8760
|
+
import { execSync as execSync3 } from "child_process";
|
|
8727
8761
|
function getHabitsToolsList() {
|
|
8728
8762
|
return [
|
|
8729
8763
|
{
|
|
@@ -8927,7 +8961,7 @@ async function handleHabitsCheck(args, ctx) {
|
|
|
8927
8961
|
].some((k) => taskLower.includes(k));
|
|
8928
8962
|
let gitClean;
|
|
8929
8963
|
try {
|
|
8930
|
-
const status =
|
|
8964
|
+
const status = execSync3("git status --porcelain", {
|
|
8931
8965
|
cwd: ctx.rootDir,
|
|
8932
8966
|
encoding: "utf8",
|
|
8933
8967
|
timeout: 5e3
|
|
@@ -10980,7 +11014,7 @@ var PERSONA_SCHEMA = {
|
|
|
10980
11014
|
var sentinelSchemaRegistered = false;
|
|
10981
11015
|
async function emitPersonaEvents(result) {
|
|
10982
11016
|
try {
|
|
10983
|
-
const { SentinelStorage: SentinelStorage2 } = await import("./dist-
|
|
11017
|
+
const { SentinelStorage: SentinelStorage2 } = await import("./dist-IKBGY7FQ.js");
|
|
10984
11018
|
const storage2 = new SentinelStorage2();
|
|
10985
11019
|
if (!sentinelSchemaRegistered) {
|
|
10986
11020
|
try {
|
|
@@ -11933,7 +11967,7 @@ function summarizeStep(step) {
|
|
|
11933
11967
|
|
|
11934
11968
|
// ../paradigm-mcp/src/tools/fallback-grep.ts
|
|
11935
11969
|
import * as path23 from "path";
|
|
11936
|
-
import { execSync as
|
|
11970
|
+
import { execSync as execSync4 } from "child_process";
|
|
11937
11971
|
function grepForReferences(rootDir, symbol, options = {}) {
|
|
11938
11972
|
const { maxResults = 20 } = options;
|
|
11939
11973
|
const results = [];
|
|
@@ -11947,7 +11981,7 @@ function grepForReferences(rootDir, symbol, options = {}) {
|
|
|
11947
11981
|
let output = "";
|
|
11948
11982
|
for (const cmd of grepCommands) {
|
|
11949
11983
|
try {
|
|
11950
|
-
output =
|
|
11984
|
+
output = execSync4(cmd, { encoding: "utf8", maxBuffer: 1024 * 1024 });
|
|
11951
11985
|
if (output.trim()) break;
|
|
11952
11986
|
} catch {
|
|
11953
11987
|
continue;
|
|
@@ -12614,7 +12648,7 @@ function registerTools(server, getContext2, reloadContext2) {
|
|
|
12614
12648
|
const symbols = getSymbolsByType(ctx.index, type);
|
|
12615
12649
|
examples[type] = symbols.slice(0, 3).map((s) => s.symbol);
|
|
12616
12650
|
}
|
|
12617
|
-
const platform2 =
|
|
12651
|
+
const platform2 = os2.platform();
|
|
12618
12652
|
const isWindows = platform2 === "win32";
|
|
12619
12653
|
const shell = isWindows ? "PowerShell/CMD" : platform2 === "darwin" ? "zsh/bash" : "bash";
|
|
12620
12654
|
let protocols;
|
|
@@ -12854,7 +12888,7 @@ Update command:
|
|
|
12854
12888
|
trackToolCall(noWsText.length, name);
|
|
12855
12889
|
return { content: [{ type: "text", text: noWsText }] };
|
|
12856
12890
|
}
|
|
12857
|
-
const { rebuildStaticFiles: rebuildStaticFiles2 } = await import("./reindex-
|
|
12891
|
+
const { rebuildStaticFiles: rebuildStaticFiles2 } = await import("./reindex-UAYAEF7M.js");
|
|
12858
12892
|
const memberResults = [];
|
|
12859
12893
|
for (const member of ctx.workspace.config.members) {
|
|
12860
12894
|
const memberAbsPath = path24.resolve(path24.dirname(ctx.workspace.workspacePath), member.path);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
recordLore
|
|
4
|
-
|
|
3
|
+
recordLore,
|
|
4
|
+
resolveAuthor
|
|
5
|
+
} from "./chunk-YHRRJM6J.js";
|
|
5
6
|
import "./chunk-ZXMDA7VB.js";
|
|
6
7
|
|
|
7
8
|
// src/commands/lore/record.ts
|
|
@@ -14,10 +15,7 @@ async function loreRecordCommand(options) {
|
|
|
14
15
|
type: options.type || "human-note",
|
|
15
16
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16
17
|
duration_minutes: options.duration ? parseInt(options.duration, 10) : void 0,
|
|
17
|
-
author:
|
|
18
|
-
type: "human",
|
|
19
|
-
id: options.author || "unknown"
|
|
20
|
-
},
|
|
18
|
+
author: options.author || resolveAuthor(),
|
|
21
19
|
title: options.title || "Untitled",
|
|
22
20
|
summary: options.summary || "",
|
|
23
21
|
symbols_touched: options.symbols ? options.symbols.split(",").map((s) => s.trim()) : [],
|
|
@@ -25,7 +23,9 @@ async function loreRecordCommand(options) {
|
|
|
25
23
|
files_created: options.filesCreated ? options.filesCreated.split(",").map((f) => f.trim()) : void 0,
|
|
26
24
|
commit: options.commit || void 0,
|
|
27
25
|
learnings: options.learnings ? options.learnings.split(",").map((l) => l.trim()) : void 0,
|
|
28
|
-
tags: options.tags ? options.tags.split(",").map((t) => t.trim()) : void 0
|
|
26
|
+
tags: options.tags ? options.tags.split(",").map((t) => t.trim()) : void 0,
|
|
27
|
+
meta: options.meta ? JSON.parse(options.meta) : void 0
|
|
28
|
+
// git_context is auto-captured by recordLore
|
|
29
29
|
};
|
|
30
30
|
await recordLore(rootDir, entry);
|
|
31
31
|
console.log(chalk.green(`
|
|
@@ -9,7 +9,7 @@ async function loreServeCommand(path, options) {
|
|
|
9
9
|
const shouldOpen = options.open !== false;
|
|
10
10
|
console.log(chalk.cyan("\nStarting Lore Timeline...\n"));
|
|
11
11
|
try {
|
|
12
|
-
const { startLoreServer } = await import("./lore-server-
|
|
12
|
+
const { startLoreServer } = await import("./lore-server-XEW7EG62.js");
|
|
13
13
|
console.log(chalk.gray(`Project: ${projectDir}`));
|
|
14
14
|
console.log(chalk.gray(`Port: ${port}`));
|
|
15
15
|
console.log();
|