create-lore 0.9.0 → 0.10.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
@@ -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.
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
 
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.10.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,66 @@ 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
+ '.gitattributes',
113
+ '.gitignore',
114
+ ]);
115
+ for (const entry of fs.readdirSync(tmpDir)) {
116
+ if (!keep.has(entry)) {
117
+ fs.rmSync(path.join(tmpDir, entry), { recursive: true, force: true });
118
+ }
119
+ }
120
+
102
121
  fs.cpSync(tmpDir, targetDir, { recursive: true });
103
122
  } finally {
104
123
  // Always clean up the temp dir
105
124
  if (fs.existsSync(tmpDir)) fs.rmSync(tmpDir, { recursive: true });
106
125
  }
107
126
 
108
- // -- Write .lore-config --
127
+ // -- Write .lore/config.json --
109
128
  const projectName = isPath ? path.basename(targetDir) : name;
110
- // Read version from the template's .lore-config so instances track their source version
129
+ // Read version from the copied config.json, then rewrite from template
111
130
  let templateConfig;
112
131
  try {
113
- templateConfig = JSON.parse(fs.readFileSync(path.join(targetDir, '.lore-config'), 'utf8'));
114
- } catch (e) {
132
+ templateConfig = JSON.parse(fs.readFileSync(path.join(targetDir, '.lore', 'config.json'), 'utf8'));
133
+ } catch {
115
134
  templateConfig = {};
116
135
  }
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');
136
+ const templateVersion = templateConfig.version || '0.0.0';
137
+ const createdDate = new Date().toISOString().split('T')[0];
138
+ const configTemplate = fs.readFileSync(path.join(targetDir, '.lore', 'templates', 'config.json'), 'utf8');
139
+ const configContent = configTemplate
140
+ .replace('{{name}}', projectName)
141
+ .replace('{{version}}', templateVersion)
142
+ .replace('{{created}}', createdDate);
143
+ fs.writeFileSync(path.join(targetDir, '.lore', 'config.json'), configContent);
144
+
145
+ // -- Create gitignored files from templates --
146
+ // Templates are already in targetDir (copied from the template clone via .lore/).
147
+ // These are normally recreated by ensureStickyFiles() each session, but the
148
+ // installer should produce a complete instance from the start.
149
+ const tplDir = path.join(targetDir, '.lore', 'templates');
150
+ const localDir = path.join(targetDir, 'docs', 'knowledge', 'local');
151
+ fs.mkdirSync(localDir, { recursive: true });
152
+
153
+ fs.writeFileSync(path.join(localDir, 'index.md'), fs.readFileSync(path.join(tplDir, 'local-index.md'), 'utf8'));
154
+ fs.writeFileSync(
155
+ path.join(localDir, 'operator-profile.md'),
156
+ fs.readFileSync(path.join(tplDir, 'operator-profile.md'), 'utf8'),
157
+ );
158
+ fs.writeFileSync(
159
+ path.join(targetDir, '.lore', 'memory.local.md'),
160
+ fs.readFileSync(path.join(tplDir, 'memory-local.md'), 'utf8'),
161
+ );
123
162
 
124
163
  // -- Initialize git --
125
164
  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.10.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',