@wildorder/nightshift 0.1.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/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/agent-runner.d.ts +64 -0
- package/dist/agent-runner.d.ts.map +1 -0
- package/dist/agent-runner.js +128 -0
- package/dist/agent-runner.js.map +1 -0
- package/dist/agent-summary.d.ts +35 -0
- package/dist/agent-summary.d.ts.map +1 -0
- package/dist/agent-summary.js +95 -0
- package/dist/agent-summary.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +18 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +74 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +62 -0
- package/dist/config.js.map +1 -0
- package/dist/detect-package-manager.d.ts +15 -0
- package/dist/detect-package-manager.d.ts.map +1 -0
- package/dist/detect-package-manager.js +78 -0
- package/dist/detect-package-manager.js.map +1 -0
- package/dist/findings.d.ts +106 -0
- package/dist/findings.d.ts.map +1 -0
- package/dist/findings.js +107 -0
- package/dist/findings.js.map +1 -0
- package/dist/graph.d.ts +30 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +87 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/program-memory.d.ts +252 -0
- package/dist/program-memory.d.ts.map +1 -0
- package/dist/program-memory.js +385 -0
- package/dist/program-memory.js.map +1 -0
- package/dist/project-manifest.d.ts +23 -0
- package/dist/project-manifest.d.ts.map +1 -0
- package/dist/project-manifest.js +78 -0
- package/dist/project-manifest.js.map +1 -0
- package/dist/prompt.d.ts +70 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +237 -0
- package/dist/prompt.js.map +1 -0
- package/dist/worktree-guard.d.ts +40 -0
- package/dist/worktree-guard.d.ts.map +1 -0
- package/dist/worktree-guard.js +91 -0
- package/dist/worktree-guard.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ManifestSkipReason = "package.json exists" | "foreign manifest";
|
|
2
|
+
export interface CreateProjectManifestResult {
|
|
3
|
+
created: boolean;
|
|
4
|
+
path: string;
|
|
5
|
+
/** The package name written, when a manifest was created. */
|
|
6
|
+
name?: string;
|
|
7
|
+
reason?: ManifestSkipReason;
|
|
8
|
+
/** The file that made this directory look like another ecosystem. */
|
|
9
|
+
foreignManifest?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Derive a valid npm package name from a directory name. npm allows lowercase
|
|
13
|
+
* letters, digits, and `-._`, and forbids a leading `.` or `_`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function toPackageName(directoryName: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Write a minimal placeholder package.json so a brand-new project can pin the
|
|
18
|
+
* pipeline as a devDependency. Deliberately not `npm init --yes`: that writes a
|
|
19
|
+
* stub `test` script that fails by design, which `init` would then pick up as a
|
|
20
|
+
* verify command and every build would fail on it.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createProjectManifest(cwd: string): Promise<CreateProjectManifestResult>;
|
|
23
|
+
//# sourceMappingURL=project-manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-manifest.d.ts","sourceRoot":"","sources":["../src/project-manifest.ts"],"names":[],"mappings":"AA6BA,MAAM,MAAM,kBAAkB,GAAG,qBAAqB,GAAG,kBAAkB,CAAC;AAE5E,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAS3D;AAkBD;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,2BAA2B,CAAC,CAmBtC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { basename, join, resolve } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Manifests that mark the directory as belonging to another ecosystem. A
|
|
5
|
+
* package.json dropped next to one of these would misrepresent the project, so
|
|
6
|
+
* setup leaves those repositories alone and runs the CLI through npx instead.
|
|
7
|
+
*/
|
|
8
|
+
const FOREIGN_MANIFESTS = new Set([
|
|
9
|
+
"pyproject.toml",
|
|
10
|
+
"requirements.txt",
|
|
11
|
+
"setup.py",
|
|
12
|
+
"Pipfile",
|
|
13
|
+
"go.mod",
|
|
14
|
+
"Cargo.toml",
|
|
15
|
+
"Gemfile",
|
|
16
|
+
"composer.json",
|
|
17
|
+
"pom.xml",
|
|
18
|
+
"build.gradle",
|
|
19
|
+
"build.gradle.kts",
|
|
20
|
+
"build.sbt",
|
|
21
|
+
"mix.exs",
|
|
22
|
+
"pubspec.yaml",
|
|
23
|
+
"Package.swift",
|
|
24
|
+
"CMakeLists.txt",
|
|
25
|
+
]);
|
|
26
|
+
const FOREIGN_EXTENSIONS = [".csproj", ".fsproj", ".sln"];
|
|
27
|
+
/**
|
|
28
|
+
* Derive a valid npm package name from a directory name. npm allows lowercase
|
|
29
|
+
* letters, digits, and `-._`, and forbids a leading `.` or `_`.
|
|
30
|
+
*/
|
|
31
|
+
export function toPackageName(directoryName) {
|
|
32
|
+
const slug = directoryName
|
|
33
|
+
.trim()
|
|
34
|
+
.toLowerCase()
|
|
35
|
+
.replace(/[^a-z0-9._-]+/gu, "-")
|
|
36
|
+
.replace(/^[._-]+/u, "")
|
|
37
|
+
.replace(/[-.]+$/u, "")
|
|
38
|
+
.slice(0, 214);
|
|
39
|
+
return slug.length > 0 ? slug : "project";
|
|
40
|
+
}
|
|
41
|
+
async function findForeignManifest(root) {
|
|
42
|
+
let entries;
|
|
43
|
+
try {
|
|
44
|
+
entries = await readdir(root);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return entries.find((entry) => FOREIGN_MANIFESTS.has(entry) ||
|
|
50
|
+
FOREIGN_EXTENSIONS.some((extension) => entry.toLowerCase().endsWith(extension)));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Write a minimal placeholder package.json so a brand-new project can pin the
|
|
54
|
+
* pipeline as a devDependency. Deliberately not `npm init --yes`: that writes a
|
|
55
|
+
* stub `test` script that fails by design, which `init` would then pick up as a
|
|
56
|
+
* verify command and every build would fail on it.
|
|
57
|
+
*/
|
|
58
|
+
export async function createProjectManifest(cwd) {
|
|
59
|
+
const root = resolve(cwd);
|
|
60
|
+
const path = join(root, "package.json");
|
|
61
|
+
const entries = await readdir(root).catch(() => []);
|
|
62
|
+
if (entries.includes("package.json")) {
|
|
63
|
+
return { created: false, path, reason: "package.json exists" };
|
|
64
|
+
}
|
|
65
|
+
const foreignManifest = await findForeignManifest(root);
|
|
66
|
+
if (foreignManifest !== undefined) {
|
|
67
|
+
return { created: false, path, reason: "foreign manifest", foreignManifest };
|
|
68
|
+
}
|
|
69
|
+
const name = toPackageName(basename(root));
|
|
70
|
+
const manifest = {
|
|
71
|
+
name,
|
|
72
|
+
version: "0.0.0",
|
|
73
|
+
private: true,
|
|
74
|
+
};
|
|
75
|
+
await writeFile(path, `${JSON.stringify(manifest, undefined, 2)}\n`, "utf8");
|
|
76
|
+
return { created: true, path, name };
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=project-manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-manifest.js","sourceRoot":"","sources":["../src/project-manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/prompt.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A minimal keyboard-driven prompt set.
|
|
3
|
+
*
|
|
4
|
+
* Hand-rolled rather than pulled from a dependency: the primary invocation of
|
|
5
|
+
* this CLI is `npx --yes @wildorder/nightshift`, where every transitive
|
|
6
|
+
* dependency is a user-visible download, and these prompts need to render
|
|
7
|
+
* per-row annotations (resolved path, detection state) that a generic
|
|
8
|
+
* checkbox prompt fights.
|
|
9
|
+
*/
|
|
10
|
+
interface PromptInput {
|
|
11
|
+
isTTY?: boolean | undefined;
|
|
12
|
+
setRawMode?: (mode: boolean) => unknown;
|
|
13
|
+
setEncoding: (encoding: BufferEncoding) => unknown;
|
|
14
|
+
on: (event: "data", listener: (chunk: string) => void) => unknown;
|
|
15
|
+
off: (event: "data", listener: (chunk: string) => void) => unknown;
|
|
16
|
+
resume: () => unknown;
|
|
17
|
+
pause: () => unknown;
|
|
18
|
+
}
|
|
19
|
+
interface PromptOutput {
|
|
20
|
+
isTTY?: boolean | undefined;
|
|
21
|
+
write: (chunk: string) => unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface PromptStreams {
|
|
24
|
+
input: PromptInput;
|
|
25
|
+
output: PromptOutput;
|
|
26
|
+
}
|
|
27
|
+
export interface Choice<T> {
|
|
28
|
+
value: T;
|
|
29
|
+
label: string;
|
|
30
|
+
/** Right-hand annotation, dimmed. */
|
|
31
|
+
hint?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function defaultStreams(): PromptStreams;
|
|
34
|
+
/**
|
|
35
|
+
* Prompting is only safe when a human is on both ends. The CLI is also driven
|
|
36
|
+
* by npm lifecycle hooks, CI, and the packaged skills themselves — a blocking
|
|
37
|
+
* read in any of those hangs the process.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isInteractive(streams?: PromptStreams, env?: NodeJS.ProcessEnv): boolean;
|
|
40
|
+
export interface ChooseManyOptions<T> {
|
|
41
|
+
title: string;
|
|
42
|
+
choices: Array<Choice<T>>;
|
|
43
|
+
/** Values checked when the prompt opens. */
|
|
44
|
+
initial: T[];
|
|
45
|
+
streams?: PromptStreams;
|
|
46
|
+
env?: NodeJS.ProcessEnv;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Multi-select. Resolves `undefined` when the user cancels, which callers must
|
|
50
|
+
* distinguish from an empty selection.
|
|
51
|
+
*/
|
|
52
|
+
export declare function chooseMany<T>(options: ChooseManyOptions<T>): Promise<T[] | undefined>;
|
|
53
|
+
export interface ChooseOneOptions<T> {
|
|
54
|
+
title: string;
|
|
55
|
+
choices: Array<Choice<T>>;
|
|
56
|
+
initial: T;
|
|
57
|
+
streams?: PromptStreams;
|
|
58
|
+
env?: NodeJS.ProcessEnv;
|
|
59
|
+
}
|
|
60
|
+
/** Single-select. Resolves `undefined` when the user cancels. */
|
|
61
|
+
export declare function chooseOne<T>(options: ChooseOneOptions<T>): Promise<T | undefined>;
|
|
62
|
+
export interface ConfirmOptions {
|
|
63
|
+
title: string;
|
|
64
|
+
initial?: boolean;
|
|
65
|
+
streams?: PromptStreams;
|
|
66
|
+
env?: NodeJS.ProcessEnv;
|
|
67
|
+
}
|
|
68
|
+
export declare function confirm(options: ConfirmOptions): Promise<boolean | undefined>;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;IACxC,WAAW,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC;IACnD,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK,OAAO,CAAC;IAClE,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK,OAAO,CAAC;IACnE,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,OAAO,CAAC;CACtB;AAED,UAAU,YAAY;IACpB,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAOD,wBAAgB,cAAc,IAAI,aAAa,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,OAAO,GAAE,aAAgC,EACzC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAOT;AAsHD,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,4CAA4C;IAC5C,OAAO,EAAE,CAAC,EAAE,CAAC;IACb,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAChC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAC5B,OAAO,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,CAyD1B;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,iEAAiE;AACjE,wBAAsB,SAAS,CAAC,CAAC,EAC/B,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAC3B,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CA2CxB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAW7E"}
|
package/dist/prompt.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A minimal keyboard-driven prompt set.
|
|
3
|
+
*
|
|
4
|
+
* Hand-rolled rather than pulled from a dependency: the primary invocation of
|
|
5
|
+
* this CLI is `npx --yes @wildorder/nightshift`, where every transitive
|
|
6
|
+
* dependency is a user-visible download, and these prompts need to render
|
|
7
|
+
* per-row annotations (resolved path, detection state) that a generic
|
|
8
|
+
* checkbox prompt fights.
|
|
9
|
+
*/
|
|
10
|
+
const HIDE_CURSOR = "\u001B[?25l";
|
|
11
|
+
const SHOW_CURSOR = "\u001B[?25h";
|
|
12
|
+
export function defaultStreams() {
|
|
13
|
+
return { input: process.stdin, output: process.stdout };
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Prompting is only safe when a human is on both ends. The CLI is also driven
|
|
17
|
+
* by npm lifecycle hooks, CI, and the packaged skills themselves — a blocking
|
|
18
|
+
* read in any of those hangs the process.
|
|
19
|
+
*/
|
|
20
|
+
export function isInteractive(streams = defaultStreams(), env = process.env) {
|
|
21
|
+
return (Boolean(streams.input.isTTY) &&
|
|
22
|
+
Boolean(streams.output.isTTY) &&
|
|
23
|
+
typeof streams.input.setRawMode === "function" &&
|
|
24
|
+
!env.CI);
|
|
25
|
+
}
|
|
26
|
+
function decodeKeys(chunk) {
|
|
27
|
+
const keys = [];
|
|
28
|
+
let index = 0;
|
|
29
|
+
while (index < chunk.length) {
|
|
30
|
+
const char = chunk[index] ?? "";
|
|
31
|
+
if (char === "\u001B") {
|
|
32
|
+
const next = chunk[index + 1];
|
|
33
|
+
if (next === "[" || next === "O") {
|
|
34
|
+
// Consume through the sequence's final byte so a function key never
|
|
35
|
+
// leaks through as a stray character.
|
|
36
|
+
let end = index + 2;
|
|
37
|
+
while (end < chunk.length && !/[@-~]/u.test(chunk[end] ?? ""))
|
|
38
|
+
end += 1;
|
|
39
|
+
const final = chunk[end];
|
|
40
|
+
keys.push(final === "A" ? "up" : final === "B" ? "down" : "other");
|
|
41
|
+
index = end + 1;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
// A lone escape cancels; anything else is ignored.
|
|
45
|
+
keys.push(next === undefined ? "abort" : "other");
|
|
46
|
+
index += next === undefined ? 1 : 2;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (char === "\u0003")
|
|
50
|
+
keys.push("abort");
|
|
51
|
+
else if (char === "\r" || char === "\n")
|
|
52
|
+
keys.push("enter");
|
|
53
|
+
else if (char === " ")
|
|
54
|
+
keys.push("space");
|
|
55
|
+
else if (char === "a" || char === "A")
|
|
56
|
+
keys.push("toggleAll");
|
|
57
|
+
else if (char === "k" || char === "p")
|
|
58
|
+
keys.push("up");
|
|
59
|
+
else if (char === "j" || char === "n")
|
|
60
|
+
keys.push("down");
|
|
61
|
+
else
|
|
62
|
+
keys.push("other");
|
|
63
|
+
index += 1;
|
|
64
|
+
}
|
|
65
|
+
return keys;
|
|
66
|
+
}
|
|
67
|
+
function styler(output, env) {
|
|
68
|
+
const enabled = Boolean(output.isTTY) && !env.NO_COLOR;
|
|
69
|
+
const wrap = (code) => (text) => enabled ? `\u001B[${code}m${text}\u001B[0m` : text;
|
|
70
|
+
return {
|
|
71
|
+
dim: wrap("2"),
|
|
72
|
+
cyan: wrap("36"),
|
|
73
|
+
green: wrap("32"),
|
|
74
|
+
bold: wrap("1"),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Drives one prompt to completion, restoring the terminal on every exit. */
|
|
78
|
+
function readKeys(streams, onKey) {
|
|
79
|
+
const { input, output } = streams;
|
|
80
|
+
return new Promise((resolvePromise) => {
|
|
81
|
+
let settled = false;
|
|
82
|
+
const listener = (chunk) => {
|
|
83
|
+
for (const key of decodeKeys(chunk)) {
|
|
84
|
+
if (settled)
|
|
85
|
+
return;
|
|
86
|
+
onKey(key, finish);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const finish = (value) => {
|
|
90
|
+
if (settled)
|
|
91
|
+
return;
|
|
92
|
+
settled = true;
|
|
93
|
+
input.off("data", listener);
|
|
94
|
+
input.setRawMode?.(false);
|
|
95
|
+
input.pause();
|
|
96
|
+
output.write(SHOW_CURSOR);
|
|
97
|
+
resolvePromise(value);
|
|
98
|
+
};
|
|
99
|
+
input.setRawMode?.(true);
|
|
100
|
+
input.setEncoding("utf8");
|
|
101
|
+
input.resume();
|
|
102
|
+
output.write(HIDE_CURSOR);
|
|
103
|
+
input.on("data", listener);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function frame(output) {
|
|
107
|
+
let rendered = 0;
|
|
108
|
+
const clear = () => {
|
|
109
|
+
if (rendered > 0)
|
|
110
|
+
output.write(`\u001B[${rendered}A\u001B[0J`);
|
|
111
|
+
rendered = 0;
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
clear,
|
|
115
|
+
write: (lines) => {
|
|
116
|
+
clear();
|
|
117
|
+
output.write(`${lines.join("\n")}\n`);
|
|
118
|
+
rendered = lines.length;
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function padded(choices) {
|
|
123
|
+
return choices.reduce((width, choice) => Math.max(width, choice.label.length), 0);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Multi-select. Resolves `undefined` when the user cancels, which callers must
|
|
127
|
+
* distinguish from an empty selection.
|
|
128
|
+
*/
|
|
129
|
+
export async function chooseMany(options) {
|
|
130
|
+
const streams = options.streams ?? defaultStreams();
|
|
131
|
+
const style = styler(streams.output, options.env ?? process.env);
|
|
132
|
+
const view = frame(streams.output);
|
|
133
|
+
const width = padded(options.choices);
|
|
134
|
+
const selected = new Set(options.initial);
|
|
135
|
+
let cursor = Math.max(0, options.choices.findIndex((choice) => selected.has(choice.value)));
|
|
136
|
+
const render = () => {
|
|
137
|
+
const lines = [style.bold(options.title), ""];
|
|
138
|
+
options.choices.forEach((choice, index) => {
|
|
139
|
+
const active = index === cursor;
|
|
140
|
+
const box = selected.has(choice.value) ? style.green("◉") : "◯";
|
|
141
|
+
const label = choice.label.padEnd(width);
|
|
142
|
+
const hint = choice.hint ? ` ${style.dim(choice.hint)}` : "";
|
|
143
|
+
lines.push(` ${active ? style.cyan("❯") : " "} ${box} ${active ? style.cyan(label) : label}${hint}`);
|
|
144
|
+
});
|
|
145
|
+
lines.push("", style.dim(" ↑↓ move · space toggle · a all · enter confirm · esc cancel"));
|
|
146
|
+
view.write(lines);
|
|
147
|
+
};
|
|
148
|
+
render();
|
|
149
|
+
const result = await readKeys(streams, (key, done) => {
|
|
150
|
+
if (key === "abort") {
|
|
151
|
+
view.clear();
|
|
152
|
+
done(undefined);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (key === "enter") {
|
|
156
|
+
view.clear();
|
|
157
|
+
done(options.choices.filter((c) => selected.has(c.value)).map((c) => c.value));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (key === "up")
|
|
161
|
+
cursor = (cursor - 1 + options.choices.length) % options.choices.length;
|
|
162
|
+
else if (key === "down")
|
|
163
|
+
cursor = (cursor + 1) % options.choices.length;
|
|
164
|
+
else if (key === "space") {
|
|
165
|
+
const choice = options.choices[cursor];
|
|
166
|
+
if (choice) {
|
|
167
|
+
if (selected.has(choice.value))
|
|
168
|
+
selected.delete(choice.value);
|
|
169
|
+
else
|
|
170
|
+
selected.add(choice.value);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else if (key === "toggleAll") {
|
|
174
|
+
if (selected.size === options.choices.length)
|
|
175
|
+
selected.clear();
|
|
176
|
+
else
|
|
177
|
+
for (const choice of options.choices)
|
|
178
|
+
selected.add(choice.value);
|
|
179
|
+
}
|
|
180
|
+
else
|
|
181
|
+
return;
|
|
182
|
+
render();
|
|
183
|
+
});
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
/** Single-select. Resolves `undefined` when the user cancels. */
|
|
187
|
+
export async function chooseOne(options) {
|
|
188
|
+
const streams = options.streams ?? defaultStreams();
|
|
189
|
+
const style = styler(streams.output, options.env ?? process.env);
|
|
190
|
+
const view = frame(streams.output);
|
|
191
|
+
const width = padded(options.choices);
|
|
192
|
+
let cursor = Math.max(0, options.choices.findIndex((choice) => choice.value === options.initial));
|
|
193
|
+
const render = () => {
|
|
194
|
+
const lines = [style.bold(options.title), ""];
|
|
195
|
+
options.choices.forEach((choice, index) => {
|
|
196
|
+
const active = index === cursor;
|
|
197
|
+
const label = choice.label.padEnd(width);
|
|
198
|
+
const hint = choice.hint ? ` ${style.dim(choice.hint)}` : "";
|
|
199
|
+
lines.push(` ${active ? style.cyan("❯") : " "} ${active ? style.green("●") : "○"} ${active ? style.cyan(label) : label}${hint}`);
|
|
200
|
+
});
|
|
201
|
+
lines.push("", style.dim(" ↑↓ move · enter confirm · esc cancel"));
|
|
202
|
+
view.write(lines);
|
|
203
|
+
};
|
|
204
|
+
render();
|
|
205
|
+
return readKeys(streams, (key, done) => {
|
|
206
|
+
if (key === "abort") {
|
|
207
|
+
view.clear();
|
|
208
|
+
done(undefined);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (key === "enter") {
|
|
212
|
+
view.clear();
|
|
213
|
+
done(options.choices[cursor]?.value);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (key === "up")
|
|
217
|
+
cursor = (cursor - 1 + options.choices.length) % options.choices.length;
|
|
218
|
+
else if (key === "down")
|
|
219
|
+
cursor = (cursor + 1) % options.choices.length;
|
|
220
|
+
else
|
|
221
|
+
return;
|
|
222
|
+
render();
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
export function confirm(options) {
|
|
226
|
+
return chooseOne({
|
|
227
|
+
title: options.title,
|
|
228
|
+
choices: [
|
|
229
|
+
{ value: true, label: "Yes" },
|
|
230
|
+
{ value: false, label: "No" },
|
|
231
|
+
],
|
|
232
|
+
initial: options.initial ?? true,
|
|
233
|
+
...(options.streams ? { streams: options.streams } : {}),
|
|
234
|
+
...(options.env ? { env: options.env } : {}),
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A pre-attempt snapshot of the git worktree. Rejected replanner attempts
|
|
3
|
+
* were "rolled back" by restoring exactly two files, but the replanner is a
|
|
4
|
+
* full agentic CLI that can touch anything — out-of-scope edits and stray
|
|
5
|
+
* temp scripts survived the rollback while the progress line claimed a clean
|
|
6
|
+
* transaction. This guard makes the claim true: capture the whole tracked
|
|
7
|
+
* tree via `git stash create` (which snapshots without touching the
|
|
8
|
+
* worktree) and record which paths were untracked, so a restore can revert
|
|
9
|
+
* every tracked change and delete files the agent created.
|
|
10
|
+
*
|
|
11
|
+
* Limits, stated rather than hidden: modifications to files that were
|
|
12
|
+
* already untracked at capture time cannot be restored (git has no snapshot
|
|
13
|
+
* of them), and gitignored files are invisible to the status listing. In a
|
|
14
|
+
* non-git directory `available` is false and callers fall back to the
|
|
15
|
+
* legacy two-file restore with a warning.
|
|
16
|
+
*/
|
|
17
|
+
export interface WorktreeCapture {
|
|
18
|
+
available: boolean;
|
|
19
|
+
/** Git repository toplevel; all recorded paths are relative to it. */
|
|
20
|
+
toplevel?: string;
|
|
21
|
+
/** Commit whose tree is the captured tracked state. */
|
|
22
|
+
source?: string;
|
|
23
|
+
/** Paths untracked at capture; never deleted by a restore. */
|
|
24
|
+
untracked?: Set<string>;
|
|
25
|
+
}
|
|
26
|
+
export declare function captureWorktree(root: string): Promise<WorktreeCapture>;
|
|
27
|
+
export interface WorktreeRestoreResult {
|
|
28
|
+
restored: boolean;
|
|
29
|
+
/** Tracked paths whose state drifted from the capture (before restoring). */
|
|
30
|
+
drifted: string[];
|
|
31
|
+
/** Newly created untracked files that were deleted. */
|
|
32
|
+
removed: string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Revert the worktree to `capture`, except `preservePaths` (absolute or
|
|
36
|
+
* root-relative), which keep their current content. Newly created untracked
|
|
37
|
+
* files outside the preserve list are deleted.
|
|
38
|
+
*/
|
|
39
|
+
export declare function restoreWorktree(root: string, capture: WorktreeCapture, preservePaths?: string[]): Promise<WorktreeRestoreResult>;
|
|
40
|
+
//# sourceMappingURL=worktree-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-guard.d.ts","sourceRoot":"","sources":["../src/worktree-guard.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;AAyBD,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAc5E;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,uDAAuD;IACvD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAID;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,eAAe,EACxB,aAAa,GAAE,MAAM,EAAO,GAC3B,OAAO,CAAC,qBAAqB,CAAC,CAwChC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { realpath, rm } from "node:fs/promises";
|
|
3
|
+
import { join, relative, resolve } from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
/** Symlinked temp dirs (macOS /tmp) make raw paths disagree with git's realpathed toplevel. */
|
|
6
|
+
async function canonical(path) {
|
|
7
|
+
try {
|
|
8
|
+
return await realpath(path);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return path;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const run = promisify(execFile);
|
|
15
|
+
async function git(cwd, args) {
|
|
16
|
+
const { stdout } = await run("git", args, { cwd, maxBuffer: 64 * 1024 * 1024 });
|
|
17
|
+
return stdout;
|
|
18
|
+
}
|
|
19
|
+
function parseStatus(raw) {
|
|
20
|
+
const tokens = raw.split("\0").filter((token) => token !== "");
|
|
21
|
+
const entries = [];
|
|
22
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
23
|
+
const token = tokens[index];
|
|
24
|
+
const code = token.slice(0, 2);
|
|
25
|
+
entries.push({ code, path: token.slice(3) });
|
|
26
|
+
// Rename/copy entries carry the original path as a second NUL token.
|
|
27
|
+
if (code.startsWith("R") || code.startsWith("C"))
|
|
28
|
+
index += 1;
|
|
29
|
+
}
|
|
30
|
+
return entries;
|
|
31
|
+
}
|
|
32
|
+
export async function captureWorktree(root) {
|
|
33
|
+
try {
|
|
34
|
+
const toplevel = (await git(resolve(root), ["rev-parse", "--show-toplevel"])).trim();
|
|
35
|
+
const status = parseStatus(await git(toplevel, ["status", "--porcelain", "-z"]));
|
|
36
|
+
const stash = (await git(toplevel, ["stash", "create"])).trim();
|
|
37
|
+
return {
|
|
38
|
+
available: true,
|
|
39
|
+
toplevel,
|
|
40
|
+
source: stash || "HEAD",
|
|
41
|
+
untracked: new Set(status.filter(({ code }) => code === "??").map(({ path }) => path)),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return { available: false };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const toPosix = (path) => path.replaceAll("\\", "/");
|
|
49
|
+
/**
|
|
50
|
+
* Revert the worktree to `capture`, except `preservePaths` (absolute or
|
|
51
|
+
* root-relative), which keep their current content. Newly created untracked
|
|
52
|
+
* files outside the preserve list are deleted.
|
|
53
|
+
*/
|
|
54
|
+
export async function restoreWorktree(root, capture, preservePaths = []) {
|
|
55
|
+
if (!capture.available || !capture.toplevel || !capture.source) {
|
|
56
|
+
return { restored: false, drifted: [], removed: [] };
|
|
57
|
+
}
|
|
58
|
+
const toplevel = await canonical(capture.toplevel);
|
|
59
|
+
const preserve = new Set(await Promise.all(preservePaths.map(async (path) => toPosix(relative(toplevel, await canonical(resolve(root, path)))))));
|
|
60
|
+
try {
|
|
61
|
+
// Tracked drift is worktree-vs-snapshot content difference, not a status
|
|
62
|
+
// comparison: a file dirty at capture and dirtied further by the agent
|
|
63
|
+
// has an identical status entry and would slip through.
|
|
64
|
+
const trackedDrift = (await git(toplevel, ["diff", "--name-only", "-z", capture.source]))
|
|
65
|
+
.split("\0")
|
|
66
|
+
.filter((path) => path !== "" && !preserve.has(path));
|
|
67
|
+
const current = parseStatus(await git(toplevel, ["status", "--porcelain", "-z"]));
|
|
68
|
+
const removed = [];
|
|
69
|
+
for (const { code, path } of current) {
|
|
70
|
+
if (code !== "??" || capture.untracked.has(path) || preserve.has(path))
|
|
71
|
+
continue;
|
|
72
|
+
await rm(join(toplevel, path), { force: true, recursive: true });
|
|
73
|
+
removed.push(path);
|
|
74
|
+
}
|
|
75
|
+
if (trackedDrift.length > 0) {
|
|
76
|
+
await git(toplevel, [
|
|
77
|
+
"restore",
|
|
78
|
+
"--source",
|
|
79
|
+
capture.source,
|
|
80
|
+
"--worktree",
|
|
81
|
+
"--",
|
|
82
|
+
...trackedDrift,
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
85
|
+
return { restored: true, drifted: trackedDrift, removed };
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return { restored: false, drifted: [], removed: [] };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=worktree-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-guard.js","sourceRoot":"","sources":["../src/worktree-guard.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wildorder/nightshift",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The crew that builds while you're gone: walk-away, CI-dispatched engineering programs with a decision ledger instead of gates",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
15
|
+
"build": "npm run clean && tsc -p tsconfig.json",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"lint": "eslint .",
|
|
19
|
+
"prepack": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"agents",
|
|
28
|
+
"autonomous",
|
|
29
|
+
"engineering-programs",
|
|
30
|
+
"decision-ledger",
|
|
31
|
+
"claude-code",
|
|
32
|
+
"codex",
|
|
33
|
+
"cursor"
|
|
34
|
+
],
|
|
35
|
+
"author": "Wing It Labs",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"type": "module",
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/wildorder/nightshift.git"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"bin": {
|
|
49
|
+
"nightshift": "dist/cli.js"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"commander": "^15.0.0",
|
|
53
|
+
"zod": "^4.4.3"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@eslint/js": "^10.0.1",
|
|
57
|
+
"@types/node": "^26.1.2",
|
|
58
|
+
"eslint": "^10.8.0",
|
|
59
|
+
"typescript": "^6.0.3",
|
|
60
|
+
"typescript-eslint": "^8.66.0",
|
|
61
|
+
"vitest": "^4.1.10"
|
|
62
|
+
}
|
|
63
|
+
}
|