create-lore 0.8.0 → 0.9.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/.gitattributes ADDED
@@ -0,0 +1,2 @@
1
+ # Force LF line endings everywhere — prevents CRLF issues on Windows.
2
+ * text=auto eol=lf
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something isn't working as expected
4
+ labels: bug
5
+ ---
6
+
7
+ **What happened?**
8
+
9
+ A clear description of the bug.
10
+
11
+ **Steps to reproduce**
12
+
13
+ 1. ...
14
+ 2. ...
15
+
16
+ **Expected behavior**
17
+
18
+ What should have happened instead.
19
+
20
+ **Environment**
21
+
22
+ - OS:
23
+ - Node version:
24
+ - create-lore version:
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an improvement or new capability
4
+ labels: enhancement
5
+ ---
6
+
7
+ **What problem does this solve?**
8
+
9
+ Describe the use case or pain point.
10
+
11
+ **Proposed solution**
12
+
13
+ How you'd like it to work.
14
+
15
+ **Alternatives considered**
16
+
17
+ Any workarounds or other approaches you've tried.
@@ -0,0 +1,75 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ['v*']
6
+
7
+ permissions:
8
+ contents: write
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ${{ matrix.os }}
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ os: [ubuntu-latest, macos-latest, windows-latest]
17
+ node-version: [18, 20]
18
+ steps:
19
+ - uses: actions/checkout@v4 # checkout create-lore (this repo)
20
+ - uses: actions/checkout@v4 # checkout lore template at matching tag
21
+ with:
22
+ repository: lorehq/lore
23
+ ref: ${{ github.ref_name }}
24
+ path: lore
25
+ - uses: actions/setup-node@v4
26
+ with:
27
+ node-version: ${{ matrix.node-version }}
28
+ - run: npm test
29
+ env:
30
+ LORE_TEMPLATE: ${{ github.workspace }}/lore
31
+
32
+ verify-tag:
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - name: Verify tag matches package.json version
37
+ run: |
38
+ tag="${GITHUB_REF#refs/tags/v}"
39
+ pkg="$(node -p "require('./package.json').version")"
40
+ if [[ "$tag" != "$pkg" ]]; then
41
+ echo "::error::Tag v$tag does not match package.json version $pkg"
42
+ exit 1
43
+ fi
44
+ echo "Tag v$tag matches package.json"
45
+ - name: Verify matching lore tag exists
46
+ run: |
47
+ tag="${GITHUB_REF#refs/tags/}"
48
+ if ! git ls-remote --tags https://github.com/lorehq/lore.git "refs/tags/$tag" | grep -q "$tag"; then
49
+ echo "::error::lorehq/lore does not have tag $tag — tag lore first"
50
+ exit 1
51
+ fi
52
+ echo "lorehq/lore has matching tag $tag"
53
+
54
+ publish:
55
+ needs: [test, verify-tag]
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ - uses: actions/setup-node@v4
60
+ with:
61
+ node-version: 20
62
+ registry-url: https://registry.npmjs.org
63
+ - name: Publish to npm
64
+ run: npm publish
65
+ env:
66
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
67
+ - name: Create GitHub Release
68
+ env:
69
+ GH_TOKEN: ${{ github.token }}
70
+ run: |
71
+ tag="${GITHUB_REF#refs/tags/}"
72
+ gh release delete "$tag" --yes 2>/dev/null || true
73
+ gh release create "$tag" \
74
+ --title "$tag" \
75
+ --generate-notes
@@ -0,0 +1,52 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, macos-latest, windows-latest]
16
+ node-version: [18, 20]
17
+ steps:
18
+ - uses: actions/checkout@v4 # checkout create-lore (this repo)
19
+ - uses: actions/checkout@v4 # checkout lore template (used as LORE_TEMPLATE)
20
+ with:
21
+ repository: lorehq/lore
22
+ path: lore
23
+ - uses: actions/setup-node@v4
24
+ with:
25
+ node-version: ${{ matrix.node-version }}
26
+ - run: npm test
27
+ env:
28
+ LORE_TEMPLATE: ${{ github.workspace }}/lore
29
+
30
+ e2e:
31
+ runs-on: ${{ matrix.os }}
32
+ strategy:
33
+ fail-fast: false
34
+ matrix:
35
+ os: [ubuntu-latest, macos-latest, windows-latest]
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: actions/checkout@v4
39
+ with:
40
+ repository: lorehq/lore
41
+ path: lore
42
+ - uses: actions/setup-node@v4
43
+ with:
44
+ node-version: 20
45
+ - name: Scaffold a project and validate it
46
+ shell: bash
47
+ env:
48
+ LORE_TEMPLATE: ${{ github.workspace }}/lore
49
+ run: |
50
+ node bin/create-lore.js test-project
51
+ cd test-project
52
+ bash scripts/validate-consistency.sh
@@ -0,0 +1,51 @@
1
+ # Contributing to create-lore
2
+
3
+ Thanks for your interest in contributing. `create-lore` is the CLI scaffolder for [Lore](https://github.com/lorehq/lore).
4
+
5
+ ## Dev Setup
6
+
7
+ ```bash
8
+ git clone https://github.com/lorehq/create-lore.git
9
+ cd create-lore
10
+ ```
11
+
12
+ Requires **Node.js 18+**. Zero runtime dependencies.
13
+
14
+ ## Running Tests
15
+
16
+ ```bash
17
+ npm test
18
+ ```
19
+
20
+ Tests use `LORE_TEMPLATE` env var to point at a local lore repo instead of cloning from GitHub:
21
+
22
+ ```bash
23
+ LORE_TEMPLATE=../lore npm test
24
+ ```
25
+
26
+ ## Pull Requests
27
+
28
+ 1. Fork the repo and create a branch from `main`
29
+ 2. Make your changes
30
+ 3. Run `npm test`
31
+ 4. Open a pull request
32
+
33
+ ## What We're Looking For
34
+
35
+ - Bug fixes with clear reproduction steps
36
+ - Better error messaging for common failure modes
37
+ - Test coverage improvements
38
+
39
+ ## Guidelines
40
+
41
+ - Keep changes focused — one concern per PR
42
+ - Match existing code style
43
+ - For framework changes (hooks, skills, lib), contribute to [lorehq/lore](https://github.com/lorehq/lore) instead
44
+
45
+ ## Reporting Issues
46
+
47
+ Use [GitHub Issues](../../issues). For security vulnerabilities, see [SECURITY.md](SECURITY.md).
48
+
49
+ ## License
50
+
51
+ By contributing, you agree that your contributions will be licensed under the Apache-2.0 license.
package/README.md CHANGED
@@ -1,37 +1,57 @@
1
1
  # create-lore
2
2
 
3
- Create a new [Lore](https://github.com/lorehq/lore) knowledge-persistent AI coding framework repo.
3
+ Bootstrap a new [Lore](https://github.com/lorehq/lore) project — persistent memory for AI coding agents.
4
4
 
5
- ## Usage
5
+ ## The Problem
6
+
7
+ AI coding agents (Claude Code, Cursor, OpenCode) forget everything between sessions. Every session you re-explain project structure, re-discover API quirks, and repeat lessons learned yesterday. Lore fixes that.
8
+
9
+ ## What Lore Does
10
+
11
+ Lore wraps your coding agent in a git-versioned knowledge base. Hooks fire automatically to reinforce knowledge capture as you work. Gotchas become skills, and every future session starts with what previous sessions learned. Complex work delegates to focused workers loaded with curated skills.
12
+
13
+ - **Skills** — API quirks, auth gotchas, encoding tricks. Captured once, loaded forever.
14
+ - **Knowledge docs** — Environment details, runbooks, architecture decisions. Accumulated across sessions.
15
+ - **Work tracking** — Roadmaps, plans, and brainstorms that persist and appear in every session banner.
16
+ - **Hooks** — Session init, capture reminders, memory protection. All automatic.
17
+
18
+ ## Quick Start
6
19
 
7
20
  ```bash
8
- npx create-lore myproject
21
+ npx create-lore my-project
22
+ cd my-project
23
+ git add -A && git commit -m "Init Lore"
9
24
  ```
10
25
 
11
- This creates `lore-myproject/` with the full Lore framework hooks, skills, scripts, and operating instructions that teach Claude Code to learn and remember across sessions.
26
+ Then open the project in your agent. Hooks fire automatically.
12
27
 
13
- ## What you get
28
+ ## Supported Platforms
14
29
 
15
- - **AGENTS.md / CLAUDE.md** — Operating instructions Claude Code reads automatically
16
- - **Hooks** — Session init, memory guard, post-action capture reminders
17
- - **Skills** `create-skill` and `create-agent` for building your knowledge base
18
- - **Scripts** Registry generation, agent generation, consistency validation
30
+ | Platform | Integration |
31
+ |----------|-------------|
32
+ | Claude Code | `hooks/` + `CLAUDE.md` |
33
+ | Cursor | `.cursor/hooks/` + `.cursor/mcp/` + `.cursor/rules/` |
34
+ | OpenCode | `.opencode/plugins/` + `opencode.json` |
35
+
36
+ All platforms share the same knowledge base. No configuration needed.
19
37
 
20
38
  ## Options
21
39
 
22
40
  ```bash
23
- npx create-lore myproject # creates ./lore-myproject/
24
- npx create-lore ./custom-path # creates at specific path
41
+ npx create-lore my-project # creates ./my-project/
42
+ npx create-lore ./custom-path # creates at specific path
43
+ npx create-lore --help # show usage
44
+ npx create-lore --version # show version
25
45
  ```
26
46
 
27
- ## After setup
47
+ ## Requirements
28
48
 
29
- ```bash
30
- cd lore-myproject
31
- git add -A && git commit -m "Init Lore"
32
- ```
49
+ - Node.js 18+
50
+ - git
51
+
52
+ ## Docs
33
53
 
34
- Then open Claude Code in the project. The hooks will fire automatically and the self-learning loop begins.
54
+ Full documentation: [lorehq.github.io/lore-docs](https://lorehq.github.io/lore-docs/)
35
55
 
36
56
  ## License
37
57
 
package/SECURITY.md ADDED
@@ -0,0 +1,24 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ If you discover a security vulnerability, please report it responsibly:
6
+
7
+ 1. **Do not** open a public GitHub issue
8
+ 2. Email the maintainers or use [GitHub's private vulnerability reporting](../../security/advisories/new)
9
+ 3. Include steps to reproduce and potential impact
10
+
11
+ We will acknowledge receipt within 48 hours and provide a timeline for a fix.
12
+
13
+ ## Scope
14
+
15
+ `create-lore` is a CLI scaffolder that clones a template repo and initializes a new project. Security concerns are primarily:
16
+
17
+ - Shell command execution during project scaffolding (`git clone`, `git init`)
18
+ - Template integrity (clones from a pinned version tag on GitHub)
19
+
20
+ ## Supported Versions
21
+
22
+ | Version | Supported |
23
+ |---------|-----------|
24
+ | 0.8.x | Yes |
@@ -18,9 +18,25 @@ const fs = require('fs');
18
18
  const path = require('path');
19
19
 
20
20
  const REPO_URL = 'https://github.com/lorehq/lore.git';
21
+ const pkg = require('../package.json');
21
22
 
22
23
  // -- Parse arguments --
23
- const name = process.argv[2];
24
+ const arg = process.argv[2];
25
+ if (arg === '--help' || arg === '-h') {
26
+ console.log(`create-lore v${pkg.version}\n`);
27
+ console.log('Usage: create-lore <name|path>\n');
28
+ console.log('Bootstrap a new Lore knowledge-persistent agent repo.\n');
29
+ console.log('Examples:');
30
+ console.log(' npx create-lore myproject # creates ./myproject/');
31
+ console.log(' npx create-lore ./custom-path # creates at specific path');
32
+ process.exit(0);
33
+ }
34
+ if (arg === '--version' || arg === '-v') {
35
+ console.log(pkg.version);
36
+ process.exit(0);
37
+ }
38
+
39
+ const name = arg;
24
40
  if (!name) {
25
41
  console.error('Usage: create-lore <name>');
26
42
  process.exit(1);
@@ -31,6 +47,25 @@ if (!name) {
31
47
  const isPath = name.includes('/') || name.includes(path.sep);
32
48
  const targetDir = path.resolve(isPath ? name : `./${name}`);
33
49
 
50
+ // Validate every segment of the resolved path's tail (the parts the user controls).
51
+ // For simple names, validate the name directly. For paths, validate the basename.
52
+ // This prevents shell-hostile characters like ; | & $ ` from sneaking through.
53
+ const segmentPattern = /^[a-zA-Z0-9._-]+$/;
54
+ const finalName = path.basename(targetDir);
55
+ if (!segmentPattern.test(finalName)) {
56
+ console.error(`Error: Invalid project name '${finalName}'`);
57
+ console.error('Names may contain letters, numbers, dots, hyphens, and underscores.');
58
+ process.exit(1);
59
+ }
60
+
61
+ // Guard against path traversal — resolved target must be under cwd
62
+ const cwd = process.cwd();
63
+ if (!targetDir.startsWith(cwd + path.sep) && targetDir !== cwd) {
64
+ console.error(`Error: Target directory '${targetDir}' is outside the current working directory.`);
65
+ console.error('Use a relative name or path within the current directory.');
66
+ process.exit(1);
67
+ }
68
+
34
69
  if (fs.existsSync(targetDir)) {
35
70
  console.error(`Error: ${targetDir} already exists`);
36
71
  process.exit(1);
@@ -45,7 +80,23 @@ try {
45
80
  if (templateDir) {
46
81
  fs.cpSync(templateDir, tmpDir, { recursive: true });
47
82
  } else {
48
- execSync(`git clone --depth 1 ${REPO_URL} "${tmpDir}"`, { stdio: 'pipe' });
83
+ try {
84
+ execSync(`git clone --depth 1 --branch v${pkg.version} ${REPO_URL} "${tmpDir}"`, { stdio: 'pipe' });
85
+ } catch (err) {
86
+ const stderr = err.stderr ? err.stderr.toString() : '';
87
+ if (stderr.includes('not found') || stderr.includes('not a valid')) {
88
+ console.error(`Error: Version tag v${pkg.version} not found in ${REPO_URL}`);
89
+ console.error('This usually means the release tag is missing. Try:');
90
+ console.error(' npx create-lore@latest ' + name);
91
+ } else if (stderr.includes('Could not resolve host') || stderr.includes('unable to access')) {
92
+ console.error('Error: Cannot reach github.com');
93
+ console.error('Check your internet connection, DNS, and firewall/proxy settings.');
94
+ } else {
95
+ console.error('Error: Failed to clone template from GitHub');
96
+ console.error(stderr.trim() || err.message);
97
+ }
98
+ process.exit(1);
99
+ }
49
100
  }
50
101
  fs.rmSync(path.join(tmpDir, '.git'), { recursive: true, force: true });
51
102
  fs.cpSync(tmpDir, targetDir, { recursive: true });
@@ -57,7 +108,12 @@ try {
57
108
  // -- Write .lore-config --
58
109
  const projectName = isPath ? path.basename(targetDir) : name;
59
110
  // Read version from the template's .lore-config so instances track their source version
60
- const templateConfig = JSON.parse(fs.readFileSync(path.join(targetDir, '.lore-config'), 'utf8'));
111
+ let templateConfig;
112
+ try {
113
+ templateConfig = JSON.parse(fs.readFileSync(path.join(targetDir, '.lore-config'), 'utf8'));
114
+ } catch (e) {
115
+ templateConfig = {};
116
+ }
61
117
  const config = {
62
118
  name: projectName,
63
119
  version: templateConfig.version || '0.0.0',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-lore",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Create a new Lore knowledge-persistent agent repo",
5
5
  "bin": {
6
6
  "create-lore": "bin/create-lore.js"
@@ -8,7 +8,12 @@
8
8
  "scripts": {
9
9
  "test": "node --test test/create-lore.test.js"
10
10
  },
11
- "keywords": ["lore", "agent", "ai", "knowledge"],
11
+ "keywords": [
12
+ "lore",
13
+ "agent",
14
+ "ai",
15
+ "knowledge"
16
+ ],
12
17
  "license": "Apache-2.0",
13
18
  "engines": {
14
19
  "node": ">=18"
@@ -9,7 +9,7 @@ const fs = require('fs');
9
9
  const path = require('path');
10
10
 
11
11
  const BIN = path.resolve(__dirname, '../bin/create-lore.js');
12
- const TEMPLATE = path.resolve(__dirname, '../../lore'); // Sibling lore repo
12
+ const TEMPLATE = process.env.LORE_TEMPLATE || path.resolve(__dirname, '../../lore');
13
13
  const OUTPUT = path.resolve(__dirname, '../test-output');
14
14
 
15
15
  // Run the installer with LORE_TEMPLATE pointing at the local template
@@ -21,6 +21,15 @@ function run(args = '') {
21
21
  });
22
22
  }
23
23
 
24
+ // Run with exact argv (no shell interpretation) — for testing shell metacharacters
25
+ function runExact(name) {
26
+ return require('child_process').execFileSync('node', [BIN, name], {
27
+ env: { ...process.env, LORE_TEMPLATE: TEMPLATE },
28
+ stdio: 'pipe',
29
+ encoding: 'utf8',
30
+ });
31
+ }
32
+
24
33
  function cleanup() {
25
34
  if (fs.existsSync(OUTPUT)) fs.rmSync(OUTPUT, { recursive: true });
26
35
  }
@@ -29,6 +38,18 @@ describe('create-lore', () => {
29
38
  before(cleanup);
30
39
  after(cleanup);
31
40
 
41
+ it('--help shows usage text', () => {
42
+ const output = run('--help');
43
+ assert.ok(output.includes('Usage:'), 'shows usage');
44
+ assert.ok(output.includes('create-lore'), 'mentions create-lore');
45
+ });
46
+
47
+ it('--version outputs package.json version', () => {
48
+ const output = run('--version');
49
+ const pkg = require('../package.json');
50
+ assert.equal(output.trim(), pkg.version);
51
+ });
52
+
32
53
  it('exits with error when no name given', () => {
33
54
  assert.throws(() => run(''), { status: 1 });
34
55
  });
@@ -55,6 +76,17 @@ describe('create-lore', () => {
55
76
  fs.rmSync(OUTPUT, { recursive: true });
56
77
  });
57
78
 
79
+ it('rejects names with shell metacharacters', () => {
80
+ assert.throws(() => runExact('foo;echo pwned'), /Invalid project name/);
81
+ assert.throws(() => runExact('foo$(cmd)'), /Invalid project name/);
82
+ assert.throws(() => runExact('foo|bar'), /Invalid project name/);
83
+ });
84
+
85
+ it('rejects path arguments with shell metacharacters in basename', () => {
86
+ assert.throws(() => runExact('./foo;rm'), /Invalid project name/);
87
+ assert.throws(() => runExact('/tmp/bad$(cmd)'), /Invalid project name/);
88
+ });
89
+
58
90
  // -- Template content tests --
59
91
  // These skip gracefully if the template hasn't reached that phase yet.
60
92