@codyswann/lisa 1.1.0 → 1.3.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/all/copy-overwrite/.claude/commands/tasks/load.md +28 -3
- package/all/copy-overwrite/.claude/commands/tasks/sync.md +37 -12
- package/all/copy-overwrite/.claude/hooks/sync-tasks.sh +12 -3
- package/dist/strategies/merge.d.ts +3 -3
- package/dist/strategies/merge.js +5 -5
- package/dist/strategies/merge.js.map +1 -1
- package/dist/utils/json-utils.d.ts +4 -4
- package/dist/utils/json-utils.js +4 -4
- package/package.json +1 -1
|
@@ -8,18 +8,35 @@ allowed-tools: Read, Bash, TaskCreate, TaskUpdate, TaskList
|
|
|
8
8
|
|
|
9
9
|
Load tasks from `projects/$ARGUMENTS/tasks/` into the current Claude Code session.
|
|
10
10
|
|
|
11
|
+
Tasks are stored in session subdirectories to preserve history across `/clear` commands:
|
|
12
|
+
```
|
|
13
|
+
projects/$ARGUMENTS/tasks/
|
|
14
|
+
├── {session-1-uuid}/
|
|
15
|
+
│ ├── 1.json
|
|
16
|
+
│ └── 2.json
|
|
17
|
+
└── {session-2-uuid}/
|
|
18
|
+
├── 1.json
|
|
19
|
+
└── 2.json
|
|
20
|
+
```
|
|
21
|
+
|
|
11
22
|
## Process
|
|
12
23
|
|
|
13
24
|
### Step 1: Validate Project
|
|
14
25
|
|
|
15
|
-
Check if the project exists:
|
|
26
|
+
Check if the project exists and has task files:
|
|
16
27
|
|
|
17
28
|
```bash
|
|
18
|
-
|
|
29
|
+
find projects/$ARGUMENTS/tasks -name "*.json" 2>/dev/null | head -5
|
|
19
30
|
```
|
|
20
31
|
|
|
21
32
|
If no task files exist, report: "No tasks found in projects/$ARGUMENTS/tasks/"
|
|
22
33
|
|
|
34
|
+
List available sessions:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
ls -dt projects/$ARGUMENTS/tasks/*/ 2>/dev/null | head -10
|
|
38
|
+
```
|
|
39
|
+
|
|
23
40
|
### Step 2: Set Active Project
|
|
24
41
|
|
|
25
42
|
Create the active project marker:
|
|
@@ -32,7 +49,13 @@ This ensures any new tasks created will sync back to this project.
|
|
|
32
49
|
|
|
33
50
|
### Step 3: Load Tasks
|
|
34
51
|
|
|
35
|
-
|
|
52
|
+
Find and load all task JSON files from ALL session directories:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
find projects/$ARGUMENTS/tasks -name "*.json" -type f
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For each JSON file found:
|
|
36
59
|
|
|
37
60
|
1. Read the task JSON file
|
|
38
61
|
2. Use TaskCreate to recreate the task with:
|
|
@@ -48,6 +71,7 @@ After loading all tasks, report:
|
|
|
48
71
|
|
|
49
72
|
```
|
|
50
73
|
Loaded X tasks from projects/$ARGUMENTS/tasks/
|
|
74
|
+
- Sessions found: N
|
|
51
75
|
- Pending: Y
|
|
52
76
|
- Completed: Z
|
|
53
77
|
|
|
@@ -59,5 +83,6 @@ New tasks will automatically sync to this project.
|
|
|
59
83
|
|
|
60
84
|
- Tasks are recreated with new IDs in the current session
|
|
61
85
|
- The original task IDs from the project are not preserved
|
|
86
|
+
- Tasks from ALL sessions are loaded (full history)
|
|
62
87
|
- Task dependencies (blocks/blockedBy) are NOT currently preserved across load/sync cycles
|
|
63
88
|
- Use TaskList to see the loaded tasks
|
|
@@ -6,7 +6,10 @@ allowed-tools: Read, Write, Bash, TaskList, TaskGet
|
|
|
6
6
|
|
|
7
7
|
# Sync Tasks to Project
|
|
8
8
|
|
|
9
|
-
Sync all tasks from the current session to `projects/$ARGUMENTS/tasks/`.
|
|
9
|
+
Sync all tasks from the current session to `projects/$ARGUMENTS/tasks/{session-id}/`.
|
|
10
|
+
|
|
11
|
+
This command is for manual syncing when you started work without setting an active project.
|
|
12
|
+
Once synced, the automatic hook will handle future task updates.
|
|
10
13
|
|
|
11
14
|
## Process
|
|
12
15
|
|
|
@@ -26,7 +29,23 @@ If yes, create the project structure:
|
|
|
26
29
|
mkdir -p projects/$ARGUMENTS/tasks
|
|
27
30
|
```
|
|
28
31
|
|
|
29
|
-
### Step 2:
|
|
32
|
+
### Step 2: Determine Session ID
|
|
33
|
+
|
|
34
|
+
Find the current session by looking for the most recently modified task directory:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
ls -dt ~/.claude/tasks/*/ 2>/dev/null | head -1 | xargs basename
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If no session found, use a timestamp-based identifier:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
echo "manual-$(date +%Y%m%d-%H%M%S)"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Store the session ID for use in subsequent steps.
|
|
47
|
+
|
|
48
|
+
### Step 3: Set Active Project
|
|
30
49
|
|
|
31
50
|
Create/update the active project marker:
|
|
32
51
|
|
|
@@ -34,16 +53,22 @@ Create/update the active project marker:
|
|
|
34
53
|
echo "$ARGUMENTS" > .claude-active-project
|
|
35
54
|
```
|
|
36
55
|
|
|
37
|
-
### Step
|
|
56
|
+
### Step 4: Get Current Tasks
|
|
38
57
|
|
|
39
58
|
Use TaskList to get all tasks in the current session.
|
|
40
59
|
|
|
41
|
-
### Step
|
|
60
|
+
### Step 5: Sync Each Task
|
|
42
61
|
|
|
43
62
|
For each task from TaskList:
|
|
44
63
|
|
|
45
64
|
1. Use TaskGet to get full task details
|
|
46
|
-
2. Create
|
|
65
|
+
2. Create the session directory:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
mkdir -p projects/$ARGUMENTS/tasks/{session-id}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
3. Create a JSON file with the task data:
|
|
47
72
|
|
|
48
73
|
```json
|
|
49
74
|
{
|
|
@@ -57,18 +82,18 @@ For each task from TaskList:
|
|
|
57
82
|
}
|
|
58
83
|
```
|
|
59
84
|
|
|
60
|
-
|
|
85
|
+
4. Write to `projects/$ARGUMENTS/tasks/{session-id}/<id>.json`
|
|
61
86
|
|
|
62
|
-
### Step
|
|
87
|
+
### Step 6: Stage for Git
|
|
63
88
|
|
|
64
89
|
```bash
|
|
65
|
-
git add projects/$ARGUMENTS/tasks/*.json
|
|
90
|
+
git add projects/$ARGUMENTS/tasks/{session-id}/*.json
|
|
66
91
|
```
|
|
67
92
|
|
|
68
|
-
### Step
|
|
93
|
+
### Step 7: Report
|
|
69
94
|
|
|
70
95
|
```
|
|
71
|
-
Synced X tasks to projects/$ARGUMENTS/tasks/
|
|
96
|
+
Synced X tasks to projects/$ARGUMENTS/tasks/{session-id}/
|
|
72
97
|
- Pending: Y
|
|
73
98
|
- In Progress: Z
|
|
74
99
|
- Completed: W
|
|
@@ -80,5 +105,5 @@ Files staged for commit. Run /git:commit when ready.
|
|
|
80
105
|
|
|
81
106
|
- This command manually syncs all current tasks to a project
|
|
82
107
|
- Use this when you started work without a project context
|
|
83
|
-
- After syncing, the active project is set so future tasks auto-sync
|
|
84
|
-
-
|
|
108
|
+
- After syncing, the active project is set so future tasks auto-sync via the hook
|
|
109
|
+
- Each sync creates a new session directory to preserve history
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
#
|
|
5
5
|
# This hook is triggered on PostToolUse for TaskCreate and TaskUpdate.
|
|
6
6
|
# It reads the task metadata to determine the project and syncs
|
|
7
|
-
# task JSON files to ./projects/{project}/tasks/
|
|
7
|
+
# task JSON files to ./projects/{project}/tasks/{session-id}/
|
|
8
|
+
#
|
|
9
|
+
# This session-based structure preserves task history across /clear commands,
|
|
10
|
+
# preventing overwrites when new sessions create tasks with the same IDs.
|
|
8
11
|
#
|
|
9
12
|
# Input (via stdin): JSON with tool_name, tool_input, tool_output
|
|
10
13
|
#
|
|
@@ -82,8 +85,14 @@ if [[ -z "$TASK_FILE" || ! -f "$TASK_FILE" ]]; then
|
|
|
82
85
|
exit 0
|
|
83
86
|
fi
|
|
84
87
|
|
|
85
|
-
#
|
|
86
|
-
|
|
88
|
+
# Require session ID for proper history tracking
|
|
89
|
+
if [[ -z "$SESSION_ID" ]]; then
|
|
90
|
+
echo "Warning: No session_id available, skipping sync" >&2
|
|
91
|
+
exit 0
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Ensure project tasks directory exists (includes session ID for history preservation)
|
|
95
|
+
PROJECT_TASKS_DIR="./projects/${PROJECT}/tasks/${SESSION_ID}"
|
|
87
96
|
mkdir -p "$PROJECT_TASKS_DIR"
|
|
88
97
|
|
|
89
98
|
# Copy task file to project directory
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { FileOperationResult } from "../core/config.js";
|
|
2
2
|
import type { ICopyStrategy, StrategyContext } from "./strategy.interface.js";
|
|
3
3
|
/**
|
|
4
|
-
* Merge strategy: Deep merge JSON files (
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
4
|
+
* Merge strategy: Deep merge JSON files (Lisa values take precedence)
|
|
5
|
+
* - Project values serve as defaults
|
|
6
|
+
* - Lisa values take precedence on conflicts
|
|
7
7
|
* - Handle nested paths (.claude/settings.json)
|
|
8
8
|
*/
|
|
9
9
|
export declare class MergeStrategy implements ICopyStrategy {
|
package/dist/strategies/merge.js
CHANGED
|
@@ -4,9 +4,9 @@ import { ensureParentDir } from "../utils/file-operations.js";
|
|
|
4
4
|
import { readJson, writeJson, deepMerge } from "../utils/json-utils.js";
|
|
5
5
|
import { JsonMergeError } from "../errors/index.js";
|
|
6
6
|
/**
|
|
7
|
-
* Merge strategy: Deep merge JSON files (
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
7
|
+
* Merge strategy: Deep merge JSON files (Lisa values take precedence)
|
|
8
|
+
* - Project values serve as defaults
|
|
9
|
+
* - Lisa values take precedence on conflicts
|
|
10
10
|
* - Handle nested paths (.claude/settings.json)
|
|
11
11
|
*/
|
|
12
12
|
export class MergeStrategy {
|
|
@@ -38,8 +38,8 @@ export class MergeStrategy {
|
|
|
38
38
|
const destJson = await readJson(destPath).catch(() => {
|
|
39
39
|
throw new JsonMergeError(relativePath, `Failed to parse destination: ${destPath}`);
|
|
40
40
|
});
|
|
41
|
-
// Deep merge: Lisa (source)
|
|
42
|
-
const merged = deepMerge(
|
|
41
|
+
// Deep merge: Lisa (source) takes precedence, project (dest) provides defaults
|
|
42
|
+
const merged = deepMerge(destJson, sourceJson);
|
|
43
43
|
// Normalize for comparison (parse and re-stringify both)
|
|
44
44
|
const normalizedDest = JSON.stringify(destJson, null, 2);
|
|
45
45
|
const normalizedMerged = JSON.stringify(merged, null, 2);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/strategies/merge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IACf,IAAI,GAAG,OAAgB,CAAC;IAEjC;;;;;;;OAOG;IACH,KAAK,CAAC,KAAK,CACT,UAAkB,EAClB,QAAgB,EAChB,YAAoB,EACpB,OAAwB;QAExB,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;QACnD,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAElD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,4CAA4C;YAC5C,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnB,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;gBAChC,MAAM,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACrC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC;YACD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACjE,CAAC;QAED,gCAAgC;QAChC,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAS,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAC/D,MAAM,IAAI,cAAc,CACtB,YAAY,EACZ,2BAA2B,UAAU,EAAE,CACxC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAS,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAC3D,MAAM,IAAI,cAAc,CACtB,YAAY,EACZ,gCAAgC,QAAQ,EAAE,CAC3C,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/strategies/merge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IACf,IAAI,GAAG,OAAgB,CAAC;IAEjC;;;;;;;OAOG;IACH,KAAK,CAAC,KAAK,CACT,UAAkB,EAClB,QAAgB,EAChB,YAAoB,EACpB,OAAwB;QAExB,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;QACnD,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAElD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,4CAA4C;YAC5C,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnB,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;gBAChC,MAAM,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACrC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC;YACD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACjE,CAAC;QAED,gCAAgC;QAChC,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAS,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAC/D,MAAM,IAAI,cAAc,CACtB,YAAY,EACZ,2BAA2B,UAAU,EAAE,CACxC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAS,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAC3D,MAAM,IAAI,cAAc,CACtB,YAAY,EACZ,gCAAgC,QAAQ,EAAE,CAC3C,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,+EAA+E;QAC/E,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAE/C,yDAAyD;QACzD,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzD,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAEzD,IAAI,cAAc,KAAK,gBAAgB,EAAE,CAAC;YACxC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnB,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC;YACD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAClE,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC3B,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAClC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IACjE,CAAC;CACF"}
|
|
@@ -24,11 +24,11 @@ export declare function writeJson(filePath: string, data: unknown, spaces?: numb
|
|
|
24
24
|
*/
|
|
25
25
|
export declare function isValidJson(filePath: string): Promise<boolean>;
|
|
26
26
|
/**
|
|
27
|
-
* Deep merge two objects (
|
|
27
|
+
* Deep merge two objects (Lisa values take precedence on conflicts)
|
|
28
28
|
* Uses lodash.merge for deep merging
|
|
29
|
-
* @param base Base object
|
|
30
|
-
* @param override Override object with precedence
|
|
31
|
-
* @returns Merged object
|
|
29
|
+
* @param base Base object (project values)
|
|
30
|
+
* @param override Override object with precedence (Lisa values)
|
|
31
|
+
* @returns Merged object with Lisa values winning conflicts
|
|
32
32
|
*/
|
|
33
33
|
export declare function deepMerge<T extends object>(base: T, override: T): T;
|
|
34
34
|
//# sourceMappingURL=json-utils.d.ts.map
|
package/dist/utils/json-utils.js
CHANGED
|
@@ -56,11 +56,11 @@ export async function isValidJson(filePath) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
-
* Deep merge two objects (
|
|
59
|
+
* Deep merge two objects (Lisa values take precedence on conflicts)
|
|
60
60
|
* Uses lodash.merge for deep merging
|
|
61
|
-
* @param base Base object
|
|
62
|
-
* @param override Override object with precedence
|
|
63
|
-
* @returns Merged object
|
|
61
|
+
* @param base Base object (project values)
|
|
62
|
+
* @param override Override object with precedence (Lisa values)
|
|
63
|
+
* @returns Merged object with Lisa values winning conflicts
|
|
64
64
|
*/
|
|
65
65
|
export function deepMerge(base, override) {
|
|
66
66
|
// Create a new object to avoid mutating inputs
|
package/package.json
CHANGED
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"@ast-grep/cli"
|
|
80
80
|
],
|
|
81
81
|
"name": "@codyswann/lisa",
|
|
82
|
-
"version": "1.
|
|
82
|
+
"version": "1.3.0",
|
|
83
83
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
84
84
|
"main": "dist/index.js",
|
|
85
85
|
"bin": {
|