@moglenny/content-workbench-agent 0.1.2 → 0.1.3
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/bin.mjs +52 -12
package/package.json
CHANGED
package/src/bin.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { realpathSync } from "node:fs";
|
|
5
|
-
import { mkdir, rm, stat } from "node:fs/promises";
|
|
5
|
+
import { mkdir, rename, rm, stat } from "node:fs/promises";
|
|
6
6
|
import os from "node:os";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
@@ -40,9 +40,12 @@ Options:
|
|
|
40
40
|
--repo-url <url> Git repository URL. Defaults to the official content workbench repo.
|
|
41
41
|
--branch <name> Branch to install from. Defaults to main.
|
|
42
42
|
--repo-dir <path> Local managed clone path. Defaults to ~/.content-workbench/agent/topic-dashboard.
|
|
43
|
+
--cli-prefix <path> User-owned npm prefix for cw. Defaults to ~/.content-workbench/npm.
|
|
43
44
|
--skills-target <path> Skill install target. Repeatable.
|
|
44
45
|
--mcp-target <path> Write MCP config snippet to this JSON file.
|
|
45
|
-
--
|
|
46
|
+
--shell-profile <path> Shell profile that should include cw in PATH.
|
|
47
|
+
--skip-cli Do not install the user-level cw CLI.
|
|
48
|
+
--skip-shell-profile Do not add cw to the shell profile PATH.
|
|
46
49
|
--skip-skills Do not copy Skills.
|
|
47
50
|
--skip-mcp Do not write MCP config.
|
|
48
51
|
--api-base-url <url> Base URL shown in post-install setup guidance.
|
|
@@ -92,13 +95,13 @@ export function parseAgentInstallerArgs(argv = process.argv.slice(2)) {
|
|
|
92
95
|
options.repoDir = path.resolve(expandHome(args[++index] || ""));
|
|
93
96
|
continue;
|
|
94
97
|
}
|
|
95
|
-
if (arg === "--skills-target" || arg === "--mcp-target" || arg === "--api-base-url") {
|
|
98
|
+
if (arg === "--skills-target" || arg === "--mcp-target" || arg === "--api-base-url" || arg === "--cli-prefix" || arg === "--shell-profile") {
|
|
96
99
|
const value = args[++index];
|
|
97
100
|
if (!value) throw new Error(`Missing value for ${arg}`);
|
|
98
101
|
options.installArgs.push(arg, value);
|
|
99
102
|
continue;
|
|
100
103
|
}
|
|
101
|
-
if (arg === "--skip-cli" || arg === "--skip-skills" || arg === "--skip-mcp") {
|
|
104
|
+
if (arg === "--skip-cli" || arg === "--skip-shell-profile" || arg === "--skip-skills" || arg === "--skip-mcp") {
|
|
102
105
|
options.installArgs.push(arg);
|
|
103
106
|
continue;
|
|
104
107
|
}
|
|
@@ -217,6 +220,24 @@ async function runStepWithRetry(step, options) {
|
|
|
217
220
|
}
|
|
218
221
|
}
|
|
219
222
|
|
|
223
|
+
async function runSteps(steps, options) {
|
|
224
|
+
for (const step of steps) {
|
|
225
|
+
await runStepWithRetry(step, options);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function clearManagedRepo(options) {
|
|
230
|
+
try {
|
|
231
|
+
await options.removeDir(options.repoDir, { recursive: true, force: true });
|
|
232
|
+
return null;
|
|
233
|
+
} catch {
|
|
234
|
+
const quarantineDir = `${options.repoDir}.broken-${options.now()}`;
|
|
235
|
+
await options.renameDir(options.repoDir, quarantineDir);
|
|
236
|
+
options.stdout.write(`Moved inaccessible managed repository to ${quarantineDir}\n`);
|
|
237
|
+
return quarantineDir;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
220
241
|
function printPlan(plan, stdout) {
|
|
221
242
|
stdout.write(`${plan.dryRun ? "Content Workbench Agent install dry run" : "Content Workbench Agent install"}\n`);
|
|
222
243
|
stdout.write(`Managed repository: ${plan.repoDir}\n`);
|
|
@@ -244,15 +265,34 @@ export async function runAgentInstaller(argv = process.argv.slice(2), io = proce
|
|
|
244
265
|
|
|
245
266
|
const runner = io.run || run;
|
|
246
267
|
const removeDir = io.removeDir || rm;
|
|
268
|
+
const renameDir = io.renameDir || rename;
|
|
247
269
|
const wait = io.sleep || sleep;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
270
|
+
const runnerOptions = {
|
|
271
|
+
runner,
|
|
272
|
+
removeDir,
|
|
273
|
+
renameDir,
|
|
274
|
+
repoDir: options.repoDir,
|
|
275
|
+
sleep: wait,
|
|
276
|
+
now: io.now || Date.now,
|
|
277
|
+
stdout: io.stdout,
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
if (repoExists) {
|
|
281
|
+
const updateSteps = plan.steps.slice(0, 3);
|
|
282
|
+
const installStep = plan.steps.at(-1);
|
|
283
|
+
try {
|
|
284
|
+
await runSteps(updateSteps, runnerOptions);
|
|
285
|
+
} catch {
|
|
286
|
+
io.stdout.write("Existing managed repository could not be updated. Recreating a clean managed repository...\n");
|
|
287
|
+
const quarantinedRepoDir = await clearManagedRepo(runnerOptions);
|
|
288
|
+
const cleanPlan = buildInstallPlan(options, false);
|
|
289
|
+
await runSteps(cleanPlan.steps, runnerOptions);
|
|
290
|
+
io.stdout.write("Content Workbench Agent install complete\n");
|
|
291
|
+
return { ...cleanPlan, recreatedExistingRepo: true, quarantinedRepoDir };
|
|
292
|
+
}
|
|
293
|
+
await runSteps([installStep], runnerOptions);
|
|
294
|
+
} else {
|
|
295
|
+
await runSteps(plan.steps, runnerOptions);
|
|
256
296
|
}
|
|
257
297
|
|
|
258
298
|
io.stdout.write("Content Workbench Agent install complete\n");
|