openclew 0.4.0 → 0.5.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/UPGRADING.md +14 -0
- package/bin/openclew.js +2 -0
- package/lib/init.js +61 -8
- package/lib/session-header.js +60 -0
- package/lib/templates.js +1 -0
- package/package.json +1 -1
package/UPGRADING.md
CHANGED
|
@@ -133,6 +133,20 @@ openclew migrate # should show "0 to migrate"
|
|
|
133
133
|
|
|
134
134
|
## Version-specific notes
|
|
135
135
|
|
|
136
|
+
### → 0.5.0 (init guard + global config)
|
|
137
|
+
|
|
138
|
+
`init` now creates `~/.openclew/config.json` on every run. If you are not inside
|
|
139
|
+
a project directory (no `.git`, `package.json`, etc.), init stops after creating
|
|
140
|
+
the global config — it no longer creates `doc/` or `AGENTS.md` in random
|
|
141
|
+
directories.
|
|
142
|
+
|
|
143
|
+
New command: `openclew peek` — displays the doc index.
|
|
144
|
+
|
|
145
|
+
New: `scripts/qa.py` — QA checklist in box-drawing format (dev only, not
|
|
146
|
+
published to npm).
|
|
147
|
+
|
|
148
|
+
License changed from MIT to Apache 2.0.
|
|
149
|
+
|
|
136
150
|
### → 0.4.0 (format migration)
|
|
137
151
|
|
|
138
152
|
First migration release. Converts from the legacy format (YAML frontmatter,
|
package/bin/openclew.js
CHANGED
|
@@ -34,6 +34,7 @@ Usage:
|
|
|
34
34
|
Advanced:
|
|
35
35
|
openclew status Documentation health dashboard
|
|
36
36
|
openclew index Regenerate doc/_INDEX.md
|
|
37
|
+
openclew session-header Format session header line
|
|
37
38
|
openclew mcp Start MCP server (stdio JSON-RPC)
|
|
38
39
|
|
|
39
40
|
Options (init):
|
|
@@ -72,6 +73,7 @@ const commands = {
|
|
|
72
73
|
peek: () => require("../lib/peek"),
|
|
73
74
|
status: () => require("../lib/status"),
|
|
74
75
|
index: () => require("../lib/index-gen"),
|
|
76
|
+
"session-header": () => require("../lib/session-header"),
|
|
75
77
|
mcp: () => require("../lib/mcp-server"),
|
|
76
78
|
};
|
|
77
79
|
|
package/lib/init.js
CHANGED
|
@@ -1,26 +1,67 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* openclew init — set up openclew in the current project.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* 0. Create ~/.openclew/ (global config)
|
|
5
|
+
* 1. Detect if we're in a project (project markers)
|
|
6
|
+
* - If not: stop after global config
|
|
7
|
+
* - If yes: proceed with project init
|
|
8
|
+
* 2. Create doc/ and doc/log/
|
|
9
|
+
* 3. Detect entry point (AGENTS.md case-insensitive by default)
|
|
10
|
+
* 4. Inject openclew block into entry point
|
|
11
|
+
* 5. Install pre-commit hook for index generation
|
|
12
|
+
* 6. Create guide + example docs
|
|
13
|
+
* 7. Generate initial _INDEX.md
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
16
|
const fs = require("fs");
|
|
13
17
|
const path = require("path");
|
|
18
|
+
const os = require("os");
|
|
14
19
|
const readline = require("readline");
|
|
15
20
|
const { detectInstructionFiles, findAgentsMdCaseInsensitive } = require("./detect");
|
|
16
21
|
const { inject, isAlreadyInjected } = require("./inject");
|
|
17
22
|
const { writeConfig } = require("./config");
|
|
18
|
-
const { guideContent, frameworkIntegrationContent, exampleRefdocContent, exampleLogContent, today } = require("./templates");
|
|
23
|
+
const { guideContent, frameworkIntegrationContent, exampleRefdocContent, exampleLogContent, today, ocVersion } = require("./templates");
|
|
19
24
|
|
|
20
25
|
const PROJECT_ROOT = process.cwd();
|
|
21
26
|
const DOC_DIR = path.join(PROJECT_ROOT, "doc");
|
|
22
27
|
const LOG_DIR = path.join(DOC_DIR, "log");
|
|
23
28
|
const GIT_DIR = path.join(PROJECT_ROOT, ".git");
|
|
29
|
+
const OPENCLEW_HOME = path.join(os.homedir(), ".openclew");
|
|
30
|
+
|
|
31
|
+
const PROJECT_MARKERS = [".git", "package.json", "Cargo.toml", "pyproject.toml", "go.mod", "Gemfile", "composer.json", "Makefile", "pom.xml", "build.gradle", "CMakeLists.txt", "setup.py", "setup.cfg"];
|
|
32
|
+
|
|
33
|
+
function isProjectDir() {
|
|
34
|
+
return PROJECT_MARKERS.some((m) => fs.existsSync(path.join(PROJECT_ROOT, m)));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function ensureGlobalDir() {
|
|
38
|
+
const created = !fs.existsSync(OPENCLEW_HOME);
|
|
39
|
+
if (created) {
|
|
40
|
+
fs.mkdirSync(OPENCLEW_HOME, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const configPath = path.join(OPENCLEW_HOME, "config.json");
|
|
44
|
+
if (!fs.existsSync(configPath)) {
|
|
45
|
+
fs.writeFileSync(
|
|
46
|
+
configPath,
|
|
47
|
+
JSON.stringify({ version: ocVersion(), installedAt: today() }, null, 2) + "\n",
|
|
48
|
+
"utf-8"
|
|
49
|
+
);
|
|
50
|
+
} else {
|
|
51
|
+
// Update version on each init
|
|
52
|
+
try {
|
|
53
|
+
const cfg = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
54
|
+
cfg.version = ocVersion();
|
|
55
|
+
fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
|
|
56
|
+
} catch {}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (created) {
|
|
60
|
+
console.log(" Created ~/.openclew/");
|
|
61
|
+
} else {
|
|
62
|
+
console.log(" ~/.openclew/ already exists");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
24
65
|
|
|
25
66
|
const args = process.argv.slice(2);
|
|
26
67
|
const noHook = args.includes("--no-hook");
|
|
@@ -295,8 +336,20 @@ function installSlashCommands() {
|
|
|
295
336
|
async function main() {
|
|
296
337
|
console.log("\nopenclew init\n");
|
|
297
338
|
|
|
339
|
+
// Step 0: Global config (~/.openclew/)
|
|
340
|
+
console.log("0. Global config");
|
|
341
|
+
ensureGlobalDir();
|
|
342
|
+
|
|
343
|
+
// Check if we're in a project
|
|
344
|
+
if (!isProjectDir()) {
|
|
345
|
+
console.log(`\n─── Done ───\n`);
|
|
346
|
+
console.log(` openclew installed → ~/.openclew/`);
|
|
347
|
+
console.log("");
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
298
351
|
// Step 1: Create directories
|
|
299
|
-
console.log("
|
|
352
|
+
console.log("\n1. Project structure");
|
|
300
353
|
createDirs();
|
|
301
354
|
|
|
302
355
|
// Step 2: Gitignore
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* openclew session-header — format a session header line.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* openclew session-header --name "Refonte checkout" --tags voice,stt,voxtral
|
|
6
|
+
* openclew session-header --name "Fix streaming" --tags streaming --date 2026-03-27
|
|
7
|
+
*
|
|
8
|
+
* Output:
|
|
9
|
+
* 📅 2026-03-28 🏷️ Refonte checkout ----- #voice #stt #voxtral
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { today } = require("./templates");
|
|
13
|
+
|
|
14
|
+
function formatSessionHeader(name, tags, date) {
|
|
15
|
+
if (!name) {
|
|
16
|
+
console.error("Error: --name is required");
|
|
17
|
+
console.error(
|
|
18
|
+
'Usage: openclew session-header --name "Session title" --tags tag1,tag2'
|
|
19
|
+
);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const d = date || today();
|
|
24
|
+
const hashTags = tags.length > 0 ? tags.map((t) => `#${t}`).join(" ") : "";
|
|
25
|
+
const line = `📅 ${d} 🏷️ ${name} ----- ${hashTags}`.trimEnd();
|
|
26
|
+
|
|
27
|
+
console.log(line);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function main() {
|
|
31
|
+
const args = process.argv.slice(2);
|
|
32
|
+
let name = "";
|
|
33
|
+
let tags = [];
|
|
34
|
+
let date = "";
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < args.length; i++) {
|
|
37
|
+
if (args[i] === "--name" && args[i + 1]) {
|
|
38
|
+
name = args[++i];
|
|
39
|
+
} else if (args[i] === "--tags" && args[i + 1]) {
|
|
40
|
+
tags = args[++i].split(",").map((t) => t.trim()).filter(Boolean);
|
|
41
|
+
} else if (args[i] === "--date" && args[i + 1]) {
|
|
42
|
+
date = args[++i];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
formatSessionHeader(name, tags, date);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = { formatSessionHeader };
|
|
50
|
+
|
|
51
|
+
if (require.main === module) {
|
|
52
|
+
main();
|
|
53
|
+
} else {
|
|
54
|
+
// Called via require from bin/openclew.js — run main
|
|
55
|
+
const callerIsOpenclew =
|
|
56
|
+
process.argv[1] && process.argv[1].includes("openclew");
|
|
57
|
+
if (callerIsOpenclew) {
|
|
58
|
+
main();
|
|
59
|
+
}
|
|
60
|
+
}
|
package/lib/templates.js
CHANGED