lanekeeper 0.1.7 → 0.1.8
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/bin/lanekeeper.js
CHANGED
|
@@ -34,10 +34,15 @@ async function init() {
|
|
|
34
34
|
}
|
|
35
35
|
const { writeFileSync, readFileSync: read, existsSync, appendFileSync } = await import("node:fs");
|
|
36
36
|
const { join } = await import("node:path");
|
|
37
|
+
// What actually got newly written or modified this run — only these need
|
|
38
|
+
// committing. If everything below was already wired from a previous run,
|
|
39
|
+
// there's nothing new to tell you to commit.
|
|
40
|
+
const writtenFiles = [];
|
|
37
41
|
if (hasConfig(root)) {
|
|
38
42
|
console.log("lanekeeper init: lanekeeper.config.mjs already exists — leaving it alone.");
|
|
39
43
|
}
|
|
40
44
|
else {
|
|
45
|
+
writtenFiles.push("lanekeeper.config.mjs");
|
|
41
46
|
const detectedBranch = detectCurrentBranch(root);
|
|
42
47
|
const detectedCheck = detectCheckCommand(root);
|
|
43
48
|
const generated = {
|
|
@@ -80,10 +85,12 @@ export default ${JSON.stringify(generated, null, 2)};
|
|
|
80
85
|
if (!existsSync(claudeMdPath)) {
|
|
81
86
|
writeFileSync(claudeMdPath, `# Project instructions for Claude Code\n\n${snippet}`);
|
|
82
87
|
console.log(`lanekeeper init: wrote ${claudeMdPath}`);
|
|
88
|
+
writtenFiles.push("CLAUDE.md");
|
|
83
89
|
}
|
|
84
90
|
else if (!read(claudeMdPath, "utf8").includes(MARKER)) {
|
|
85
91
|
appendFileSync(claudeMdPath, `\n${snippet}`);
|
|
86
92
|
console.log(`lanekeeper init: appended the LaneKeeper workflow section to ${claudeMdPath}`);
|
|
93
|
+
writtenFiles.push("CLAUDE.md");
|
|
87
94
|
}
|
|
88
95
|
else {
|
|
89
96
|
console.log(`lanekeeper init: ${claudeMdPath} already has the LaneKeeper workflow section — leaving it alone.`);
|
|
@@ -92,9 +99,11 @@ export default ${JSON.stringify(generated, null, 2)};
|
|
|
92
99
|
switch (claudeSettingsResult) {
|
|
93
100
|
case "created":
|
|
94
101
|
console.log(`lanekeeper init: wrote ${join(root, ".claude", "settings.json")} with the WorktreeCreate hook.`);
|
|
102
|
+
writtenFiles.push(".claude/settings.json");
|
|
95
103
|
break;
|
|
96
104
|
case "merged":
|
|
97
105
|
console.log(`lanekeeper init: added the WorktreeCreate hook to your existing ${join(root, ".claude", "settings.json")}.`);
|
|
106
|
+
writtenFiles.push(".claude/settings.json");
|
|
98
107
|
break;
|
|
99
108
|
case "already-wired":
|
|
100
109
|
console.log("lanekeeper init: .claude/settings.json already has the WorktreeCreate hook — leaving it alone.");
|
|
@@ -108,9 +117,11 @@ export default ${JSON.stringify(generated, null, 2)};
|
|
|
108
117
|
switch (prePushResult) {
|
|
109
118
|
case "created":
|
|
110
119
|
console.log("lanekeeper init: wrote .husky/pre-push.");
|
|
120
|
+
writtenFiles.push(".husky/pre-push");
|
|
111
121
|
break;
|
|
112
122
|
case "merged":
|
|
113
123
|
console.log("lanekeeper init: appended LaneKeeper's checks to your existing .husky/pre-push.");
|
|
124
|
+
writtenFiles.push(".husky/pre-push");
|
|
114
125
|
break;
|
|
115
126
|
case "already-wired":
|
|
116
127
|
console.log("lanekeeper init: .husky/pre-push already wired — leaving it alone.");
|
|
@@ -143,6 +154,7 @@ export default ${JSON.stringify(generated, null, 2)};
|
|
|
143
154
|
switch (scriptsResult.result) {
|
|
144
155
|
case "added":
|
|
145
156
|
console.log(`lanekeeper init: added "${scriptsResult.added.join('", "')}" to package.json scripts.`);
|
|
157
|
+
writtenFiles.push("package.json");
|
|
146
158
|
break;
|
|
147
159
|
case "already-wired":
|
|
148
160
|
console.log("lanekeeper init: package.json already has all five scripts — leaving them alone.");
|
|
@@ -157,9 +169,14 @@ export default ${JSON.stringify(generated, null, 2)};
|
|
|
157
169
|
}
|
|
158
170
|
console.log("");
|
|
159
171
|
console.log("Next steps:");
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
172
|
+
if (writtenFiles.length > 0) {
|
|
173
|
+
console.log(` 1. Commit what it wrote — ${writtenFiles.join(", ")}.`);
|
|
174
|
+
console.log(" 2. claude --worktree <name> — the agent takes it from there.");
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
console.log(" 1. claude --worktree <name> — the agent takes it from there.");
|
|
178
|
+
console.log(" (everything was already wired — nothing new to commit)");
|
|
179
|
+
}
|
|
163
180
|
}
|
|
164
181
|
async function main() {
|
|
165
182
|
switch (command) {
|
|
@@ -11,4 +11,5 @@ export declare function createLane(mainTop: string, cfg: LaneKeeperConfig): {
|
|
|
11
11
|
lane: number;
|
|
12
12
|
};
|
|
13
13
|
export declare function isEphemeralNpxCopy(selfPath: string): boolean;
|
|
14
|
+
export declare function expectsLocalInstall(mainTop: string): boolean;
|
|
14
15
|
export declare function runWorktreeCreateHook(): Promise<void>;
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* automatically — nothing to release by hand.
|
|
25
25
|
*/
|
|
26
26
|
import { execFileSync } from "node:child_process";
|
|
27
|
-
import { existsSync, mkdirSync, symlinkSync } from "node:fs";
|
|
27
|
+
import { existsSync, mkdirSync, readFileSync, symlinkSync } from "node:fs";
|
|
28
28
|
import { dirname, join, basename, sep } from "node:path";
|
|
29
29
|
import { fileURLToPath } from "node:url";
|
|
30
30
|
import { loadConfig, hasConfig, DEFAULTS } from "../lib/config.js";
|
|
@@ -140,6 +140,25 @@ export function createLane(mainTop, cfg) {
|
|
|
140
140
|
export function isEphemeralNpxCopy(selfPath) {
|
|
141
141
|
return selfPath.includes(`${sep}_npx${sep}`);
|
|
142
142
|
}
|
|
143
|
+
// The guard above only makes sense for a host project that's an npm project
|
|
144
|
+
// with lanekeeper as a real dependency — hola, say. A non-Node host repo
|
|
145
|
+
// (a Haskell/Lua/Rust/whatever project with no package.json at all) has
|
|
146
|
+
// nowhere to install lanekeeper INTO; npx's ephemeral cache is the only way
|
|
147
|
+
// it can ever run lanekeeper commands, not a fallback masking a broken
|
|
148
|
+
// local install. Only expect a local install — and therefore only treat
|
|
149
|
+
// ephemeral execution as suspicious — when the host's own package.json
|
|
150
|
+
// actually lists lanekeeper as a dependency. No package.json, or one that
|
|
151
|
+
// doesn't mention lanekeeper: ephemeral execution is completely normal.
|
|
152
|
+
export function expectsLocalInstall(mainTop) {
|
|
153
|
+
let pkg;
|
|
154
|
+
try {
|
|
155
|
+
pkg = JSON.parse(readFileSync(join(mainTop, "package.json"), "utf8"));
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return false; // no package.json, or unreadable/invalid — nothing "expected" to be there
|
|
159
|
+
}
|
|
160
|
+
return Boolean(pkg.dependencies?.lanekeeper || pkg.devDependencies?.lanekeeper);
|
|
161
|
+
}
|
|
143
162
|
async function readStdin() {
|
|
144
163
|
const chunks = [];
|
|
145
164
|
for await (const chunk of process.stdin)
|
|
@@ -156,11 +175,11 @@ export async function runWorktreeCreateHook() {
|
|
|
156
175
|
}
|
|
157
176
|
const fromCwd = input.cwd ?? process.cwd();
|
|
158
177
|
try {
|
|
159
|
-
|
|
178
|
+
const mainTop = resolveMainCheckout(fromCwd);
|
|
179
|
+
if (expectsLocalInstall(mainTop) && isEphemeralNpxCopy(fileURLToPath(import.meta.url))) {
|
|
160
180
|
throw new Error("running from npx's ephemeral cache, not this project's own installed dependency — " +
|
|
161
181
|
"node_modules is missing or broken. Run `npm install` in the main checkout and try again.");
|
|
162
182
|
}
|
|
163
|
-
const mainTop = resolveMainCheckout(fromCwd);
|
|
164
183
|
const cfg = hasConfig(mainTop) ? await loadConfig(mainTop) : { ...DEFAULTS };
|
|
165
184
|
const { wt } = createLane(mainTop, cfg);
|
|
166
185
|
process.stdout.write(wt + "\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lanekeeper",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "The local, zero-cost merge queue for parallel Claude Code agents. Plugs into Claude Code's native worktree isolation; one build at a time, one landing at a time, zero races.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|