codebyplan 1.1.0 → 1.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/dist/cli.js +113 -8
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -14,7 +14,7 @@ var VERSION, PACKAGE_NAME;
|
|
|
14
14
|
var init_version = __esm({
|
|
15
15
|
"src/lib/version.ts"() {
|
|
16
16
|
"use strict";
|
|
17
|
-
VERSION = "1.
|
|
17
|
+
VERSION = "1.3.0";
|
|
18
18
|
PACKAGE_NAME = "codebyplan";
|
|
19
19
|
}
|
|
20
20
|
});
|
|
@@ -296,21 +296,45 @@ var init_hook_registry = __esm({
|
|
|
296
296
|
});
|
|
297
297
|
|
|
298
298
|
// src/lib/variables.ts
|
|
299
|
+
function splitFrontmatter(content) {
|
|
300
|
+
const fmMatch = content.match(/^(---\s*\n[\s\S]*?\n---\n?)([\s\S]*)$/);
|
|
301
|
+
if (fmMatch) {
|
|
302
|
+
return { frontmatter: fmMatch[1], body: fmMatch[2] };
|
|
303
|
+
}
|
|
304
|
+
if (content.startsWith("#!/") || content.startsWith("# @")) {
|
|
305
|
+
const lines = content.split("\n");
|
|
306
|
+
let headerEnd = 0;
|
|
307
|
+
for (let i = 0; i < lines.length; i++) {
|
|
308
|
+
if (lines[i].startsWith("#") || lines[i].startsWith("#!/") || lines[i].trim() === "") {
|
|
309
|
+
headerEnd = i + 1;
|
|
310
|
+
} else {
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
frontmatter: lines.slice(0, headerEnd).join("\n") + "\n",
|
|
316
|
+
body: lines.slice(headerEnd).join("\n")
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
return { frontmatter: "", body: content };
|
|
320
|
+
}
|
|
299
321
|
function substituteVariables(content, repoData) {
|
|
300
322
|
if (!content.includes("{{")) return content;
|
|
301
|
-
|
|
323
|
+
const { frontmatter, body } = splitFrontmatter(content);
|
|
324
|
+
let result = body;
|
|
302
325
|
for (const [name, resolver] of Object.entries(TEMPLATE_VARIABLES)) {
|
|
303
326
|
const placeholder = `{{${name}}}`;
|
|
304
327
|
if (result.includes(placeholder)) {
|
|
305
328
|
result = result.replaceAll(placeholder, resolver(repoData));
|
|
306
329
|
}
|
|
307
330
|
}
|
|
308
|
-
return result;
|
|
331
|
+
return frontmatter + result;
|
|
309
332
|
}
|
|
310
333
|
function escapeRegex(str) {
|
|
311
334
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
312
335
|
}
|
|
313
336
|
function reverseSubstituteVariables(content, repoData) {
|
|
337
|
+
const { frontmatter, body } = splitFrontmatter(content);
|
|
314
338
|
const entries = [];
|
|
315
339
|
for (const [name, resolver] of Object.entries(TEMPLATE_VARIABLES)) {
|
|
316
340
|
const value = resolver(repoData);
|
|
@@ -318,7 +342,7 @@ function reverseSubstituteVariables(content, repoData) {
|
|
|
318
342
|
entries.push([value, `{{${name}}}`]);
|
|
319
343
|
}
|
|
320
344
|
entries.sort((a, b) => b[0].length - a[0].length);
|
|
321
|
-
let result =
|
|
345
|
+
let result = body;
|
|
322
346
|
for (const [value, placeholder] of entries) {
|
|
323
347
|
if (value.length < 8) {
|
|
324
348
|
const pattern = new RegExp(`\\b${escapeRegex(value)}\\b`, "g");
|
|
@@ -327,7 +351,7 @@ function reverseSubstituteVariables(content, repoData) {
|
|
|
327
351
|
result = result.replaceAll(value, placeholder);
|
|
328
352
|
}
|
|
329
353
|
}
|
|
330
|
-
return result;
|
|
354
|
+
return frontmatter + result;
|
|
331
355
|
}
|
|
332
356
|
var TEMPLATE_VARIABLES;
|
|
333
357
|
var init_variables = __esm({
|
|
@@ -1038,6 +1062,13 @@ async function scanLocalFiles(claudeDir, projectPath) {
|
|
|
1038
1062
|
await scanFlatType(join5(claudeDir, "rules"), "rule", ".md", result);
|
|
1039
1063
|
await scanFlatType(join5(claudeDir, "hooks"), "hook", ".sh", result);
|
|
1040
1064
|
await scanTemplates(join5(claudeDir, "templates"), result);
|
|
1065
|
+
await scanCategorizedType(
|
|
1066
|
+
join5(claudeDir, "context"),
|
|
1067
|
+
"context",
|
|
1068
|
+
".md",
|
|
1069
|
+
result
|
|
1070
|
+
);
|
|
1071
|
+
await scanDocsRecursive(join5(claudeDir, "docs"), result);
|
|
1041
1072
|
await scanSettings(claudeDir, projectPath, result);
|
|
1042
1073
|
return result;
|
|
1043
1074
|
}
|
|
@@ -1112,6 +1143,69 @@ async function scanFlatType(dir, type, ext, result) {
|
|
|
1112
1143
|
}
|
|
1113
1144
|
}
|
|
1114
1145
|
}
|
|
1146
|
+
async function scanCategorizedType(dir, type, ext, result) {
|
|
1147
|
+
let entries;
|
|
1148
|
+
try {
|
|
1149
|
+
entries = await readdir3(dir, { withFileTypes: true });
|
|
1150
|
+
} catch {
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
for (const entry of entries) {
|
|
1154
|
+
if (entry.isDirectory()) {
|
|
1155
|
+
const category = entry.name;
|
|
1156
|
+
let subEntries;
|
|
1157
|
+
try {
|
|
1158
|
+
subEntries = await readdir3(join5(dir, category), {
|
|
1159
|
+
withFileTypes: true
|
|
1160
|
+
});
|
|
1161
|
+
} catch {
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
for (const sub of subEntries) {
|
|
1165
|
+
if (sub.isFile() && sub.name.endsWith(ext)) {
|
|
1166
|
+
const name = sub.name.slice(0, -ext.length);
|
|
1167
|
+
const content = await readFile5(
|
|
1168
|
+
join5(dir, category, sub.name),
|
|
1169
|
+
"utf-8"
|
|
1170
|
+
);
|
|
1171
|
+
const scope = extractScope(content, type);
|
|
1172
|
+
const key = compositeKey(type, name, category);
|
|
1173
|
+
result.set(key, { type, name, category, content, scope });
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
} else if (entry.isFile() && entry.name.endsWith(ext)) {
|
|
1177
|
+
const name = entry.name.slice(0, -ext.length);
|
|
1178
|
+
const content = await readFile5(join5(dir, entry.name), "utf-8");
|
|
1179
|
+
const scope = extractScope(content, type);
|
|
1180
|
+
const key = compositeKey(type, name, null);
|
|
1181
|
+
result.set(key, { type, name, category: null, content, scope });
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
async function scanDocsRecursive(docsDir, result) {
|
|
1186
|
+
await scanDocsDir(docsDir, docsDir, result);
|
|
1187
|
+
}
|
|
1188
|
+
async function scanDocsDir(baseDir, currentDir, result) {
|
|
1189
|
+
let entries;
|
|
1190
|
+
try {
|
|
1191
|
+
entries = await readdir3(currentDir, { withFileTypes: true });
|
|
1192
|
+
} catch {
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
for (const entry of entries) {
|
|
1196
|
+
if (entry.isDirectory()) {
|
|
1197
|
+
await scanDocsDir(baseDir, join5(currentDir, entry.name), result);
|
|
1198
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
1199
|
+
const name = entry.name.slice(0, -3);
|
|
1200
|
+
const content = await readFile5(join5(currentDir, entry.name), "utf-8");
|
|
1201
|
+
const scope = extractScope(content, "docs");
|
|
1202
|
+
const relDir = currentDir.slice(baseDir.length + 1);
|
|
1203
|
+
const category = relDir || null;
|
|
1204
|
+
const key = compositeKey("docs", name, category);
|
|
1205
|
+
result.set(key, { type: "docs", name, category, content, scope });
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1115
1209
|
async function scanTemplates(dir, result) {
|
|
1116
1210
|
let entries;
|
|
1117
1211
|
try {
|
|
@@ -2667,7 +2761,10 @@ function groupByType(items) {
|
|
|
2667
2761
|
rule: "Rules",
|
|
2668
2762
|
hook: "Hooks",
|
|
2669
2763
|
template: "Templates",
|
|
2670
|
-
settings: "Settings"
|
|
2764
|
+
settings: "Settings",
|
|
2765
|
+
context: "Context",
|
|
2766
|
+
docs_stack: "Stack Docs",
|
|
2767
|
+
docs: "Docs"
|
|
2671
2768
|
};
|
|
2672
2769
|
for (const item of items) {
|
|
2673
2770
|
const label = typeLabels[item.type] ?? item.type;
|
|
@@ -2685,6 +2782,9 @@ function getLocalFilePath(claudeDir, projectPath, remote) {
|
|
|
2685
2782
|
rule: { dir: "rules", ext: ".md" },
|
|
2686
2783
|
hook: { dir: "hooks", ext: ".sh" },
|
|
2687
2784
|
template: { dir: "templates", ext: "" },
|
|
2785
|
+
context: { dir: "context", ext: ".md" },
|
|
2786
|
+
docs_stack: { dir: join7("docs", "stack"), ext: ".md" },
|
|
2787
|
+
docs: { dir: "docs", ext: ".md" },
|
|
2688
2788
|
claude_md: { dir: "", ext: "" },
|
|
2689
2789
|
settings: { dir: "", ext: "" }
|
|
2690
2790
|
};
|
|
@@ -2698,11 +2798,13 @@ function getLocalFilePath(claudeDir, projectPath, remote) {
|
|
|
2698
2798
|
if (remote.type === "command" && remote.category)
|
|
2699
2799
|
return join7(typeDir, remote.category, `${remote.name}${cfg.ext}`);
|
|
2700
2800
|
if (remote.type === "template") return join7(typeDir, remote.name);
|
|
2801
|
+
if (remote.category && (remote.type === "context" || remote.type === "docs_stack" || remote.type === "docs"))
|
|
2802
|
+
return join7(typeDir, remote.category, `${remote.name}${cfg.ext}`);
|
|
2701
2803
|
return join7(typeDir, `${remote.name}${cfg.ext}`);
|
|
2702
2804
|
}
|
|
2703
2805
|
function getSyncVersion() {
|
|
2704
2806
|
try {
|
|
2705
|
-
return "1.
|
|
2807
|
+
return "1.3.0";
|
|
2706
2808
|
} catch {
|
|
2707
2809
|
return "unknown";
|
|
2708
2810
|
}
|
|
@@ -2716,7 +2818,10 @@ function flattenSyncData(data) {
|
|
|
2716
2818
|
rules: "rule",
|
|
2717
2819
|
hooks: "hook",
|
|
2718
2820
|
templates: "template",
|
|
2719
|
-
settings: "settings"
|
|
2821
|
+
settings: "settings",
|
|
2822
|
+
contexts: "context",
|
|
2823
|
+
docs_stack: "docs_stack",
|
|
2824
|
+
docs: "docs"
|
|
2720
2825
|
};
|
|
2721
2826
|
for (const [syncKey, typeName] of Object.entries(typeMap)) {
|
|
2722
2827
|
const files = data[syncKey] ?? [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codebyplan",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "CLI for CodeByPlan — AI-powered development planning and tracking",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|
|
35
35
|
"url": "https://github.com/codebyplan/codebyplan.git",
|
|
36
|
-
"directory": "packages/codebyplan"
|
|
36
|
+
"directory": "packages/codebyplan-package"
|
|
37
37
|
},
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"publishConfig": {
|