runshift 0.0.3 → 0.0.5
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/.claude/settings.local.json +4 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +149 -16
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/remove.d.ts +2 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +49 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/context/collector.d.ts.map +1 -1
- package/dist/context/collector.js +33 -0
- package/dist/context/collector.js.map +1 -1
- package/dist/index.js +17 -5
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/display.d.ts +5 -0
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +56 -4
- package/dist/ui/display.js.map +1 -1
- package/dist/ui/prompt.d.ts +2 -0
- package/dist/ui/prompt.d.ts.map +1 -1
- package/dist/ui/prompt.js +37 -0
- package/dist/ui/prompt.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/init.ts +180 -18
- package/src/commands/remove.ts +59 -0
- package/src/context/collector.ts +44 -0
- package/src/index.ts +17 -5
- package/src/types.ts +2 -0
- package/src/ui/display.ts +59 -4
- package/src/ui/prompt.ts +42 -0
package/src/index.ts
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { init } from "./commands/init.js";
|
|
4
|
+
import { remove } from "./commands/remove.js";
|
|
4
5
|
|
|
5
6
|
const args = process.argv.slice(2);
|
|
6
7
|
const command = args[0] ?? "init";
|
|
7
8
|
|
|
8
9
|
switch (command) {
|
|
9
10
|
case "init":
|
|
10
|
-
init().catch((err) => {
|
|
11
|
+
init(args.slice(1)).catch((err) => {
|
|
12
|
+
console.error(err.message ?? err);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
});
|
|
15
|
+
break;
|
|
16
|
+
case "remove":
|
|
17
|
+
remove().catch((err) => {
|
|
11
18
|
console.error(err.message ?? err);
|
|
12
19
|
process.exit(1);
|
|
13
20
|
});
|
|
14
21
|
break;
|
|
15
22
|
case "--version":
|
|
16
23
|
case "-v":
|
|
17
|
-
console.log("runshift 0.0.
|
|
24
|
+
console.log("runshift 0.0.3");
|
|
18
25
|
break;
|
|
19
26
|
case "--help":
|
|
20
27
|
case "-h":
|
|
@@ -22,11 +29,16 @@ switch (command) {
|
|
|
22
29
|
runshift — the control plane for agents, wherever they run.
|
|
23
30
|
|
|
24
31
|
Usage:
|
|
25
|
-
npx runshift init
|
|
32
|
+
npx runshift init [options] Read your repo, generate governance rules
|
|
33
|
+
npx runshift remove Revert the runshift install commit
|
|
26
34
|
|
|
27
35
|
Options:
|
|
28
|
-
--version, -v
|
|
29
|
-
--help, -h
|
|
36
|
+
--version, -v Show version
|
|
37
|
+
--help, -h Show this help
|
|
38
|
+
|
|
39
|
+
Init options:
|
|
40
|
+
--dry-run Preview changes without writing files
|
|
41
|
+
--branch <name> Run on a new branch (default: relay-init)
|
|
30
42
|
`);
|
|
31
43
|
break;
|
|
32
44
|
default:
|
package/src/types.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface RepoContext {
|
|
|
17
17
|
migrationCount: number;
|
|
18
18
|
migrationNames: string[];
|
|
19
19
|
rootConfigs: string[];
|
|
20
|
+
protectedPaths: string[];
|
|
20
21
|
gitState: {
|
|
21
22
|
branch: string;
|
|
22
23
|
isDirty: boolean;
|
|
@@ -41,4 +42,5 @@ export interface InitResponse {
|
|
|
41
42
|
files: GeneratedFile[];
|
|
42
43
|
findings: Findings;
|
|
43
44
|
summary: string;
|
|
45
|
+
previewId?: string;
|
|
44
46
|
}
|
package/src/ui/display.ts
CHANGED
|
@@ -13,8 +13,9 @@ export function showBanner(): void {
|
|
|
13
13
|
horizontalLayout: "default",
|
|
14
14
|
});
|
|
15
15
|
console.log(amber(banner));
|
|
16
|
-
console.log(muted(" v0.0.
|
|
17
|
-
console.log(muted(" the control plane for agents, wherever they run
|
|
16
|
+
console.log(muted(" v0.0.3"));
|
|
17
|
+
console.log(muted(" the control plane for agents, wherever they run."));
|
|
18
|
+
console.log(dim(" usage: npx runshift init [--dry-run] [--branch <name>]\n"));
|
|
18
19
|
console.log(divider + "\n");
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -62,13 +63,17 @@ export function showScanResults(context: RepoContext): void {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
const existingRuleKeys = Object.keys(context.existingRules);
|
|
66
|
+
const protectedSet = new Set(context.protectedPaths);
|
|
65
67
|
const cursorRules = existingRuleKeys.filter((k) => k.startsWith(".cursor/rules/"));
|
|
66
68
|
if (cursorRules.length > 0) {
|
|
67
|
-
|
|
69
|
+
const protectedCount = cursorRules.filter((k) => protectedSet.has(k)).length;
|
|
70
|
+
const suffix = protectedCount > 0 ? ` (${protectedCount} protected)` : "";
|
|
71
|
+
detections.push(`.cursor/rules/ — ${cursorRules.length} existing file${cursorRules.length === 1 ? "" : "s"} detected${suffix}`);
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
if (existingRuleKeys.includes("CLAUDE.md")) {
|
|
71
|
-
|
|
75
|
+
const claudeProtected = protectedSet.has("CLAUDE.md") ? " (protected — human-written)" : "";
|
|
76
|
+
detections.push(`existing CLAUDE.md detected${claudeProtected}`);
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
if (context.tsconfig) {
|
|
@@ -120,6 +125,19 @@ export function showFileList(files: GeneratedFile[]): void {
|
|
|
120
125
|
console.log(dim("\n + = create, ~ = update existing file\n"));
|
|
121
126
|
}
|
|
122
127
|
|
|
128
|
+
export function showSelectedFiles(allFiles: GeneratedFile[], selectedPaths: string[]): void {
|
|
129
|
+
const selected = new Set(selectedPaths);
|
|
130
|
+
console.log(amber(" relay understood:\n"));
|
|
131
|
+
for (const file of allFiles) {
|
|
132
|
+
if (selected.has(file.path)) {
|
|
133
|
+
console.log(dim(" ✓ ") + file.path + dim(" (included)"));
|
|
134
|
+
} else {
|
|
135
|
+
console.log(dim(" ✗ ") + muted(file.path) + dim(" (excluded)"));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
console.log();
|
|
139
|
+
}
|
|
140
|
+
|
|
123
141
|
export function showWriting(filePath: string): void {
|
|
124
142
|
console.log(dim(" ✓ ") + filePath);
|
|
125
143
|
}
|
|
@@ -128,6 +146,16 @@ export function showCommit(): void {
|
|
|
128
146
|
console.log(dim(" ✓ ") + "committed");
|
|
129
147
|
}
|
|
130
148
|
|
|
149
|
+
export function showProtectedFiles(protectedPaths: string[]): void {
|
|
150
|
+
if (protectedPaths.length === 0) return;
|
|
151
|
+
console.log();
|
|
152
|
+
console.log(amber(" relay preserved your existing files:"));
|
|
153
|
+
for (const p of protectedPaths) {
|
|
154
|
+
console.log(dim(` ~ ${p} — human-written, not overwritten`));
|
|
155
|
+
}
|
|
156
|
+
console.log(dim(" run npx runshift update to review suggested changes.\n"));
|
|
157
|
+
}
|
|
158
|
+
|
|
131
159
|
export function showSummary(summary: string): void {
|
|
132
160
|
console.log(muted(` ${summary.replace(/\n/g, "\n ")}\n`));
|
|
133
161
|
}
|
|
@@ -142,6 +170,33 @@ export function showSuccess(): void {
|
|
|
142
170
|
console.log("\n" + divider + "\n");
|
|
143
171
|
}
|
|
144
172
|
|
|
173
|
+
export function showDataPolicy(): void {
|
|
174
|
+
console.log(amber(" relay will send to runshift.ai:\n"));
|
|
175
|
+
console.log(dim(" ✓ package.json (dependencies and scripts only)"));
|
|
176
|
+
console.log(dim(" ✓ directory structure (top 2 levels, folder names only)"));
|
|
177
|
+
console.log(dim(" ✓ .env.example (key names only — values are never read)"));
|
|
178
|
+
console.log(dim(" ✓ existing CLAUDE.md (if present)"));
|
|
179
|
+
console.log(dim(" ✓ existing .cursor/rules/ (if present)"));
|
|
180
|
+
console.log(dim(" ✓ migration file names (no file contents)"));
|
|
181
|
+
console.log(dim("\n no source code is sent."));
|
|
182
|
+
console.log(dim(" no secret values are ever read.\n"));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function showDryRunComplete(): void {
|
|
186
|
+
console.log("\n" + divider + "\n");
|
|
187
|
+
console.log(amber(" dry run complete — no files written."));
|
|
188
|
+
console.log(dim(" run npx runshift init to install.\n"));
|
|
189
|
+
console.log(divider + "\n");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function showCancelled(): void {
|
|
193
|
+
console.log();
|
|
194
|
+
console.log(amber(" no changes made."));
|
|
195
|
+
console.log(dim(" run npx runshift init when you're ready."));
|
|
196
|
+
console.log();
|
|
197
|
+
console.log(divider + "\n");
|
|
198
|
+
}
|
|
199
|
+
|
|
145
200
|
export function showError(type: "network" | "rate-limit" | "validation" | "server", message?: string): void {
|
|
146
201
|
console.log();
|
|
147
202
|
switch (type) {
|
package/src/ui/prompt.ts
CHANGED
|
@@ -31,3 +31,45 @@ export async function promptChoice(question: string): Promise<"y" | "a" | "n"> {
|
|
|
31
31
|
export async function promptFilePath(question: string): Promise<string> {
|
|
32
32
|
return ask(question);
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
export async function promptFileSelection(question: string): Promise<"a" | "s" | "n"> {
|
|
36
|
+
const answer = await ask(question);
|
|
37
|
+
const normalized = answer.toLowerCase();
|
|
38
|
+
if (normalized === "a" || normalized === "accept") return "a";
|
|
39
|
+
if (normalized === "s" || normalized === "select") return "s";
|
|
40
|
+
return "n";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function promptPreview(message: string): Promise<boolean> {
|
|
44
|
+
return new Promise((resolve) => {
|
|
45
|
+
process.stdout.write(message);
|
|
46
|
+
|
|
47
|
+
const wasRaw = process.stdin.isRaw;
|
|
48
|
+
process.stdin.setRawMode(true);
|
|
49
|
+
process.stdin.resume();
|
|
50
|
+
|
|
51
|
+
const onData = (key: Buffer) => {
|
|
52
|
+
process.stdin.setRawMode(wasRaw ?? false);
|
|
53
|
+
process.stdin.pause();
|
|
54
|
+
process.stdin.removeListener("data", onData);
|
|
55
|
+
|
|
56
|
+
const ch = key.toString();
|
|
57
|
+
|
|
58
|
+
// ctrl-c
|
|
59
|
+
if (ch === "\x03") {
|
|
60
|
+
console.log();
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (ch.toLowerCase() === "o") {
|
|
65
|
+
console.log("o\n");
|
|
66
|
+
resolve(true);
|
|
67
|
+
} else {
|
|
68
|
+
console.log("\n");
|
|
69
|
+
resolve(false);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
process.stdin.on("data", onData);
|
|
74
|
+
});
|
|
75
|
+
}
|