@a-company/paradigm 3.1.0 → 3.1.4
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-LRSJNX7K.js → chunk-6HZ7PZGG.js} +118 -100
- package/dist/{chunk-X3ROB27T.js → chunk-MVXJVRFI.js} +44 -1
- package/dist/delete-W67IVTLJ.js +45 -0
- package/dist/edit-Y7XPYSMK.js +63 -0
- package/dist/habits-FA65W77Y.js +1153 -0
- package/dist/{hooks-ZVGXLK6Z.js → hooks-QGUF77MB.js} +1 -1
- package/dist/index.js +51 -19
- package/dist/{list-SDYF6T7M.js → list-R3QWW4SC.js} +3 -1
- package/dist/{lore-server-3TAIUZ3Y.js → lore-server-RQH5REZV.js} +166 -41
- package/dist/mcp.js +559 -127
- package/dist/{record-5IY5RWTI.js → record-OHQNWOUP.js} +7 -2
- package/dist/{review-CSA223ZJ.js → review-RUHX25A5.js} +1 -1
- package/dist/{serve-WCIRW244.js → serve-H7ZBMODT.js} +1 -1
- package/dist/{shift-DLV5YLFJ.js → shift-OCNF4575.js} +1 -1
- package/dist/{show-QRV7CWKT.js → show-WTOJXUTN.js} +1 -1
- package/dist/timeline-P7BARFLI.js +110 -0
- package/dist/university-content/courses/para-401.json +1 -1
- package/dist/university-content/courses/para-501.json +4 -4
- package/lore-ui/dist/assets/index-BB3P4Cok.js +56 -0
- package/lore-ui/dist/assets/index-DI0Q6NmX.css +1 -0
- package/lore-ui/dist/index.html +2 -2
- package/package.json +3 -2
- package/dist/habits-YVCOZ2LC.js +0 -485
- package/lore-ui/dist/assets/index-DcT8TINz.js +0 -56
- package/lore-ui/dist/assets/index-DyJhpQ5w.css +0 -1
|
@@ -4,100 +4,8 @@
|
|
|
4
4
|
import * as fs from "fs";
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import chalk from "chalk";
|
|
7
|
-
var POST_COMMIT_HOOK = `#!/bin/sh
|
|
8
|
-
# Paradigm post-commit hook - captures history from commits
|
|
9
|
-
# Installed by: paradigm hooks install
|
|
10
|
-
|
|
11
|
-
# Get the commit message and hash
|
|
12
|
-
COMMIT_HASH=$(git rev-parse HEAD)
|
|
13
|
-
COMMIT_MSG=$(git log -1 --pretty=%B)
|
|
14
|
-
|
|
15
|
-
# Get changed files
|
|
16
|
-
CHANGED_FILES=$(git diff-tree --no-commit-id --name-only -r HEAD)
|
|
17
|
-
|
|
18
|
-
# Extract symbols from changed files (look for .purpose files)
|
|
19
|
-
extract_symbols() {
|
|
20
|
-
local symbols=""
|
|
21
|
-
for file in $CHANGED_FILES; do
|
|
22
|
-
# Check if there's a .purpose file in the directory
|
|
23
|
-
dir=$(dirname "$file")
|
|
24
|
-
while [ "$dir" != "." ]; do
|
|
25
|
-
if [ -f "$dir/.purpose" ]; then
|
|
26
|
-
# Extract feature/component names from .purpose
|
|
27
|
-
purpose_symbols=$(grep -E '^(features|components|gates|flows):' "$dir/.purpose" -A 10 2>/dev/null | grep -E '^ - (name|id):' | sed 's/.*: //' | tr '\\n' ',' | sed 's/,$//')
|
|
28
|
-
if [ -n "$purpose_symbols" ]; then
|
|
29
|
-
symbols="$symbols,$purpose_symbols"
|
|
30
|
-
fi
|
|
31
|
-
break
|
|
32
|
-
fi
|
|
33
|
-
dir=$(dirname "$dir")
|
|
34
|
-
done
|
|
35
|
-
done
|
|
36
|
-
echo "$symbols" | sed 's/^,//' | tr ',' '\\n' | sort -u | tr '\\n' ',' | sed 's/,$//'
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
SYMBOLS=$(extract_symbols)
|
|
40
|
-
|
|
41
|
-
# Extract symbols from commit message Symbols: trailer
|
|
42
|
-
MSG_SYMBOLS=$(echo "$COMMIT_MSG" | grep -E '^Symbols:' | sed 's/^Symbols: //' | tr -d ' ')
|
|
43
|
-
if [ -n "$MSG_SYMBOLS" ]; then
|
|
44
|
-
if [ -n "$SYMBOLS" ]; then
|
|
45
|
-
SYMBOLS="$SYMBOLS,$MSG_SYMBOLS"
|
|
46
|
-
else
|
|
47
|
-
SYMBOLS="$MSG_SYMBOLS"
|
|
48
|
-
fi
|
|
49
|
-
# Deduplicate
|
|
50
|
-
SYMBOLS=$(echo "$SYMBOLS" | tr ',' '\\n' | sort -u | tr '\\n' ',' | sed 's/,$//')
|
|
51
|
-
fi
|
|
52
|
-
|
|
53
|
-
# Determine intent from commit message
|
|
54
|
-
determine_intent() {
|
|
55
|
-
case "$COMMIT_MSG" in
|
|
56
|
-
feat*|feature*|add*) echo "feature" ;;
|
|
57
|
-
fix*|bug*) echo "fix" ;;
|
|
58
|
-
refactor*) echo "refactor" ;;
|
|
59
|
-
*) echo "feature" ;;
|
|
60
|
-
esac
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
INTENT=$(determine_intent)
|
|
64
|
-
|
|
65
|
-
# Record if we found symbols (from .purpose or commit message) and .paradigm/history exists
|
|
66
|
-
if [ -n "$SYMBOLS" ] && [ -d ".paradigm/history" ]; then
|
|
67
|
-
# Generate entry ID
|
|
68
|
-
if [ -f ".paradigm/history/log.jsonl" ]; then
|
|
69
|
-
COUNT=$(wc -l < ".paradigm/history/log.jsonl" | tr -d ' ')
|
|
70
|
-
COUNT=$((COUNT + 1))
|
|
71
|
-
else
|
|
72
|
-
COUNT=1
|
|
73
|
-
fi
|
|
74
|
-
ID=$(printf "h%04d" $COUNT)
|
|
75
|
-
|
|
76
|
-
# Create entry
|
|
77
|
-
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
78
|
-
AUTHOR=$(git config user.name || echo "unknown")
|
|
79
|
-
|
|
80
|
-
# Format symbols as JSON array
|
|
81
|
-
SYMBOLS_JSON=$(echo "$SYMBOLS" | sed 's/,/","/g' | sed 's/^/"/' | sed 's/$/"/')
|
|
82
7
|
|
|
83
|
-
|
|
84
|
-
FILES_JSON=$(echo "$CHANGED_FILES" | tr '\\n' ',' | sed 's/,$//' | sed 's/,/","/g' | sed 's/^/"/' | sed 's/$/"/')
|
|
85
|
-
|
|
86
|
-
# Write entry
|
|
87
|
-
echo "{\\"id\\":\\"$ID\\",\\"ts\\":\\"$TIMESTAMP\\",\\"type\\":\\"implement\\",\\"symbols\\":[$SYMBOLS_JSON],\\"author\\":{\\"type\\":\\"human\\",\\"id\\":\\"$AUTHOR\\"},\\"commit\\":\\"$COMMIT_HASH\\",\\"intent\\":\\"$INTENT\\",\\"files\\":[$FILES_JSON],\\"description\\":\\"$(echo "$COMMIT_MSG" | head -1 | sed 's/"/\\\\"/g')\\"}" >> .paradigm/history/log.jsonl
|
|
88
|
-
|
|
89
|
-
echo "[paradigm] History entry $ID recorded"
|
|
90
|
-
fi
|
|
91
|
-
`;
|
|
92
|
-
var PRE_PUSH_HOOK = `#!/bin/sh
|
|
93
|
-
# Paradigm pre-push hook - reindex history before pushing
|
|
94
|
-
# Installed by: paradigm hooks install
|
|
95
|
-
|
|
96
|
-
if [ -d ".paradigm/history" ] && [ -f ".paradigm/history/log.jsonl" ]; then
|
|
97
|
-
echo "[paradigm] Reindexing history..."
|
|
98
|
-
npx paradigm history reindex 2>/dev/null || true
|
|
99
|
-
fi
|
|
100
|
-
`;
|
|
8
|
+
// src/commands/hooks/generated-hooks.ts
|
|
101
9
|
var CLAUDE_CODE_STOP_HOOK = `#!/bin/sh
|
|
102
10
|
# Paradigm Claude Code Stop Hook (v2)
|
|
103
11
|
# Validates paradigm compliance before allowing the agent to finish.
|
|
@@ -251,8 +159,8 @@ for purpose_file in $(find . -name ".purpose" -not -path "*/node_modules/*" -not
|
|
|
251
159
|
if [ "$in_anchors" = true ]; then
|
|
252
160
|
anchor_path=$(echo "$line" | sed 's/.*- //' | sed 's/:.*//' | tr -d ' ')
|
|
253
161
|
if [ -n "$anchor_path" ]; then
|
|
254
|
-
|
|
255
|
-
if [ ! -f "$
|
|
162
|
+
# Try relative to .purpose dir first, then project root
|
|
163
|
+
if [ ! -f "$purpose_dir/$anchor_path" ] && [ ! -f "./$anchor_path" ]; then
|
|
256
164
|
VIOLATIONS="$VIOLATIONS
|
|
257
165
|
- Aspect anchor '$anchor_path' in $purpose_file does not exist.
|
|
258
166
|
Update the anchor or remove the stale aspect."
|
|
@@ -357,6 +265,13 @@ if [ "$SOURCE_COUNT" -ge 3 ] && [ -d ".paradigm/lore" ]; then
|
|
|
357
265
|
fi
|
|
358
266
|
fi
|
|
359
267
|
|
|
268
|
+
# --- Auto-evaluate on-stop habits via CLI ---
|
|
269
|
+
if command -v paradigm >/dev/null 2>&1; then
|
|
270
|
+
paradigm habits check --trigger on-stop --record --json 2>/dev/null || true
|
|
271
|
+
elif command -v npx >/dev/null 2>&1; then
|
|
272
|
+
npx paradigm habits check --trigger on-stop --record --json 2>/dev/null || true
|
|
273
|
+
fi
|
|
274
|
+
|
|
360
275
|
# --- Check 8: Blocking habits ---
|
|
361
276
|
if [ -f ".paradigm/.habits-blocking" ]; then
|
|
362
277
|
HABITS_BLOCKING=$(cat ".paradigm/.habits-blocking")
|
|
@@ -561,8 +476,8 @@ var CURSOR_STOP_HOOK = `#!/bin/sh
|
|
|
561
476
|
# 4. Aspect anchor files that no longer exist
|
|
562
477
|
# 5. Per-directory .purpose freshness (tracked via .pending-review)
|
|
563
478
|
# 6. Aspect coverage advisory
|
|
564
|
-
# 8. Blocking habits not satisfied (from paradigm_habits_check)
|
|
565
479
|
# 7. Lore entry expected for significant sessions (3+ source files)
|
|
480
|
+
# 8. Blocking habits not satisfied (from paradigm_habits_check)
|
|
566
481
|
|
|
567
482
|
# Read JSON from stdin (hook input)
|
|
568
483
|
INPUT=$(cat)
|
|
@@ -571,7 +486,7 @@ INPUT=$(cat)
|
|
|
571
486
|
if command -v jq >/dev/null 2>&1; then
|
|
572
487
|
CWD=$(echo "$INPUT" | jq -r '.workspace_roots[0] // empty' 2>/dev/null)
|
|
573
488
|
else
|
|
574
|
-
CWD=$(echo "$INPUT" | grep -o '"workspace_roots"[[:space:]]*:[[:space:]]
|
|
489
|
+
CWD=$(echo "$INPUT" | grep -o '"workspace_roots"[[:space:]]*:[[:space:]]*\\["[^"]*"' | head -1 | sed 's/.*\\["//' | sed 's/"$//')
|
|
575
490
|
fi
|
|
576
491
|
|
|
577
492
|
if [ -z "$CWD" ]; then
|
|
@@ -670,7 +585,7 @@ else
|
|
|
670
585
|
case "$file" in
|
|
671
586
|
*.ts|*.js|*.tsx|*.jsx|*.py|*.rs|*.go)
|
|
672
587
|
if [ -f "$file" ]; then
|
|
673
|
-
if grep -qE '
|
|
588
|
+
if grep -qE '\\.(get|post|put|patch|delete)\\s*\\(|router\\.|app\\.(get|post|put|delete)|@(Get|Post|Put|Delete)|#\\[actix_web::(get|post)' "$file" 2>/dev/null; then
|
|
674
589
|
ROUTE_FILES="$ROUTE_FILES $file"
|
|
675
590
|
fi
|
|
676
591
|
fi
|
|
@@ -699,8 +614,8 @@ for purpose_file in $(find . -name ".purpose" -not -path "*/node_modules/*" -not
|
|
|
699
614
|
if [ "$in_anchors" = true ]; then
|
|
700
615
|
anchor_path=$(echo "$line" | sed 's/.*- //' | sed 's/:.*//' | tr -d ' ')
|
|
701
616
|
if [ -n "$anchor_path" ]; then
|
|
702
|
-
|
|
703
|
-
if [ ! -f "$
|
|
617
|
+
# Try relative to .purpose dir first, then project root
|
|
618
|
+
if [ ! -f "$purpose_dir/$anchor_path" ] && [ ! -f "./$anchor_path" ]; then
|
|
704
619
|
VIOLATIONS="$VIOLATIONS
|
|
705
620
|
- Aspect anchor '$anchor_path' in $purpose_file does not exist.
|
|
706
621
|
Update the anchor or remove the stale aspect."
|
|
@@ -805,6 +720,13 @@ if [ "$SOURCE_COUNT" -ge 3 ] && [ -d ".paradigm/lore" ]; then
|
|
|
805
720
|
fi
|
|
806
721
|
fi
|
|
807
722
|
|
|
723
|
+
# --- Auto-evaluate on-stop habits via CLI ---
|
|
724
|
+
if command -v paradigm >/dev/null 2>&1; then
|
|
725
|
+
paradigm habits check --trigger on-stop --record --json 2>/dev/null || true
|
|
726
|
+
elif command -v npx >/dev/null 2>&1; then
|
|
727
|
+
npx paradigm habits check --trigger on-stop --record --json 2>/dev/null || true
|
|
728
|
+
fi
|
|
729
|
+
|
|
808
730
|
# --- Check 8: Blocking habits ---
|
|
809
731
|
if [ -f ".paradigm/.habits-blocking" ]; then
|
|
810
732
|
HABITS_BLOCKING=$(cat ".paradigm/.habits-blocking")
|
|
@@ -994,6 +916,102 @@ done
|
|
|
994
916
|
# Never block \u2014 exit 0
|
|
995
917
|
exit 0
|
|
996
918
|
`;
|
|
919
|
+
|
|
920
|
+
// src/commands/hooks/index.ts
|
|
921
|
+
var POST_COMMIT_HOOK = `#!/bin/sh
|
|
922
|
+
# Paradigm post-commit hook - captures history from commits
|
|
923
|
+
# Installed by: paradigm hooks install
|
|
924
|
+
|
|
925
|
+
# Get the commit message and hash
|
|
926
|
+
COMMIT_HASH=$(git rev-parse HEAD)
|
|
927
|
+
COMMIT_MSG=$(git log -1 --pretty=%B)
|
|
928
|
+
|
|
929
|
+
# Get changed files
|
|
930
|
+
CHANGED_FILES=$(git diff-tree --no-commit-id --name-only -r HEAD)
|
|
931
|
+
|
|
932
|
+
# Extract symbols from changed files (look for .purpose files)
|
|
933
|
+
extract_symbols() {
|
|
934
|
+
local symbols=""
|
|
935
|
+
for file in $CHANGED_FILES; do
|
|
936
|
+
# Check if there's a .purpose file in the directory
|
|
937
|
+
dir=$(dirname "$file")
|
|
938
|
+
while [ "$dir" != "." ]; do
|
|
939
|
+
if [ -f "$dir/.purpose" ]; then
|
|
940
|
+
# Extract feature/component names from .purpose
|
|
941
|
+
purpose_symbols=$(grep -E '^(features|components|gates|flows):' "$dir/.purpose" -A 10 2>/dev/null | grep -E '^ - (name|id):' | sed 's/.*: //' | tr '\\n' ',' | sed 's/,$//')
|
|
942
|
+
if [ -n "$purpose_symbols" ]; then
|
|
943
|
+
symbols="$symbols,$purpose_symbols"
|
|
944
|
+
fi
|
|
945
|
+
break
|
|
946
|
+
fi
|
|
947
|
+
dir=$(dirname "$dir")
|
|
948
|
+
done
|
|
949
|
+
done
|
|
950
|
+
echo "$symbols" | sed 's/^,//' | tr ',' '\\n' | sort -u | tr '\\n' ',' | sed 's/,$//'
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
SYMBOLS=$(extract_symbols)
|
|
954
|
+
|
|
955
|
+
# Extract symbols from commit message Symbols: trailer
|
|
956
|
+
MSG_SYMBOLS=$(echo "$COMMIT_MSG" | grep -E '^Symbols:' | sed 's/^Symbols: //' | tr -d ' ')
|
|
957
|
+
if [ -n "$MSG_SYMBOLS" ]; then
|
|
958
|
+
if [ -n "$SYMBOLS" ]; then
|
|
959
|
+
SYMBOLS="$SYMBOLS,$MSG_SYMBOLS"
|
|
960
|
+
else
|
|
961
|
+
SYMBOLS="$MSG_SYMBOLS"
|
|
962
|
+
fi
|
|
963
|
+
# Deduplicate
|
|
964
|
+
SYMBOLS=$(echo "$SYMBOLS" | tr ',' '\\n' | sort -u | tr '\\n' ',' | sed 's/,$//')
|
|
965
|
+
fi
|
|
966
|
+
|
|
967
|
+
# Determine intent from commit message
|
|
968
|
+
determine_intent() {
|
|
969
|
+
case "$COMMIT_MSG" in
|
|
970
|
+
feat*|feature*|add*) echo "feature" ;;
|
|
971
|
+
fix*|bug*) echo "fix" ;;
|
|
972
|
+
refactor*) echo "refactor" ;;
|
|
973
|
+
*) echo "feature" ;;
|
|
974
|
+
esac
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
INTENT=$(determine_intent)
|
|
978
|
+
|
|
979
|
+
# Record if we found symbols (from .purpose or commit message) and .paradigm/history exists
|
|
980
|
+
if [ -n "$SYMBOLS" ] && [ -d ".paradigm/history" ]; then
|
|
981
|
+
# Generate entry ID
|
|
982
|
+
if [ -f ".paradigm/history/log.jsonl" ]; then
|
|
983
|
+
COUNT=$(wc -l < ".paradigm/history/log.jsonl" | tr -d ' ')
|
|
984
|
+
COUNT=$((COUNT + 1))
|
|
985
|
+
else
|
|
986
|
+
COUNT=1
|
|
987
|
+
fi
|
|
988
|
+
ID=$(printf "h%04d" $COUNT)
|
|
989
|
+
|
|
990
|
+
# Create entry
|
|
991
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
992
|
+
AUTHOR=$(git config user.name || echo "unknown")
|
|
993
|
+
|
|
994
|
+
# Format symbols as JSON array
|
|
995
|
+
SYMBOLS_JSON=$(echo "$SYMBOLS" | sed 's/,/","/g' | sed 's/^/"/' | sed 's/$/"/')
|
|
996
|
+
|
|
997
|
+
# Format files as JSON array
|
|
998
|
+
FILES_JSON=$(echo "$CHANGED_FILES" | tr '\\n' ',' | sed 's/,$//' | sed 's/,/","/g' | sed 's/^/"/' | sed 's/$/"/')
|
|
999
|
+
|
|
1000
|
+
# Write entry
|
|
1001
|
+
echo "{\\"id\\":\\"$ID\\",\\"ts\\":\\"$TIMESTAMP\\",\\"type\\":\\"implement\\",\\"symbols\\":[$SYMBOLS_JSON],\\"author\\":{\\"type\\":\\"human\\",\\"id\\":\\"$AUTHOR\\"},\\"commit\\":\\"$COMMIT_HASH\\",\\"intent\\":\\"$INTENT\\",\\"files\\":[$FILES_JSON],\\"description\\":\\"$(echo "$COMMIT_MSG" | head -1 | sed 's/"/\\\\"/g')\\"}" >> .paradigm/history/log.jsonl
|
|
1002
|
+
|
|
1003
|
+
echo "[paradigm] History entry $ID recorded"
|
|
1004
|
+
fi
|
|
1005
|
+
`;
|
|
1006
|
+
var PRE_PUSH_HOOK = `#!/bin/sh
|
|
1007
|
+
# Paradigm pre-push hook - reindex history before pushing
|
|
1008
|
+
# Installed by: paradigm hooks install
|
|
1009
|
+
|
|
1010
|
+
if [ -d ".paradigm/history" ] && [ -f ".paradigm/history/log.jsonl" ]; then
|
|
1011
|
+
echo "[paradigm] Reindexing history..."
|
|
1012
|
+
npx paradigm history reindex 2>/dev/null || true
|
|
1013
|
+
fi
|
|
1014
|
+
`;
|
|
997
1015
|
async function hooksInstallCommand(options = {}) {
|
|
998
1016
|
const rootDir = process.cwd();
|
|
999
1017
|
const onlyClaudeCode = options.claudeCode && !options.postCommit && !options.prePush && !options.cursor;
|
|
@@ -180,6 +180,47 @@ async function loadLoreEntry(rootDir, entryId) {
|
|
|
180
180
|
const entries = await loadLoreEntries(rootDir);
|
|
181
181
|
return entries.find((e) => e.id === entryId) || null;
|
|
182
182
|
}
|
|
183
|
+
async function updateLoreEntry(rootDir, entryId, partial) {
|
|
184
|
+
const entry = await loadLoreEntry(rootDir, entryId);
|
|
185
|
+
if (!entry) return false;
|
|
186
|
+
const dateStr = entry.timestamp.slice(0, 10);
|
|
187
|
+
const entryPath = path.join(rootDir, LORE_DIR, ENTRIES_DIR, dateStr, `${entryId}.yaml`);
|
|
188
|
+
if (!fs.existsSync(entryPath)) return false;
|
|
189
|
+
if (partial.title !== void 0) entry.title = partial.title;
|
|
190
|
+
if (partial.summary !== void 0) entry.summary = partial.summary;
|
|
191
|
+
if (partial.type !== void 0) entry.type = partial.type;
|
|
192
|
+
if (partial.duration_minutes !== void 0) entry.duration_minutes = partial.duration_minutes;
|
|
193
|
+
if (partial.symbols_touched !== void 0) entry.symbols_touched = partial.symbols_touched;
|
|
194
|
+
if (partial.symbols_created !== void 0) entry.symbols_created = partial.symbols_created;
|
|
195
|
+
if (partial.files_created !== void 0) entry.files_created = partial.files_created;
|
|
196
|
+
if (partial.files_modified !== void 0) entry.files_modified = partial.files_modified;
|
|
197
|
+
if (partial.lines_added !== void 0) entry.lines_added = partial.lines_added;
|
|
198
|
+
if (partial.lines_removed !== void 0) entry.lines_removed = partial.lines_removed;
|
|
199
|
+
if (partial.commit !== void 0) entry.commit = partial.commit;
|
|
200
|
+
if (partial.decisions !== void 0) entry.decisions = partial.decisions;
|
|
201
|
+
if (partial.errors_encountered !== void 0) entry.errors_encountered = partial.errors_encountered;
|
|
202
|
+
if (partial.learnings !== void 0) entry.learnings = partial.learnings;
|
|
203
|
+
if (partial.verification !== void 0) entry.verification = partial.verification;
|
|
204
|
+
if (partial.tags !== void 0) entry.tags = partial.tags;
|
|
205
|
+
fs.writeFileSync(entryPath, yaml.dump(entry, { lineWidth: -1, noRefs: true }));
|
|
206
|
+
await rebuildTimeline(rootDir);
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
async function deleteLoreEntry(rootDir, entryId) {
|
|
210
|
+
const entry = await loadLoreEntry(rootDir, entryId);
|
|
211
|
+
if (!entry) return false;
|
|
212
|
+
const dateStr = entry.timestamp.slice(0, 10);
|
|
213
|
+
const entryPath = path.join(rootDir, LORE_DIR, ENTRIES_DIR, dateStr, `${entryId}.yaml`);
|
|
214
|
+
if (!fs.existsSync(entryPath)) return false;
|
|
215
|
+
fs.unlinkSync(entryPath);
|
|
216
|
+
const dateDir = path.dirname(entryPath);
|
|
217
|
+
const remaining = fs.readdirSync(dateDir).filter((f) => f.endsWith(".yaml"));
|
|
218
|
+
if (remaining.length === 0) {
|
|
219
|
+
fs.rmdirSync(dateDir);
|
|
220
|
+
}
|
|
221
|
+
await rebuildTimeline(rootDir);
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
183
224
|
function migrateLegacyEntries(rootDir) {
|
|
184
225
|
const entriesPath = path.join(rootDir, LORE_DIR, ENTRIES_DIR);
|
|
185
226
|
if (!fs.existsSync(entriesPath)) return 0;
|
|
@@ -249,5 +290,7 @@ export {
|
|
|
249
290
|
recordLore,
|
|
250
291
|
loadLoreEntries,
|
|
251
292
|
addReview,
|
|
252
|
-
loadLoreEntry
|
|
293
|
+
loadLoreEntry,
|
|
294
|
+
updateLoreEntry,
|
|
295
|
+
deleteLoreEntry
|
|
253
296
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
deleteLoreEntry,
|
|
4
|
+
loadLoreEntry
|
|
5
|
+
} from "./chunk-MVXJVRFI.js";
|
|
6
|
+
import "./chunk-MO4EEYFW.js";
|
|
7
|
+
|
|
8
|
+
// src/commands/lore/delete.ts
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
async function loreDeleteCommand(id, options) {
|
|
11
|
+
const rootDir = process.cwd();
|
|
12
|
+
const entry = await loadLoreEntry(rootDir, id);
|
|
13
|
+
if (!entry) {
|
|
14
|
+
console.error(chalk.red(`
|
|
15
|
+
Entry not found: ${id}
|
|
16
|
+
`));
|
|
17
|
+
process.exitCode = 1;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (!options.yes) {
|
|
21
|
+
console.log(chalk.yellow(`
|
|
22
|
+
Will delete lore entry:`));
|
|
23
|
+
console.log(chalk.white(` ${entry.id} - ${entry.title}`));
|
|
24
|
+
console.log(chalk.gray(` Type: ${entry.type} | Author: ${entry.author.id} | ${entry.timestamp}`));
|
|
25
|
+
console.log(chalk.gray(` Symbols: ${entry.symbols_touched.join(", ")}`));
|
|
26
|
+
console.log(chalk.gray(`
|
|
27
|
+
Use --yes to confirm deletion.
|
|
28
|
+
`));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const success = await deleteLoreEntry(rootDir, id);
|
|
32
|
+
if (success) {
|
|
33
|
+
console.log(chalk.green(`
|
|
34
|
+
Deleted lore entry: ${id}
|
|
35
|
+
`));
|
|
36
|
+
} else {
|
|
37
|
+
console.error(chalk.red(`
|
|
38
|
+
Failed to delete: ${id}
|
|
39
|
+
`));
|
|
40
|
+
process.exitCode = 1;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
loreDeleteCommand
|
|
45
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadLoreEntry,
|
|
4
|
+
updateLoreEntry
|
|
5
|
+
} from "./chunk-MVXJVRFI.js";
|
|
6
|
+
import "./chunk-MO4EEYFW.js";
|
|
7
|
+
|
|
8
|
+
// src/commands/lore/edit.ts
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
async function loreEditCommand(id, options) {
|
|
11
|
+
const rootDir = process.cwd();
|
|
12
|
+
const entry = await loadLoreEntry(rootDir, id);
|
|
13
|
+
if (!entry) {
|
|
14
|
+
console.error(chalk.red(`
|
|
15
|
+
Entry not found: ${id}
|
|
16
|
+
`));
|
|
17
|
+
process.exitCode = 1;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const partial = {};
|
|
21
|
+
if (options.title) partial.title = options.title;
|
|
22
|
+
if (options.summary) partial.summary = options.summary;
|
|
23
|
+
if (options.type) {
|
|
24
|
+
const validTypes = ["agent-session", "human-note", "decision", "review", "incident", "milestone"];
|
|
25
|
+
if (!validTypes.includes(options.type)) {
|
|
26
|
+
console.error(chalk.red(`Invalid type: ${options.type}. Valid: ${validTypes.join(", ")}`));
|
|
27
|
+
process.exitCode = 1;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
partial.type = options.type;
|
|
31
|
+
}
|
|
32
|
+
if (options.symbols) {
|
|
33
|
+
partial.symbols_touched = options.symbols.split(",").map((s) => s.trim());
|
|
34
|
+
}
|
|
35
|
+
if (options.tags) {
|
|
36
|
+
partial.tags = options.tags.split(",").map((t) => t.trim());
|
|
37
|
+
}
|
|
38
|
+
if (options.learnings) {
|
|
39
|
+
partial.learnings = options.learnings.split(",").map((l) => l.trim());
|
|
40
|
+
}
|
|
41
|
+
if (Object.keys(partial).length === 0) {
|
|
42
|
+
console.log(chalk.yellow("\n No changes specified. Use --title, --summary, --type, --symbols, --tags, or --learnings.\n"));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const success = await updateLoreEntry(rootDir, id, partial);
|
|
46
|
+
if (success) {
|
|
47
|
+
console.log(chalk.green(`
|
|
48
|
+
Updated lore entry: ${id}`));
|
|
49
|
+
for (const [key, value] of Object.entries(partial)) {
|
|
50
|
+
const display = Array.isArray(value) ? value.join(", ") : String(value);
|
|
51
|
+
console.log(chalk.gray(` ${key}: ${display}`));
|
|
52
|
+
}
|
|
53
|
+
console.log();
|
|
54
|
+
} else {
|
|
55
|
+
console.error(chalk.red(`
|
|
56
|
+
Failed to update: ${id}
|
|
57
|
+
`));
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export {
|
|
62
|
+
loreEditCommand
|
|
63
|
+
};
|