openclew 0.2.1 → 0.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/README.md +5 -1
- package/UPGRADING.md +167 -0
- package/bin/openclew.js +46 -18
- package/lib/index-gen.js +100 -25
- package/lib/init.js +42 -31
- package/lib/inject.js +16 -7
- package/lib/mcp-server.js +313 -0
- package/lib/new-doc.js +12 -4
- package/lib/new-log.js +4 -4
- package/lib/search.js +242 -0
- package/lib/status.js +151 -0
- package/lib/templates.js +193 -13
- package/package.json +24 -3
- package/skills/openclew-checkpoint/SKILL.md +36 -0
- package/skills/openclew-init/SKILL.md +49 -0
- package/skills/openclew-search/SKILL.md +45 -0
- package/templates/FORMAT.md +299 -0
- package/templates/log.md +1 -1
- package/templates/onboarding/flow.md +59 -0
- package/templates/onboarding/scaffold_index.md +31 -0
- package/templates/refdoc.md +1 -1
- package/hooks/generate-index.py +0 -226
package/README.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/openclew/openclew/main/assets/logo.png" alt="openclew" width="200">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# openclew
|
|
2
6
|
|
|
3
7
|
> Long Life Memory for LLMs
|
|
@@ -114,7 +118,7 @@ The index auto-regenerates on every commit. Never edit it manually.
|
|
|
114
118
|
1. Create `doc/` and `doc/log/`
|
|
115
119
|
2. Copy templates from [`templates/`](templates/) (refdoc.md, log.md)
|
|
116
120
|
3. Add the openclew block to your instruction file (see `doc/_USING_OPENCLEW.md` after init for the exact format)
|
|
117
|
-
4.
|
|
121
|
+
4. Run `openclew index` to generate `doc/_INDEX.md` (or wire it as a pre-commit hook)
|
|
118
122
|
|
|
119
123
|
</details>
|
|
120
124
|
|
package/UPGRADING.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Upgrading openclew
|
|
2
|
+
|
|
3
|
+
openclew evolves. When the format changes, your existing docs still work — parsers
|
|
4
|
+
are backward-compatible. But new features expect the current format.
|
|
5
|
+
|
|
6
|
+
`openclew migrate` bridges the gap.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Quick version
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install -g openclew@latest # or: npx openclew@latest
|
|
14
|
+
openclew status # shows legacy doc count
|
|
15
|
+
openclew migrate # dry-run: what would change
|
|
16
|
+
openclew migrate --write # apply
|
|
17
|
+
git diff # review
|
|
18
|
+
git add doc/ && git commit -m "chore: migrate docs to openclew format"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## When to upgrade
|
|
24
|
+
|
|
25
|
+
After updating openclew, run `openclew status`. If it reports legacy docs,
|
|
26
|
+
run `openclew migrate` to see what needs changing.
|
|
27
|
+
|
|
28
|
+
You can also check directly:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
openclew migrate
|
|
32
|
+
# → 12 to migrate, 45 already current, 0 errors (57 total)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
No output = nothing to do.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## How it works
|
|
40
|
+
|
|
41
|
+
`migrate` converts docs from older formats to the current openclew format.
|
|
42
|
+
It is **safe by default**:
|
|
43
|
+
|
|
44
|
+
- **Dry-run first** — shows what would change without touching files
|
|
45
|
+
- **`--write` to apply** — only modifies files when you explicitly ask
|
|
46
|
+
- **Git-friendly** — files are tracked, `git diff` shows exactly what changed
|
|
47
|
+
- **Idempotent** — running it twice produces the same result
|
|
48
|
+
- **Skips current docs** — only touches files that need updating
|
|
49
|
+
|
|
50
|
+
### What it converts
|
|
51
|
+
|
|
52
|
+
| Before | After |
|
|
53
|
+
|--------|-------|
|
|
54
|
+
| `R.AlphA.Doc@7.0.0` (line 1) | `openclew@0.3.0 · created: ... · type: ... · ...` |
|
|
55
|
+
| `subject: Title` (plain L1) | `**subject:** Title` (bold L1) |
|
|
56
|
+
| `summary: ...` | `**doc_brief:** ...` |
|
|
57
|
+
| `# 📋 L1 · Métadonnées` | _(removed — metadata is on line 1)_ |
|
|
58
|
+
| `# 📝 L2 · Résumé` | `# L2 - Summary` |
|
|
59
|
+
| `# 🔧 L3 · Détails` | `# L3 - Details` |
|
|
60
|
+
| YAML frontmatter (`---`) | Replaced by line 1 + L1 block |
|
|
61
|
+
| `status: Vivant` | `status: Active` |
|
|
62
|
+
| `status: Terminé` | `status: Done` |
|
|
63
|
+
|
|
64
|
+
### What it does NOT change
|
|
65
|
+
|
|
66
|
+
- **L2/L3 body content** — only headers are normalized, your content is untouched
|
|
67
|
+
- **Sub-headers** — `## Objective`, `## Key points` etc. are preserved as-is
|
|
68
|
+
- **`related_docs` paths** — kept on line 1 but not repointed if you move files
|
|
69
|
+
- **Files already in openclew format** — skipped entirely
|
|
70
|
+
- **`_INDEX.md`** — auto-generated, never touched
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Step by step
|
|
75
|
+
|
|
76
|
+
### 1. Update openclew
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm install -g openclew@latest
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. Check your docs
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
openclew status
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Look for the "Legacy format" line. If it says 0, you're done.
|
|
89
|
+
|
|
90
|
+
### 3. Preview changes
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
openclew migrate
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
This lists every file that would be converted. No files are modified.
|
|
97
|
+
|
|
98
|
+
### 4. Apply
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
openclew migrate --write
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Each converted file is printed with `✓`.
|
|
105
|
+
|
|
106
|
+
### 5. Review and commit
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git diff # inspect the changes
|
|
110
|
+
openclew index # regenerate the index
|
|
111
|
+
git add doc/ && git commit -m "chore: migrate docs to openclew format"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 6. Verify
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
openclew status # should show 0 legacy docs
|
|
118
|
+
openclew migrate # should show "0 to migrate"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## After migrating
|
|
124
|
+
|
|
125
|
+
- **New docs** you create with `openclew add ref` / `openclew add log` already
|
|
126
|
+
use the current format. No action needed.
|
|
127
|
+
- **Docs created by AI agents** will follow the format they see in your codebase.
|
|
128
|
+
Once your existing docs are migrated, agents will generate in the new format.
|
|
129
|
+
- **Empty `doc_brief`** — some old docs may have no brief after migration.
|
|
130
|
+
Run `openclew status` to find them and fill them in.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Version-specific notes
|
|
135
|
+
|
|
136
|
+
### → 0.4.0 (format migration)
|
|
137
|
+
|
|
138
|
+
First migration release. Converts from the legacy format (YAML frontmatter,
|
|
139
|
+
plain `key: value` L1, emoji headers) to the openclew format (condensed line 1,
|
|
140
|
+
bold L1 fields, clean headers).
|
|
141
|
+
|
|
142
|
+
**Scope**: line 1 + L1 block + L2/L3 main headers.
|
|
143
|
+
|
|
144
|
+
**Not in scope**: sub-header emojis, `related_docs` repointing, recursive
|
|
145
|
+
`doc/` subdirectory scanning (refdocs must be in `doc/_*.md`, not `doc/ref/`).
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Limitations
|
|
150
|
+
|
|
151
|
+
### Flat `doc/` structure required
|
|
152
|
+
|
|
153
|
+
All openclew tools (search, index, status, migrate) scan `doc/_*.md` for refdocs
|
|
154
|
+
and `doc/log/*.md` for logs. Subdirectories like `doc/ref/` are not scanned yet.
|
|
155
|
+
|
|
156
|
+
If you plan to reorganize into subdirectories, wait for recursive scan support
|
|
157
|
+
(tracked in the openclew roadmap).
|
|
158
|
+
|
|
159
|
+
### `related_docs` are not repointed
|
|
160
|
+
|
|
161
|
+
If a doc references `related_docs: [doc/_AUTH.md]` and you rename that file,
|
|
162
|
+
the reference breaks. `migrate` preserves paths as-is — manual update required.
|
|
163
|
+
|
|
164
|
+
### Parsers are backward-compatible
|
|
165
|
+
|
|
166
|
+
Even without migrating, your docs are still readable by openclew tools.
|
|
167
|
+
Migration improves consistency and enables new features, but is not blocking.
|
package/bin/openclew.js
CHANGED
|
@@ -9,39 +9,67 @@ const USAGE = `
|
|
|
9
9
|
openclew — Long Life Memory for LLMs
|
|
10
10
|
|
|
11
11
|
Usage:
|
|
12
|
-
openclew init Set up openclew in
|
|
13
|
-
openclew
|
|
14
|
-
openclew log <title>
|
|
15
|
-
openclew
|
|
16
|
-
openclew
|
|
17
|
-
openclew help Show this help
|
|
12
|
+
openclew init Set up openclew in your project
|
|
13
|
+
openclew add ref <title> Create a refdoc (evolves with the project)
|
|
14
|
+
openclew add log <title> Create a session log (frozen facts)
|
|
15
|
+
openclew search <query> Search docs by keyword
|
|
16
|
+
openclew checkout End-of-session summary
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
Run 'openclew help --all' for advanced commands.
|
|
19
|
+
More at: https://github.com/openclew/openclew
|
|
20
|
+
`.trim();
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
# Edit doc/_ARCHITECTURE.md 2. Replace the example with your project's architecture
|
|
26
|
-
openclew new "API design" 3. Create your own refdocs
|
|
27
|
-
git commit 4. Index auto-regenerates on commit
|
|
22
|
+
const USAGE_ALL = `
|
|
23
|
+
openclew — Long Life Memory for LLMs
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
Usage:
|
|
26
|
+
openclew init Set up openclew in your project
|
|
27
|
+
openclew add ref <title> Create a refdoc (evolves with the project)
|
|
28
|
+
openclew add log <title> Create a session log (frozen facts)
|
|
29
|
+
openclew search <query> Search docs by keyword
|
|
30
|
+
openclew checkout End-of-session summary
|
|
31
|
+
|
|
32
|
+
Advanced:
|
|
33
|
+
openclew status Documentation health dashboard
|
|
34
|
+
openclew index Regenerate doc/_INDEX.md
|
|
35
|
+
openclew mcp Start MCP server (stdio JSON-RPC)
|
|
36
|
+
|
|
37
|
+
Options (init):
|
|
38
|
+
--no-hook Skip pre-commit hook installation
|
|
39
|
+
--no-inject Skip instruction file injection
|
|
32
40
|
`.trim();
|
|
33
41
|
|
|
34
42
|
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
35
|
-
|
|
43
|
+
const showAll = args.includes("--all");
|
|
44
|
+
console.log(showAll ? USAGE_ALL : USAGE);
|
|
45
|
+
process.exit(0);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Handle "add ref" / "add log" subcommands
|
|
49
|
+
if (command === "add") {
|
|
50
|
+
const sub = args[1];
|
|
51
|
+
if (sub === "ref") {
|
|
52
|
+
require("../lib/new-doc");
|
|
53
|
+
} else if (sub === "log") {
|
|
54
|
+
require("../lib/new-log");
|
|
55
|
+
} else {
|
|
56
|
+
console.error(`Unknown type: ${sub || "(none)"}`);
|
|
57
|
+
console.error('Usage: openclew add ref <title> or openclew add log <title>');
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
36
60
|
process.exit(0);
|
|
37
61
|
}
|
|
38
62
|
|
|
63
|
+
// Legacy aliases
|
|
39
64
|
const commands = {
|
|
40
65
|
init: () => require("../lib/init"),
|
|
41
66
|
new: () => require("../lib/new-doc"),
|
|
42
67
|
log: () => require("../lib/new-log"),
|
|
43
68
|
checkout: () => require("../lib/checkout"),
|
|
69
|
+
search: () => require("../lib/search"),
|
|
70
|
+
status: () => require("../lib/status"),
|
|
44
71
|
index: () => require("../lib/index-gen"),
|
|
72
|
+
mcp: () => require("../lib/mcp-server"),
|
|
45
73
|
};
|
|
46
74
|
|
|
47
75
|
if (!commands[command]) {
|
package/lib/index-gen.js
CHANGED
|
@@ -1,40 +1,115 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* openclew index — regenerate doc/_INDEX.md
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Pure JS implementation. Reuses parsers from search.js (SSOT).
|
|
5
|
+
* Zero dependencies — Node 16+ standard library only.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const { execSync } = require("child_process");
|
|
9
8
|
const fs = require("fs");
|
|
10
9
|
const path = require("path");
|
|
10
|
+
const { collectDocs } = require("./search");
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Generate _INDEX.md content from parsed docs.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} docDir - Absolute path to doc/ directory
|
|
16
|
+
* @returns {string} Generated index content
|
|
17
|
+
*/
|
|
18
|
+
function generateIndex(docDir) {
|
|
19
|
+
const docs = collectDocs(docDir);
|
|
20
|
+
const refdocs = docs.filter((d) => d.kind === "refdoc");
|
|
21
|
+
const logs = docs.filter((d) => d.kind === "log");
|
|
22
|
+
|
|
23
|
+
const now = new Date();
|
|
24
|
+
const timestamp = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")} ${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;
|
|
25
|
+
|
|
26
|
+
const lines = [
|
|
27
|
+
"# Project Knowledge Index",
|
|
28
|
+
"",
|
|
29
|
+
`> Auto-generated by [openclew](https://github.com/openclew/openclew) on ${timestamp}.`,
|
|
30
|
+
"> Do not edit manually — rebuilt from L1 metadata on every commit.",
|
|
31
|
+
"",
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
// Refdocs section
|
|
35
|
+
lines.push("## Refdocs");
|
|
36
|
+
lines.push("");
|
|
37
|
+
if (refdocs.length) {
|
|
38
|
+
lines.push("| Document | Subject | Status | Category |");
|
|
39
|
+
lines.push("|----------|---------|--------|----------|");
|
|
40
|
+
for (const doc of refdocs) {
|
|
41
|
+
const name = path.basename(doc.filepath);
|
|
42
|
+
const subject = doc.meta.subject || "—";
|
|
43
|
+
const status = doc.meta.status || "—";
|
|
44
|
+
const category = doc.meta.category || "—";
|
|
45
|
+
const relPath = path.relative(path.dirname(docDir), doc.filepath);
|
|
46
|
+
lines.push(`| [${name}](${relPath}) | ${subject} | ${status} | ${category} |`);
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
lines.push("_No refdocs yet. Create one with `npx openclew add ref \"Title\"`._");
|
|
50
|
+
}
|
|
51
|
+
lines.push("");
|
|
52
|
+
|
|
53
|
+
// Logs section (last 20)
|
|
54
|
+
const displayLogs = logs.slice(0, 20);
|
|
55
|
+
lines.push("## Recent logs");
|
|
56
|
+
lines.push("");
|
|
57
|
+
if (displayLogs.length) {
|
|
58
|
+
lines.push("| Date | Subject | Status | Category |");
|
|
59
|
+
lines.push("|------|---------|--------|----------|");
|
|
60
|
+
for (const doc of displayLogs) {
|
|
61
|
+
const date = doc.meta.date || path.basename(doc.filepath).slice(0, 10);
|
|
62
|
+
const subject = doc.meta.subject || "—";
|
|
63
|
+
const status = doc.meta.status || "—";
|
|
64
|
+
const category = doc.meta.category || "—";
|
|
65
|
+
const relPath = path.relative(path.dirname(docDir), doc.filepath);
|
|
66
|
+
lines.push(`| ${date} | [${subject}](${relPath}) | ${status} | ${category} |`);
|
|
67
|
+
}
|
|
68
|
+
if (logs.length > 20) {
|
|
69
|
+
lines.push("");
|
|
70
|
+
lines.push(`_${logs.length - 20} older logs not shown._`);
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
lines.push("_No logs yet. Create one with `npx openclew add log \"Title\"`._");
|
|
74
|
+
}
|
|
75
|
+
lines.push("");
|
|
13
76
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
77
|
+
// Stats
|
|
78
|
+
lines.push("---");
|
|
79
|
+
lines.push(`**${refdocs.length}** refdocs, **${logs.length}** logs.`);
|
|
80
|
+
lines.push("");
|
|
81
|
+
|
|
82
|
+
return lines.join("\n");
|
|
17
83
|
}
|
|
18
84
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Write _INDEX.md to disk.
|
|
87
|
+
*
|
|
88
|
+
* @param {string} docDir - Absolute path to doc/ directory
|
|
89
|
+
* @returns {{ refdocs: number, logs: number }} Counts
|
|
90
|
+
*/
|
|
91
|
+
function writeIndex(docDir) {
|
|
92
|
+
const content = generateIndex(docDir);
|
|
93
|
+
const indexPath = path.join(docDir, "_INDEX.md");
|
|
94
|
+
fs.writeFileSync(indexPath, content, "utf-8");
|
|
95
|
+
|
|
96
|
+
const docs = collectDocs(docDir);
|
|
97
|
+
const refdocs = docs.filter((d) => d.kind === "refdoc").length;
|
|
98
|
+
const logs = docs.filter((d) => d.kind === "log").length;
|
|
99
|
+
return { refdocs, logs };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// CLI runner
|
|
103
|
+
if (require.main === module || process.argv.includes("index")) {
|
|
104
|
+
const docDir = process.argv[2] || path.join(process.cwd(), "doc");
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(docDir)) {
|
|
107
|
+
console.error("No doc/ directory found. Run 'openclew init' first.");
|
|
35
108
|
process.exit(1);
|
|
36
109
|
}
|
|
110
|
+
|
|
111
|
+
const { refdocs, logs } = writeIndex(docDir);
|
|
112
|
+
console.log(`Generated doc/_INDEX.md (${refdocs} refdocs, ${logs} logs)`);
|
|
37
113
|
}
|
|
38
114
|
|
|
39
|
-
|
|
40
|
-
process.exit(1);
|
|
115
|
+
module.exports = { generateIndex, writeIndex };
|
package/lib/init.js
CHANGED
|
@@ -15,7 +15,7 @@ const readline = require("readline");
|
|
|
15
15
|
const { detectInstructionFiles, findAgentsMdCaseInsensitive } = require("./detect");
|
|
16
16
|
const { inject, isAlreadyInjected } = require("./inject");
|
|
17
17
|
const { writeConfig } = require("./config");
|
|
18
|
-
const { guideContent, exampleRefdocContent, exampleLogContent, today } = require("./templates");
|
|
18
|
+
const { guideContent, frameworkIntegrationContent, exampleRefdocContent, exampleLogContent, today } = require("./templates");
|
|
19
19
|
|
|
20
20
|
const PROJECT_ROOT = process.cwd();
|
|
21
21
|
const DOC_DIR = path.join(PROJECT_ROOT, "doc");
|
|
@@ -126,8 +126,8 @@ function installPreCommitHook() {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
const preCommitPath = path.join(hooksDir, "pre-commit");
|
|
129
|
-
const indexScript = `if
|
|
130
|
-
|
|
129
|
+
const indexScript = `if command -v npx >/dev/null 2>&1; then
|
|
130
|
+
npx --yes openclew index 2>/dev/null || echo "openclew: index generation failed"
|
|
131
131
|
git add doc/_INDEX.md 2>/dev/null
|
|
132
132
|
fi`;
|
|
133
133
|
|
|
@@ -168,26 +168,19 @@ function updateGitignore() {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
console.log(" doc/generate-index.py
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (fs.existsSync(src)) {
|
|
181
|
-
fs.copyFileSync(src, dst);
|
|
182
|
-
console.log(" Copied generate-index.py to doc/");
|
|
171
|
+
function cleanupLegacyPython() {
|
|
172
|
+
// Remove legacy generate-index.py if present (replaced by JS-native index-gen)
|
|
173
|
+
const legacyScript = path.join(DOC_DIR, "generate-index.py");
|
|
174
|
+
if (fs.existsSync(legacyScript)) {
|
|
175
|
+
fs.unlinkSync(legacyScript);
|
|
176
|
+
console.log(" Removed legacy doc/generate-index.py (now JS-native)");
|
|
183
177
|
return true;
|
|
184
178
|
}
|
|
185
|
-
|
|
186
|
-
console.log(" generate-index.py not found in package — skipping");
|
|
179
|
+
console.log(" No legacy Python script to clean up");
|
|
187
180
|
return false;
|
|
188
181
|
}
|
|
189
182
|
|
|
190
|
-
function createDocs() {
|
|
183
|
+
function createDocs(entryPointPath) {
|
|
191
184
|
// Guide — always created
|
|
192
185
|
const guidePath = path.join(DOC_DIR, "_USING_OPENCLEW.md");
|
|
193
186
|
if (!fs.existsSync(guidePath)) {
|
|
@@ -197,11 +190,30 @@ function createDocs() {
|
|
|
197
190
|
console.log(" doc/_USING_OPENCLEW.md already exists");
|
|
198
191
|
}
|
|
199
192
|
|
|
200
|
-
//
|
|
193
|
+
// Framework integration guide
|
|
194
|
+
const frameworkPath = path.join(DOC_DIR, "_OPENCLEW_FRAMEWORK_INTEGRATION.md");
|
|
195
|
+
if (!fs.existsSync(frameworkPath)) {
|
|
196
|
+
fs.writeFileSync(frameworkPath, frameworkIntegrationContent(), "utf-8");
|
|
197
|
+
console.log(" Created doc/_OPENCLEW_FRAMEWORK_INTEGRATION.md (framework integration guide)");
|
|
198
|
+
} else {
|
|
199
|
+
console.log(" doc/_OPENCLEW_FRAMEWORK_INTEGRATION.md already exists");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Architecture refdoc — seeded from existing instruction file if available
|
|
201
203
|
const examplePath = path.join(DOC_DIR, "_ARCHITECTURE.md");
|
|
202
204
|
if (!fs.existsSync(examplePath)) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
+
let existingInstructions = null;
|
|
206
|
+
if (entryPointPath && fs.existsSync(entryPointPath)) {
|
|
207
|
+
try {
|
|
208
|
+
existingInstructions = fs.readFileSync(entryPointPath, "utf-8");
|
|
209
|
+
} catch {}
|
|
210
|
+
}
|
|
211
|
+
fs.writeFileSync(examplePath, exampleRefdocContent(existingInstructions), "utf-8");
|
|
212
|
+
if (existingInstructions) {
|
|
213
|
+
console.log(" Created doc/_ARCHITECTURE.md (seeded from instruction file)");
|
|
214
|
+
} else {
|
|
215
|
+
console.log(" Created doc/_ARCHITECTURE.md (template)");
|
|
216
|
+
}
|
|
205
217
|
} else {
|
|
206
218
|
console.log(" doc/_ARCHITECTURE.md already exists");
|
|
207
219
|
}
|
|
@@ -217,15 +229,14 @@ function createDocs() {
|
|
|
217
229
|
}
|
|
218
230
|
|
|
219
231
|
function runIndexGenerator() {
|
|
220
|
-
|
|
221
|
-
if (!fs.existsSync(indexScript)) return;
|
|
232
|
+
if (!fs.existsSync(DOC_DIR)) return;
|
|
222
233
|
|
|
223
234
|
try {
|
|
224
|
-
const {
|
|
225
|
-
|
|
226
|
-
console.log(
|
|
227
|
-
} catch {
|
|
228
|
-
console.log(
|
|
235
|
+
const { writeIndex } = require("./index-gen");
|
|
236
|
+
const { refdocs, logs } = writeIndex(DOC_DIR);
|
|
237
|
+
console.log(` Generated doc/_INDEX.md (${refdocs} refdocs, ${logs} logs)`);
|
|
238
|
+
} catch (err) {
|
|
239
|
+
console.log(` Could not generate index: ${err.message}`);
|
|
229
240
|
}
|
|
230
241
|
}
|
|
231
242
|
|
|
@@ -240,9 +251,9 @@ async function main() {
|
|
|
240
251
|
console.log("\n2. Gitignore");
|
|
241
252
|
updateGitignore();
|
|
242
253
|
|
|
243
|
-
// Step 3:
|
|
254
|
+
// Step 3: Cleanup legacy Python (if upgrading from older version)
|
|
244
255
|
console.log("\n3. Index generator");
|
|
245
|
-
|
|
256
|
+
cleanupLegacyPython();
|
|
246
257
|
|
|
247
258
|
// Step 4: Entry point
|
|
248
259
|
console.log("\n4. Entry point");
|
|
@@ -273,7 +284,7 @@ async function main() {
|
|
|
273
284
|
|
|
274
285
|
// Step 6: Docs
|
|
275
286
|
console.log("\n6. Docs");
|
|
276
|
-
createDocs();
|
|
287
|
+
createDocs(entryPoint ? entryPoint.fullPath : null);
|
|
277
288
|
|
|
278
289
|
// Step 7: Generate index
|
|
279
290
|
console.log("\n7. Index");
|
package/lib/inject.js
CHANGED
|
@@ -7,17 +7,26 @@ const fs = require("fs");
|
|
|
7
7
|
const OPENCLEW_BLOCK = `
|
|
8
8
|
## Project knowledge (openclew)
|
|
9
9
|
|
|
10
|
-
This
|
|
10
|
+
This project uses \`doc/\` as its knowledge base. Before starting any task:
|
|
11
11
|
|
|
12
|
-
**
|
|
12
|
+
1. **Read \`doc/_INDEX.md\`** — it lists all available docs with a one-line summary each
|
|
13
|
+
2. **Pick your reference doc(s)** — choose one or more docs relevant to what you're about to do
|
|
14
|
+
3. **Read them** (L1 for relevance, L2 for context) — then start working
|
|
15
|
+
4. **No matching doc?** — propose creating a refdoc with \`npx openclew new "Title"\` before starting
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
- **Refdocs** (\`doc/_*.md\`) — evolve with the project (architecture, conventions, decisions)
|
|
16
|
-
- **Logs** (\`doc/log/YYYY-MM-DD_*.md\`) — frozen facts from a session, never modified after
|
|
17
|
+
If a doc contains placeholder comments (\`<!-- ... -->\`), fill them in based on what you observe in the code. This is expected — the docs are meant to be written by you.
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
Two types of docs:
|
|
20
|
+
- **Refdocs** (\`doc/_*.md\`) — architecture, conventions, decisions (evolve over time)
|
|
21
|
+
- **Logs** (\`doc/log/YYYY-MM-DD_*.md\`) — frozen facts from past sessions
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
Each doc has 3 levels: **L1** (subject + brief — 1 line) → **L2** (summary) → **L3** (full details, only when needed).
|
|
24
|
+
|
|
25
|
+
**Session commands** (user asks in chat, you run):
|
|
26
|
+
- "checkout" → \`npx openclew checkout\` (end-of-session summary + log)
|
|
27
|
+
- "new doc about X" → \`npx openclew new "X"\` (create refdoc)
|
|
28
|
+
- "search X" → \`npx openclew search "X"\` (search docs)
|
|
29
|
+
- "doc status" → \`npx openclew status\` (health dashboard)
|
|
21
30
|
`.trim();
|
|
22
31
|
|
|
23
32
|
const MARKER_START = "<!-- openclew_START -->";
|