@tonycasey/lisa 1.0.6 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonycasey/lisa",
3
- "version": "1.0.6",
3
+ "version": "1.1.1",
4
4
  "description": "Long-term memory for Claude Code. Automatic context persistence, task tracking, and knowledge capture across coding sessions.",
5
5
  "bin": {
6
6
  "remember": "cli.js",
@@ -38,6 +38,7 @@
38
38
  "commander": "^11.1.0",
39
39
  "execa": "^8.0.1",
40
40
  "fs-extra": "^11.2.0",
41
+ "glob": "^10.3.10",
41
42
  "yaml": "^2.4.2"
42
43
  }
43
44
  }
@@ -0,0 +1,57 @@
1
+ # Local Extensions
2
+
3
+ This project supports local rule and skill extensions that persist across package updates.
4
+
5
+ ## How Local Extensions Work
6
+
7
+ When loading any rule file (e.g., `git-rules.md`), **always check if a corresponding `.local.md` file exists** (e.g., `git-rules.local.md`). If it exists, apply both files with the local file taking precedence.
8
+
9
+ ## Extension Pattern
10
+
11
+ Local files use inheritance semantics:
12
+
13
+ - **Inherits**: All sections from the base file apply unless overridden
14
+ - **Override**: A section with the same name in the local file replaces the base section
15
+ - **Extend**: New sections in the local file add to the base rules
16
+
17
+ ## File Naming Convention
18
+
19
+ | Base File | Local Extension |
20
+ |-----------|-----------------|
21
+ | `git-rules.md` | `git-rules.local.md` |
22
+ | `coding-standards.md` | `coding-standards.local.md` |
23
+ | `testing-principles.md` | `testing-principles.local.md` |
24
+
25
+ ## Local File Format
26
+
27
+ Local extension files should include:
28
+
29
+ 1. A title indicating it's a local extension
30
+ 2. An `> Extends:` directive referencing the base file
31
+ 3. Sections that override or extend the base
32
+
33
+ ### Example: `git-rules.local.md`
34
+
35
+ ```markdown
36
+ # Git Rules (Local Extensions)
37
+
38
+ > Extends: git-rules.md
39
+
40
+ ## Commit Messages (Override)
41
+ - Use format: `[JIRA-123] type: description`
42
+ - All commits MUST reference a Jira ticket
43
+
44
+ ## Branch Naming (New Section)
45
+ - Feature branches: `feature/JIRA-123-description`
46
+ - Bugfix branches: `bugfix/JIRA-123-description`
47
+ ```
48
+
49
+ ## For Skills
50
+
51
+ Custom skills use a `.local.md` file name suffix too:
52
+
53
+ ## Important
54
+
55
+ - Local files are **preserved** during package updates
56
+ - Local files are **not** created automatically - users create them manually when needed
57
+ - Always apply local extensions when they exist
@@ -0,0 +1,20 @@
1
+ # Git Rules (Local Extensions)
2
+
3
+ > Extends: git-rules.md
4
+
5
+ <!--
6
+ This file extends the base git-rules.md with project-specific rules.
7
+
8
+ Add your custom git workflow rules here. They will be preserved
9
+ across package updates.
10
+
11
+ Example overrides:
12
+
13
+ ## Commit Messages (Override)
14
+ - Use format: `[JIRA-123] type: description`
15
+ - All commits MUST reference a ticket
16
+
17
+ ## Branch Naming (New Section)
18
+ - Feature: `feature/JIRA-123-description`
19
+ - Bugfix: `bugfix/JIRA-123-description`
20
+ -->
@@ -2,15 +2,24 @@
2
2
 
3
3
  ## Commit Memory Rule
4
4
 
5
- **IMPORTANT:** After every successful git commit, you MUST create a milestone memory summarizing what was committed.
5
+ **IMPORTANT:** After every successful git commit, you MUST do TWO things:
6
+ 1. Create a milestone memory summarizing what was committed
7
+ 2. Update the task status if completing a Jira ticket
6
8
 
7
- ### How to Create Commit Memory
9
+ ### Step 1: Create Commit Memory
8
10
 
9
11
  After a commit succeeds, run:
10
12
  ```bash
11
13
  node .agents/skills/memory/scripts/memory.js add "<summary>" --cache --type milestone
12
14
  ```
13
15
 
16
+ ### Step 2: Update Task Status (for tickets)
17
+
18
+ If the commit completes ticket (JIRA-1234), also run:
19
+ ```bash
20
+ node .agents/skills/tasks/scripts/tasks.js add "JIRA-1234: COMPLETED - <description>" --cache --status done
21
+ ```
22
+
14
23
  ### Summary Format
15
24
 
16
25
  The summary should be concise and describe:
@@ -20,9 +29,13 @@ The summary should be concise and describe:
20
29
 
21
30
  ### Examples
22
31
 
23
- **Feature commit:**
32
+ **Feature commit (with Jira ticket):**
24
33
  ```bash
25
- node .agents/skills/memory/scripts/memory.js add "FEATURE: Added user authentication with JWT tokens and session management" --cache --type milestone
34
+ # Step 1: Save milestone
35
+ node .agents/skills/memory/scripts/memory.js add "FEATURE: [JIRA-1234] Added Excel brandlist parser with unit tests" --cache --type milestone
36
+
37
+ # Step 2: Update task status
38
+ node .agents/skills/tasks/scripts/tasks.js add "JIRA-1234: COMPLETED - Excel brandlist parser utility created, PR #XXXX" --cache --status done
26
39
  ```
27
40
 
28
41
  **Bug fix:**
@@ -38,7 +51,8 @@ node .agents/skills/memory/scripts/memory.js add "REFACTOR: Migrated API handler
38
51
  ### Why This Matters
39
52
 
40
53
  - Creates a searchable history of development progress
41
- - Helps future sessions understand what was accomplished
54
+ - Keeps task status accurate across sessions
55
+ - Helps future sessions understand what was achieved
42
56
  - Builds project context for AI assistants
43
57
  - Tracks milestones and features over time
44
58
 
@@ -62,3 +76,8 @@ node .agents/skills/memory/scripts/memory.js add "REFACTOR: Migrated API handler
62
76
  - Keep commits focused and atomic
63
77
  - Don't mix unrelated changes in one commit
64
78
  - Write meaningful commit messages
79
+
80
+
81
+ ## Pull Requests
82
+
83
+ Follow generic guidelines for pull requests, ensuring all required information is provided in the description.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonycasey/lisa",
3
- "version": "1.0.6",
3
+ "version": "1.1.1",
4
4
  "description": "Long-term memory for Claude Code. Automatic context persistence, task tracking, and knowledge capture across coding sessions.",
5
5
  "bin": {
6
6
  "lisa": "dist/cli.js",
@@ -55,6 +55,7 @@
55
55
  "commander": "^11.1.0",
56
56
  "execa": "^8.0.1",
57
57
  "fs-extra": "^11.2.0",
58
+ "glob": "^10.3.10",
58
59
  "yaml": "^2.4.2"
59
60
  },
60
61
  "devDependencies": {
@@ -12,6 +12,7 @@ const fs = require('fs-extra');
12
12
  const { execSync, spawn } = require('child_process');
13
13
  const readline = require('readline');
14
14
  const net = require('net');
15
+ const { glob } = require('glob');
15
16
 
16
17
  // When installed as a dependency, the project root is four levels up from node_modules/@tonycasey/lisa/scripts
17
18
  // When running locally (development), use the current working directory
@@ -326,6 +327,69 @@ async function copyTemplates(src, dest, force = false) {
326
327
  return true;
327
328
  }
328
329
 
330
+ /**
331
+ * Preserve local extensions (.local.md files and .local/ directories) before deployment.
332
+ * These are user-created files that should survive package updates.
333
+ */
334
+ async function preserveLocalExtensions(targetDir) {
335
+ const preserved = { files: [], dirs: [] };
336
+
337
+ if (!(await fs.pathExists(targetDir))) {
338
+ return preserved;
339
+ }
340
+
341
+ // Find all .local.md files (rules extensions)
342
+ const localFiles = await glob('**/*.local.md', { cwd: targetDir, nodir: true });
343
+ for (const file of localFiles) {
344
+ const fullPath = path.join(targetDir, file);
345
+ const content = await fs.readFile(fullPath, 'utf8');
346
+ preserved.files.push({ path: file, content });
347
+ }
348
+
349
+ // Find all .local directories (skill extensions)
350
+ // Use trailing slash to match only directories (glob doesn't support onlyDirectories option)
351
+ const localDirMatches = await glob('**/*.local/', { cwd: targetDir });
352
+ const localDirs = localDirMatches.map(d => d.replace(/\/$/, '')); // Remove trailing slash
353
+ for (const dir of localDirs) {
354
+ const fullPath = path.join(targetDir, dir);
355
+ const files = [];
356
+ const dirFiles = await glob('**/*', { cwd: fullPath, nodir: true });
357
+ for (const file of dirFiles) {
358
+ const filePath = path.join(fullPath, file);
359
+ const content = await fs.readFile(filePath, 'utf8');
360
+ files.push({ path: file, content });
361
+ }
362
+ preserved.dirs.push({ path: dir, files });
363
+ }
364
+
365
+ if (preserved.files.length > 0 || preserved.dirs.length > 0) {
366
+ console.log(` Preserving ${preserved.files.length} local file(s) and ${preserved.dirs.length} local dir(s)`);
367
+ }
368
+
369
+ return preserved;
370
+ }
371
+
372
+ /**
373
+ * Restore preserved local extensions after deployment.
374
+ */
375
+ async function restoreLocalExtensions(targetDir, preserved) {
376
+ for (const { path: filePath, content } of preserved.files) {
377
+ const fullPath = path.join(targetDir, filePath);
378
+ await fs.ensureDir(path.dirname(fullPath));
379
+ await fs.writeFile(fullPath, content, 'utf8');
380
+ console.log(` ✓ Restored: ${filePath}`);
381
+ }
382
+
383
+ for (const { path: dirPath, files } of preserved.dirs) {
384
+ for (const { path: filePath, content } of files) {
385
+ const fullPath = path.join(targetDir, dirPath, filePath);
386
+ await fs.ensureDir(path.dirname(fullPath));
387
+ await fs.writeFile(fullPath, content, 'utf8');
388
+ }
389
+ console.log(` ✓ Restored: ${dirPath}/`);
390
+ }
391
+ }
392
+
329
393
  async function createSymlink(target, linkPath) {
330
394
  try {
331
395
  if (await fs.pathExists(linkPath)) {
@@ -367,17 +431,17 @@ async function copyDockerFiles(agentsDir) {
367
431
  await fs.copy(composeSrc, composeDest, { overwrite: false });
368
432
  }
369
433
 
370
- // Copy .env.lisa.example to project root (if no .env exists)
371
- const envSrc = path.join(dockerSrc, '.env.lisa.example');
434
+ // Copy .env to project root (if no .env exists)
435
+ const envSrc = path.join(dockerSrc, '.env');
372
436
  const rootEnv = path.join(path.dirname(agentsDir), '.env');
373
- const envExampleDest = path.join(path.dirname(agentsDir), '.env.lisa.example');
437
+ const envExampleDest = path.join(path.dirname(agentsDir), '.env');
374
438
  if (await fs.pathExists(envSrc)) {
375
439
  // Always copy the example file for reference
376
440
  await fs.copy(envSrc, envExampleDest, { overwrite: false });
377
441
  // If no .env exists, create one from the example
378
442
  if (!(await fs.pathExists(rootEnv))) {
379
443
  await fs.copy(envSrc, rootEnv);
380
- console.log(' Created .env from .env.lisa.example');
444
+ console.log(' Created .env from .env');
381
445
  }
382
446
  }
383
447
 
@@ -499,10 +563,10 @@ async function setupDocker(agentsDir) {
499
563
  // Check if .env exists in project root, if not copy from example
500
564
  const projectRoot = path.dirname(agentsDir);
501
565
  const envFile = path.join(projectRoot, '.env');
502
- const envExample = path.join(projectRoot, '.env.lisa.example');
566
+ const envExample = path.join(projectRoot, '.env');
503
567
  if (!(await fs.pathExists(envFile)) && (await fs.pathExists(envExample))) {
504
568
  await fs.copy(envExample, envFile);
505
- console.log(' Created .env from .env.lisa.example');
569
+ console.log(' Created .env from .env');
506
570
  console.log(' IMPORTANT: Edit .env and add your OPENAI_API_KEY');
507
571
  }
508
572
 
@@ -641,6 +705,9 @@ async function main() {
641
705
  const agentsDir = path.join(projectRoot, '.agents');
642
706
  const claudeDir = path.join(projectRoot, '.claude');
643
707
 
708
+ // Preserve local extensions before copying (user-created .local.md files and .local/ directories)
709
+ const preservedExtensions = await preserveLocalExtensions(agentsDir);
710
+
644
711
  // Copy .agents templates
645
712
  const agentsSrc = path.join(templateRoot, 'agents');
646
713
  const rulesSrc = path.join(templateRoot, 'rules');
@@ -658,6 +725,9 @@ async function main() {
658
725
  console.log(' ✓ Copied .agents/rules/');
659
726
  }
660
727
 
728
+ // Restore local extensions after copying
729
+ await restoreLocalExtensions(agentsDir, preservedExtensions);
730
+
661
731
  // Copy .claude templates
662
732
  const claudeSrc = path.join(templateRoot, 'claude');
663
733
  if (await fs.pathExists(claudeSrc)) {