@bobbyg603/mog 0.1.3 → 0.2.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/package.json +1 -1
- package/src/index.ts +68 -4
- package/src/sandbox.ts +13 -2
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { pushAndCreatePR } from "./github";
|
|
|
8
8
|
import { log } from "./log";
|
|
9
9
|
|
|
10
10
|
const SANDBOX_NAME = "mog";
|
|
11
|
+
const TEMPLATE_TAG = "mog-template:latest";
|
|
11
12
|
|
|
12
13
|
async function init() {
|
|
13
14
|
log.info("Initializing mog sandbox...");
|
|
@@ -43,6 +44,17 @@ async function init() {
|
|
|
43
44
|
log.die("Sandbox failed to run. Try 'docker sandbox ls' to check its status.");
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
// Save sandbox as template so it can be restored after Docker restarts
|
|
48
|
+
log.info("Saving sandbox snapshot (preserves auth across Docker restarts)...");
|
|
49
|
+
const saveResult = spawnSync("docker", ["sandbox", "save", SANDBOX_NAME, TEMPLATE_TAG], {
|
|
50
|
+
stdio: "inherit",
|
|
51
|
+
});
|
|
52
|
+
if (saveResult.status !== 0) {
|
|
53
|
+
log.warn("Failed to save sandbox snapshot. Auth may not persist across Docker restarts.");
|
|
54
|
+
} else {
|
|
55
|
+
log.ok("Snapshot saved.");
|
|
56
|
+
}
|
|
57
|
+
|
|
46
58
|
log.ok("mog is ready. Run: mog <owner/repo> <issue_number>");
|
|
47
59
|
}
|
|
48
60
|
|
|
@@ -57,10 +69,13 @@ async function main() {
|
|
|
57
69
|
}
|
|
58
70
|
}
|
|
59
71
|
|
|
60
|
-
// Check docker sandbox is available
|
|
72
|
+
// Check docker sandbox is available (may fail if sandbox state is stale after Docker restart)
|
|
61
73
|
const sandboxCheck = Bun.spawnSync(["docker", "sandbox", "ls"]);
|
|
62
74
|
if (sandboxCheck.exitCode !== 0) {
|
|
63
|
-
|
|
75
|
+
const recovered = tryRecoverSandbox(getReposDir());
|
|
76
|
+
if (!recovered) {
|
|
77
|
+
log.die("Docker sandbox not available. Make sure Docker Desktop is running and up to date.");
|
|
78
|
+
}
|
|
64
79
|
}
|
|
65
80
|
|
|
66
81
|
if (args[0] === "init") {
|
|
@@ -87,9 +102,18 @@ async function main() {
|
|
|
87
102
|
log.die("Invalid repo format. Use: owner/repo");
|
|
88
103
|
}
|
|
89
104
|
|
|
90
|
-
// Verify sandbox exists
|
|
105
|
+
// Verify sandbox exists, try to restore from template if missing
|
|
91
106
|
if (!(await sandboxExists(SANDBOX_NAME))) {
|
|
92
|
-
|
|
107
|
+
if (!templateExists()) {
|
|
108
|
+
log.die(`Sandbox '${SANDBOX_NAME}' not found. Run 'mog init' first.`);
|
|
109
|
+
}
|
|
110
|
+
log.info("Sandbox missing — restoring from saved snapshot...");
|
|
111
|
+
const reposDir = getReposDir();
|
|
112
|
+
const restored = restoreSandboxFromTemplate(SANDBOX_NAME, reposDir);
|
|
113
|
+
if (!restored) {
|
|
114
|
+
log.die("Failed to restore sandbox from snapshot. Run 'mog init' to recreate.");
|
|
115
|
+
}
|
|
116
|
+
log.ok("Sandbox restored from snapshot (auth preserved).");
|
|
93
117
|
}
|
|
94
118
|
|
|
95
119
|
// Fetch issue
|
|
@@ -130,6 +154,46 @@ async function sandboxExists(name: string): Promise<boolean> {
|
|
|
130
154
|
return output.includes(name);
|
|
131
155
|
}
|
|
132
156
|
|
|
157
|
+
function templateExists(): boolean {
|
|
158
|
+
const result = Bun.spawnSync(["docker", "image", "inspect", TEMPLATE_TAG]);
|
|
159
|
+
return result.exitCode === 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function restoreSandboxFromTemplate(name: string, reposDir: string): boolean {
|
|
163
|
+
const create = spawnSync("docker", ["sandbox", "create", "--template", TEMPLATE_TAG, "--name", name, "claude", reposDir], {
|
|
164
|
+
stdio: "inherit",
|
|
165
|
+
});
|
|
166
|
+
return create.status === 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function tryRecoverSandbox(reposDir: string): boolean {
|
|
170
|
+
log.warn("Docker sandbox state is stale — attempting recovery...");
|
|
171
|
+
|
|
172
|
+
// Clean up stale sandbox
|
|
173
|
+
spawnSync("docker", ["sandbox", "rm", SANDBOX_NAME], { stdio: "ignore" });
|
|
174
|
+
|
|
175
|
+
// Check if docker sandbox ls works now
|
|
176
|
+
const check = Bun.spawnSync(["docker", "sandbox", "ls"]);
|
|
177
|
+
if (check.exitCode !== 0) {
|
|
178
|
+
// docker sandbox itself is broken, not just stale state
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// If we have a saved template, restore from it
|
|
183
|
+
if (templateExists()) {
|
|
184
|
+
log.info("Restoring sandbox from saved snapshot...");
|
|
185
|
+
const restored = restoreSandboxFromTemplate(SANDBOX_NAME, reposDir);
|
|
186
|
+
if (restored) {
|
|
187
|
+
log.ok("Sandbox restored from snapshot (auth preserved).");
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Recovered docker sandbox command but no template — user needs to mog init
|
|
193
|
+
log.warn("No saved snapshot found. Run 'mog init' to set up the sandbox.");
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
133
197
|
async function run(cmd: string[]): Promise<string> {
|
|
134
198
|
const proc = Bun.spawnSync(cmd);
|
|
135
199
|
if (proc.exitCode !== 0) {
|
package/src/sandbox.ts
CHANGED
|
@@ -15,14 +15,25 @@ interface StreamEvent {
|
|
|
15
15
|
is_error?: boolean;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export async function ensureSandbox(name: string, reposDir: string): Promise<void> {
|
|
18
|
+
export async function ensureSandbox(name: string, reposDir: string, templateTag?: string): Promise<void> {
|
|
19
19
|
const ls = Bun.spawnSync(["docker", "sandbox", "ls"]);
|
|
20
20
|
if (ls.stdout.toString().includes(name)) {
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
// Try to restore from template if available
|
|
25
|
+
const createArgs = ["sandbox", "create"];
|
|
26
|
+
if (templateTag) {
|
|
27
|
+
const inspect = Bun.spawnSync(["docker", "image", "inspect", templateTag]);
|
|
28
|
+
if (inspect.exitCode === 0) {
|
|
29
|
+
log.info(`Restoring sandbox '${name}' from saved snapshot...`);
|
|
30
|
+
createArgs.push("--template", templateTag);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
createArgs.push("--name", name, "claude", reposDir);
|
|
34
|
+
|
|
24
35
|
log.info(`Creating persistent sandbox '${name}'...`);
|
|
25
|
-
const create = Bun.spawnSync(["docker",
|
|
36
|
+
const create = Bun.spawnSync(["docker", ...createArgs]);
|
|
26
37
|
if (create.exitCode !== 0) {
|
|
27
38
|
log.die(`Failed to create sandbox: ${create.stderr.toString()}`);
|
|
28
39
|
}
|