create-lore 0.9.0 → 0.11.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.
@@ -0,0 +1 @@
1
+ * @drewswiredin
@@ -6,6 +6,7 @@ on:
6
6
 
7
7
  permissions:
8
8
  contents: write
9
+ id-token: write
9
10
 
10
11
  jobs:
11
12
  test:
@@ -16,13 +17,13 @@ jobs:
16
17
  os: [ubuntu-latest, macos-latest, windows-latest]
17
18
  node-version: [18, 20]
18
19
  steps:
19
- - uses: actions/checkout@v4 # checkout create-lore (this repo)
20
- - uses: actions/checkout@v4 # checkout lore template at matching tag
20
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 # checkout create-lore (this repo)
21
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 # checkout lore template at matching tag
21
22
  with:
22
23
  repository: lorehq/lore
23
24
  ref: ${{ github.ref_name }}
24
25
  path: lore
25
- - uses: actions/setup-node@v4
26
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
26
27
  with:
27
28
  node-version: ${{ matrix.node-version }}
28
29
  - run: npm test
@@ -32,7 +33,7 @@ jobs:
32
33
  verify-tag:
33
34
  runs-on: ubuntu-latest
34
35
  steps:
35
- - uses: actions/checkout@v4
36
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
36
37
  - name: Verify tag matches package.json version
37
38
  run: |
38
39
  tag="${GITHUB_REF#refs/tags/v}"
@@ -55,13 +56,13 @@ jobs:
55
56
  needs: [test, verify-tag]
56
57
  runs-on: ubuntu-latest
57
58
  steps:
58
- - uses: actions/checkout@v4
59
- - uses: actions/setup-node@v4
59
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
60
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
60
61
  with:
61
62
  node-version: 20
62
63
  registry-url: https://registry.npmjs.org
63
64
  - name: Publish to npm
64
- run: npm publish
65
+ run: npm publish --provenance
65
66
  env:
66
67
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
67
68
  - name: Create GitHub Release
@@ -15,14 +15,17 @@ jobs:
15
15
  os: [ubuntu-latest, macos-latest, windows-latest]
16
16
  node-version: [18, 20]
17
17
  steps:
18
- - uses: actions/checkout@v4 # checkout create-lore (this repo)
19
- - uses: actions/checkout@v4 # checkout lore template (used as LORE_TEMPLATE)
18
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 # checkout create-lore (this repo)
19
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 # checkout lore template (used as LORE_TEMPLATE)
20
20
  with:
21
21
  repository: lorehq/lore
22
22
  path: lore
23
- - uses: actions/setup-node@v4
23
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
24
24
  with:
25
25
  node-version: ${{ matrix.node-version }}
26
+ - run: npm ci
27
+ - name: Lint & format
28
+ run: npx eslint . && npx prettier --check .
26
29
  - run: npm test
27
30
  env:
28
31
  LORE_TEMPLATE: ${{ github.workspace }}/lore
@@ -34,12 +37,12 @@ jobs:
34
37
  matrix:
35
38
  os: [ubuntu-latest, macos-latest, windows-latest]
36
39
  steps:
37
- - uses: actions/checkout@v4
38
- - uses: actions/checkout@v4
40
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
41
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
39
42
  with:
40
43
  repository: lorehq/lore
41
44
  path: lore
42
- - uses: actions/setup-node@v4
45
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
43
46
  with:
44
47
  node-version: 20
45
48
  - name: Scaffold a project and validate it
@@ -49,4 +52,4 @@ jobs:
49
52
  run: |
50
53
  node bin/create-lore.js test-project
51
54
  cd test-project
52
- bash scripts/validate-consistency.sh
55
+ bash .lore/scripts/validate-consistency.sh
@@ -0,0 +1 @@
1
+ lore/
package/.prettierrc ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "singleQuote": true,
3
+ "semi": true,
4
+ "trailingComma": "all",
5
+ "printWidth": 120,
6
+ "tabWidth": 2
7
+ }
package/README.md CHANGED
@@ -14,6 +14,7 @@ Lore wraps your coding agent in a git-versioned knowledge base. Hooks fire autom
14
14
  - **Knowledge docs** — Environment details, runbooks, architecture decisions. Accumulated across sessions.
15
15
  - **Work tracking** — Roadmaps, plans, and brainstorms that persist and appear in every session banner.
16
16
  - **Hooks** — Session init, capture reminders, memory protection. All automatic.
17
+ - **Docs UI & Semantic Search** — Run `/lore-docker` to start a local Docker sidecar. Gives agents semantic search over the full knowledge base and opens a live MkDocs site for browsing it visually. Falls back to Grep/Glob without Docker — works for small knowledge bases, degrades as docs grow.
17
18
 
18
19
  ## Quick Start
19
20
 
@@ -27,11 +28,11 @@ Then open the project in your agent. Hooks fire automatically.
27
28
 
28
29
  ## Supported Platforms
29
30
 
30
- | Platform | Integration |
31
- |----------|-------------|
32
- | Claude Code | `hooks/` + `CLAUDE.md` |
33
- | Cursor | `.cursor/hooks/` + `.cursor/mcp/` + `.cursor/rules/` |
34
- | OpenCode | `.opencode/plugins/` + `opencode.json` |
31
+ | Platform | Integration |
32
+ | ----------- | --------------------------------------------------------------------- |
33
+ | Claude Code | `.lore/hooks/` + `CLAUDE.md` |
34
+ | Cursor | `.lore/hooks/` + `.cursor/hooks/` + `.cursor/mcp/` + `.cursor/rules/` |
35
+ | OpenCode | `.opencode/plugins/` + `opencode.json` |
35
36
 
36
37
  All platforms share the same knowledge base. No configuration needed.
37
38
 
@@ -48,6 +49,7 @@ npx create-lore --version # show version
48
49
 
49
50
  - Node.js 18+
50
51
  - git
52
+ - Docker (highly recommended — enables semantic search and docs UI; not required)
51
53
 
52
54
  ## Docs
53
55
 
package/SECURITY.md CHANGED
@@ -20,5 +20,5 @@ We will acknowledge receipt within 48 hours and provide a timeline for a fix.
20
20
  ## Supported Versions
21
21
 
22
22
  | Version | Supported |
23
- |---------|-----------|
24
- | 0.8.x | Yes |
23
+ | ------- | --------- |
24
+ | 0.11.x | Yes |
@@ -7,7 +7,7 @@
7
7
  // How it works:
8
8
  // 1. Clones the Lore template from GitHub (or copies from LORE_TEMPLATE env var)
9
9
  // 2. Strips the template's .git history
10
- // 3. Writes a .lore-config with the project name and creation date
10
+ // 3. Writes .lore/config.json with the project name and creation date
11
11
  // 4. Runs git init for a clean start
12
12
  //
13
13
  // The LORE_TEMPLATE env var is used by tests to point at a local template
@@ -99,27 +99,67 @@ try {
99
99
  }
100
100
  }
101
101
  fs.rmSync(path.join(tmpDir, '.git'), { recursive: true, force: true });
102
+
103
+ // Only keep files needed in instances — remove everything else
104
+ const keep = new Set([
105
+ '.lore',
106
+ '.claude',
107
+ '.cursor',
108
+ '.opencode',
109
+ 'docs',
110
+ 'CLAUDE.md',
111
+ 'opencode.json',
112
+ '.mcp.json',
113
+ '.gitattributes',
114
+ '.gitignore',
115
+ ]);
116
+ for (const entry of fs.readdirSync(tmpDir)) {
117
+ if (!keep.has(entry)) {
118
+ fs.rmSync(path.join(tmpDir, entry), { recursive: true, force: true });
119
+ }
120
+ }
121
+
102
122
  fs.cpSync(tmpDir, targetDir, { recursive: true });
103
123
  } finally {
104
124
  // Always clean up the temp dir
105
125
  if (fs.existsSync(tmpDir)) fs.rmSync(tmpDir, { recursive: true });
106
126
  }
107
127
 
108
- // -- Write .lore-config --
128
+ // -- Write .lore/config.json --
109
129
  const projectName = isPath ? path.basename(targetDir) : name;
110
- // Read version from the template's .lore-config so instances track their source version
130
+ // Read version from the copied config.json, then rewrite from template
111
131
  let templateConfig;
112
132
  try {
113
- templateConfig = JSON.parse(fs.readFileSync(path.join(targetDir, '.lore-config'), 'utf8'));
114
- } catch (e) {
133
+ templateConfig = JSON.parse(fs.readFileSync(path.join(targetDir, '.lore', 'config.json'), 'utf8'));
134
+ } catch {
115
135
  templateConfig = {};
116
136
  }
117
- const config = {
118
- name: projectName,
119
- version: templateConfig.version || '0.0.0',
120
- created: new Date().toISOString().split('T')[0],
121
- };
122
- fs.writeFileSync(path.join(targetDir, '.lore-config'), JSON.stringify(config, null, 2) + '\n');
137
+ const templateVersion = templateConfig.version || '0.0.0';
138
+ const createdDate = new Date().toISOString().split('T')[0];
139
+ const configTemplate = fs.readFileSync(path.join(targetDir, '.lore', 'templates', 'config.json'), 'utf8');
140
+ const configContent = configTemplate
141
+ .replace('{{name}}', projectName)
142
+ .replace('{{version}}', templateVersion)
143
+ .replace('{{created}}', createdDate);
144
+ fs.writeFileSync(path.join(targetDir, '.lore', 'config.json'), configContent);
145
+
146
+ // -- Create gitignored files from templates --
147
+ // Templates are already in targetDir (copied from the template clone via .lore/).
148
+ // These are normally recreated by ensureStickyFiles() each session, but the
149
+ // installer should produce a complete instance from the start.
150
+ const tplDir = path.join(targetDir, '.lore', 'templates');
151
+ const localDir = path.join(targetDir, 'docs', 'knowledge', 'local');
152
+ fs.mkdirSync(localDir, { recursive: true });
153
+
154
+ fs.writeFileSync(path.join(localDir, 'index.md'), fs.readFileSync(path.join(tplDir, 'local-index.md'), 'utf8'));
155
+ fs.writeFileSync(
156
+ path.join(localDir, 'operator-profile.md'),
157
+ fs.readFileSync(path.join(tplDir, 'operator-profile.md'), 'utf8'),
158
+ );
159
+ fs.writeFileSync(
160
+ path.join(targetDir, '.lore', 'memory.local.md'),
161
+ fs.readFileSync(path.join(tplDir, 'memory-local.md'), 'utf8'),
162
+ );
123
163
 
124
164
  // -- Initialize git --
125
165
  execSync('git init -b main', { cwd: targetDir, stdio: 'pipe' });
@@ -0,0 +1,31 @@
1
+ const prettier = require('eslint-config-prettier');
2
+
3
+ module.exports = [
4
+ { ignores: ['lore/'] },
5
+ {
6
+ files: ['**/*.js'],
7
+ languageOptions: {
8
+ ecmaVersion: 2022,
9
+ sourceType: 'commonjs',
10
+ globals: {
11
+ console: 'readonly',
12
+ process: 'readonly',
13
+ require: 'readonly',
14
+ module: 'readonly',
15
+ __dirname: 'readonly',
16
+ __filename: 'readonly',
17
+ exports: 'readonly',
18
+ Buffer: 'readonly',
19
+ },
20
+ },
21
+ rules: {
22
+ 'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
23
+ 'no-undef': 'error',
24
+ 'no-constant-condition': 'warn',
25
+ eqeqeq: ['error', 'always'],
26
+ 'no-var': 'error',
27
+ 'prefer-const': 'warn',
28
+ },
29
+ },
30
+ prettier,
31
+ ];
package/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "name": "create-lore",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Create a new Lore knowledge-persistent agent repo",
5
5
  "bin": {
6
6
  "create-lore": "bin/create-lore.js"
7
7
  },
8
8
  "scripts": {
9
- "test": "node --test test/create-lore.test.js"
9
+ "test": "node --test test/create-lore.test.js",
10
+ "lint": "eslint .",
11
+ "format:check": "prettier --check ."
10
12
  },
11
13
  "keywords": [
12
14
  "lore",
@@ -15,7 +17,16 @@
15
17
  "knowledge"
16
18
  ],
17
19
  "license": "Apache-2.0",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/lorehq/create-lore"
23
+ },
18
24
  "engines": {
19
25
  "node": ">=18"
26
+ },
27
+ "devDependencies": {
28
+ "eslint": "^9.0.0",
29
+ "eslint-config-prettier": "^10.1.8",
30
+ "prettier": "^3.8.1"
20
31
  }
21
32
  }
@@ -4,7 +4,7 @@
4
4
 
5
5
  const { describe, it, before, after } = require('node:test');
6
6
  const assert = require('node:assert/strict');
7
- const { execSync } = require('child_process');
7
+ const { execSync, execFileSync } = require('child_process');
8
8
  const fs = require('fs');
9
9
  const path = require('path');
10
10
 
@@ -14,7 +14,7 @@ const OUTPUT = path.resolve(__dirname, '../test-output');
14
14
 
15
15
  // Run the installer with LORE_TEMPLATE pointing at the local template
16
16
  function run(args = '') {
17
- return execSync(`node ${BIN} ${args}`, {
17
+ return execFileSync('node', [BIN, ...args.split(' ').filter(Boolean)], {
18
18
  env: { ...process.env, LORE_TEMPLATE: TEMPLATE },
19
19
  stdio: 'pipe',
20
20
  encoding: 'utf8',
@@ -23,7 +23,7 @@ function run(args = '') {
23
23
 
24
24
  // Run with exact argv (no shell interpretation) — for testing shell metacharacters
25
25
  function runExact(name) {
26
- return require('child_process').execFileSync('node', [BIN, name], {
26
+ return execFileSync('node', [BIN, name], {
27
27
  env: { ...process.env, LORE_TEMPLATE: TEMPLATE },
28
28
  stdio: 'pipe',
29
29
  encoding: 'utf8',
@@ -59,8 +59,14 @@ describe('create-lore', () => {
59
59
 
60
60
  assert.ok(fs.existsSync(OUTPUT), 'output directory exists');
61
61
 
62
- // .lore-config has required fields
63
- const config = JSON.parse(fs.readFileSync(path.join(OUTPUT, '.lore-config'), 'utf8'));
62
+ // .lore/config.json has required fields (JSONC — strip comments before parsing)
63
+ const raw = fs.readFileSync(path.join(OUTPUT, '.lore', 'config.json'), 'utf8');
64
+ const config = JSON.parse(
65
+ raw
66
+ .replace(/^\s*\/\/.*$/gm, '')
67
+ .replace(/\/\*[\s\S]*?\*\//g, '')
68
+ .replace(/,(\s*[}\]])/g, '$1'),
69
+ );
64
70
  assert.ok(config.name, 'name present');
65
71
  assert.ok(config.created, 'created date present');
66
72
 
@@ -70,6 +76,34 @@ describe('create-lore', () => {
70
76
  assert.ok(entries.includes('HEAD'), '.git looks like a fresh init');
71
77
  });
72
78
 
79
+ it('strips dev-only files from scaffolded instance', () => {
80
+ cleanup();
81
+ run(OUTPUT);
82
+
83
+ const devOnly = [
84
+ 'test',
85
+ '.github',
86
+ 'node_modules',
87
+ 'site',
88
+ 'docs/assets',
89
+ 'docs/javascripts',
90
+ 'docs/stylesheets',
91
+ 'CODE_OF_CONDUCT.md',
92
+ 'CONTRIBUTING.md',
93
+ 'SECURITY.md',
94
+ 'LICENSE',
95
+ 'README.md',
96
+ '.prettierrc',
97
+ '.prettierignore',
98
+ 'eslint.config.js',
99
+ 'package-lock.json',
100
+ ];
101
+ for (const name of devOnly) {
102
+ assert.ok(!fs.existsSync(path.join(OUTPUT, name)), `${name} should be stripped`);
103
+ }
104
+ cleanup();
105
+ });
106
+
73
107
  it('fails if target directory already exists', () => {
74
108
  fs.mkdirSync(OUTPUT, { recursive: true });
75
109
  assert.throws(() => run(OUTPUT), /already exists/);
@@ -113,14 +147,16 @@ describe('create-lore', () => {
113
147
  if (!fs.existsSync(path.join(TEMPLATE, '.opencode/plugins'))) return;
114
148
 
115
149
  run(OUTPUT);
116
- assert.ok(fs.existsSync(path.join(OUTPUT, '.opencode', 'plugins', 'session-init.js')),
117
- 'session-init.js copied');
118
- assert.ok(fs.existsSync(path.join(OUTPUT, '.opencode', 'plugins', 'knowledge-tracker.js')),
119
- 'knowledge-tracker.js copied');
120
- assert.ok(fs.existsSync(path.join(OUTPUT, '.opencode', 'plugins', 'protect-memory.js')),
121
- 'protect-memory.js copied');
122
- assert.ok(fs.existsSync(path.join(OUTPUT, '.opencode', 'package.json')),
123
- '.opencode/package.json copied');
150
+ assert.ok(fs.existsSync(path.join(OUTPUT, '.opencode', 'plugins', 'session-init.js')), 'session-init.js copied');
151
+ assert.ok(
152
+ fs.existsSync(path.join(OUTPUT, '.opencode', 'plugins', 'knowledge-tracker.js')),
153
+ 'knowledge-tracker.js copied',
154
+ );
155
+ assert.ok(
156
+ fs.existsSync(path.join(OUTPUT, '.opencode', 'plugins', 'protect-memory.js')),
157
+ 'protect-memory.js copied',
158
+ );
159
+ assert.ok(fs.existsSync(path.join(OUTPUT, '.opencode', 'package.json')), '.opencode/package.json copied');
124
160
  cleanup();
125
161
  });
126
162
 
@@ -135,10 +171,10 @@ describe('create-lore', () => {
135
171
  });
136
172
 
137
173
  it('passes validate-consistency.sh when template provides it', () => {
138
- if (!fs.existsSync(path.join(TEMPLATE, 'scripts/validate-consistency.sh'))) return;
174
+ if (!fs.existsSync(path.join(TEMPLATE, '.lore/scripts/validate-consistency.sh'))) return;
139
175
 
140
176
  run(OUTPUT);
141
- const result = execSync('bash scripts/validate-consistency.sh', {
177
+ const result = execSync('bash .lore/scripts/validate-consistency.sh', {
142
178
  cwd: OUTPUT,
143
179
  encoding: 'utf8',
144
180
  stdio: 'pipe',