argos-harness 0.1.0 → 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.
Files changed (38) hide show
  1. package/assets/hooks/argos-guard-destructive.sh +1 -1
  2. package/assets/managed/disciplina-skills.md +11 -0
  3. package/assets/managed/formato-respuesta.md +2 -2
  4. package/assets/managed/identidad.md +7 -7
  5. package/assets/managed/operaciones-seguras.md +6 -6
  6. package/assets/output-styles/argos.md +12 -12
  7. package/dist/commands/adopt.d.ts +41 -1
  8. package/dist/commands/adopt.d.ts.map +1 -1
  9. package/dist/commands/adopt.js +243 -6
  10. package/dist/commands/adopt.js.map +1 -1
  11. package/dist/commands/doctor.d.ts.map +1 -1
  12. package/dist/commands/doctor.js +36 -2
  13. package/dist/commands/doctor.js.map +1 -1
  14. package/dist/commands/init.d.ts +38 -0
  15. package/dist/commands/init.d.ts.map +1 -1
  16. package/dist/commands/init.js +222 -59
  17. package/dist/commands/init.js.map +1 -1
  18. package/dist/commands/remove.d.ts +24 -0
  19. package/dist/commands/remove.d.ts.map +1 -1
  20. package/dist/commands/remove.js +94 -4
  21. package/dist/commands/remove.js.map +1 -1
  22. package/dist/commands/workspace.d.ts +32 -0
  23. package/dist/commands/workspace.d.ts.map +1 -1
  24. package/dist/commands/workspace.js +97 -3
  25. package/dist/commands/workspace.js.map +1 -1
  26. package/dist/lib/assets.d.ts +5 -3
  27. package/dist/lib/assets.d.ts.map +1 -1
  28. package/dist/lib/assets.js +5 -2
  29. package/dist/lib/assets.js.map +1 -1
  30. package/dist/lib/prompter.d.ts +63 -0
  31. package/dist/lib/prompter.d.ts.map +1 -0
  32. package/dist/lib/prompter.js +30 -0
  33. package/dist/lib/prompter.js.map +1 -0
  34. package/dist/lib/settings-merge.d.ts +78 -0
  35. package/dist/lib/settings-merge.d.ts.map +1 -1
  36. package/dist/lib/settings-merge.js +204 -0
  37. package/dist/lib/settings-merge.js.map +1 -1
  38. package/package.json +1 -1
@@ -8,7 +8,8 @@ import { createBackup } from "../lib/backup.js";
8
8
  import { listBlocks, removeBlock } from "../lib/markers.js";
9
9
  import { hasArgosFileMarker, hasArgosShellFileMarker } from "../lib/managed-files.js";
10
10
  import { resolveArgosHome, resolveClaudeDir } from "../lib/paths.js";
11
- import { removeAllArgosHooksFromSettings } from "../lib/settings-merge.js";
11
+ import { isInteractive, clackPrompter } from "../lib/prompter.js";
12
+ import { removeAllArgosHooksFromSettings, removeOutputStyleIfArgos } from "../lib/settings-merge.js";
12
13
  const STATUS_COUNT_ORDER = [
13
14
  "removed",
14
15
  "would-remove",
@@ -412,6 +413,28 @@ function processPurge(apply, rows, warnings) {
412
413
  detail: `${settingsResult.removedCount} hook ${noun}`
413
414
  });
414
415
  }
416
+ // Voice activation (spec 0004): remove settings.json.outputStyle ONLY when
417
+ // it's still exactly "Argos" — the value argos init wrote. Any other
418
+ // voice (a foreign one init never touched, or the key simply absent) is
419
+ // left byte-identical; this is `argos remove`'s own value to clean up
420
+ // after, never the user's.
421
+ const outputStyleResult = removeOutputStyleIfArgos(settingsPath, {
422
+ dryRun: !apply
423
+ });
424
+ if (outputStyleResult.status === "error") {
425
+ rows.push({
426
+ path: "settings.json#outputStyle",
427
+ category: "settings-entries",
428
+ status: "error",
429
+ detail: outputStyleResult.detail
430
+ });
431
+ } else if (outputStyleResult.status === "removed") {
432
+ rows.push({
433
+ path: "settings.json#outputStyle",
434
+ category: "settings-entries",
435
+ status: apply ? "removed" : "would-remove"
436
+ });
437
+ }
415
438
  if (purge) processPurge(apply, rows, warnings);
416
439
  // Always-present closing note: repo-side artifacts (argos.config.json, the
417
440
  // ficha block in a repo's own CLAUDE.md) are out of scope for `remove` —
@@ -431,6 +454,67 @@ function processPurge(apply, rows, warnings) {
431
454
  warnings
432
455
  };
433
456
  }
457
+ /**
458
+ * A cancelled confirmation's report: identical shape to a run that touched
459
+ * nothing. `exitCode: 1` — a cancel is neither a successful write nor
460
+ * silently indistinguishable from one by exit code alone (matches
461
+ * `runWorkspaceLinkInteractive`'s convention for its own cancel paths).
462
+ */ function cancelledRemoveReport(reason) {
463
+ return {
464
+ rows: [
465
+ {
466
+ path: "cancel",
467
+ category: "scope-note",
468
+ status: "info",
469
+ detail: reason
470
+ }
471
+ ],
472
+ summary: `argos remove: cancelado — no se tocó nada (${reason}).`,
473
+ exitCode: 1,
474
+ warnings: []
475
+ };
476
+ }
477
+ /**
478
+ * Interactive layer over `runRemove` (spec 0004 F5 "argos remove"). A pure
479
+ * additive wrapper — the core `runRemove` never changes behavior or
480
+ * contract. Without a real TTY, with `--yes`, or for a plain preview
481
+ * (`apply: false`, the default) this delegates to `runRemove(options)`
482
+ * unchanged — no prompt library call is ever reached on those paths. With a
483
+ * TTY AND `apply: true`, requires the operator to type the exact target
484
+ * directory (`resolveClaudeDir()`) before proceeding; `purge: true` on top
485
+ * of that requires a SECOND, separate confirmation mentioning backups.
486
+ * Either confirmation failing/cancelling aborts with zero writes.
487
+ */ export async function runRemoveInteractive(options = {}) {
488
+ const apply = options.apply ?? false;
489
+ const purge = options.purge ?? false;
490
+ if (!isInteractive({
491
+ yes: options.yes
492
+ }) || !apply) {
493
+ return runRemove(options);
494
+ }
495
+ const prompter = options.prompter ?? clackPrompter;
496
+ const claudeDir = resolveClaudeDir();
497
+ const typed = await prompter.text({
498
+ message: `Esto desinstala el motor Argos de ${claudeDir}. Escribí "${claudeDir}" para confirmar:`
499
+ });
500
+ if (prompter.isCancel(typed) || typed !== claudeDir) {
501
+ prompter.cancel("argos remove cancelado — no se tocó nada.");
502
+ return cancelledRemoveReport("confirmación de directorio no coincide o fue cancelada");
503
+ }
504
+ if (purge) {
505
+ const confirmPurge = await prompter.confirm({
506
+ message: "--purge también borra ~/.argos/backups — se pierde la red de seguridad de esta y de toda operación anterior. ¿Confirmás?",
507
+ initialValue: false
508
+ });
509
+ if (prompter.isCancel(confirmPurge) || !confirmPurge) {
510
+ prompter.cancel("argos remove cancelado — no se tocó nada.");
511
+ return cancelledRemoveReport("--purge no confirmado");
512
+ }
513
+ }
514
+ const report = runRemove(options);
515
+ prompter.outro(report.summary);
516
+ return report;
517
+ }
434
518
  export const removeCommand = defineCommand({
435
519
  meta: {
436
520
  name: "remove",
@@ -446,12 +530,18 @@ export const removeCommand = defineCommand({
446
530
  type: "boolean",
447
531
  default: false,
448
532
  description: "Also remove ~/.argos data (registry, global.json, backups). Irreversible."
533
+ },
534
+ yes: {
535
+ type: "boolean",
536
+ default: false,
537
+ description: "Fuerza modo no interactivo aunque haya una TTY real (salta las confirmaciones tipadas)."
449
538
  }
450
539
  },
451
- run ({ args }) {
452
- const report = runRemove({
540
+ async run ({ args }) {
541
+ const report = await runRemoveInteractive({
453
542
  apply: args.apply,
454
- purge: args.purge
543
+ purge: args.purge,
544
+ yes: Boolean(args.yes)
455
545
  });
456
546
  const colorize = (status)=>{
457
547
  const padded = status.padEnd(18);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/remove.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { existsSync, readdirSync, readFileSync, rmSync, rmdirSync } from \"node:fs\";\nimport { join, relative, sep } from \"node:path\";\nimport pc from \"picocolors\";\nimport { listSkillFiles, listSkillIds, MANAGED_BLOCK_IDS, resolveAssetsDir } from \"../lib/assets.js\";\nimport { writeFileAtomic } from \"../lib/atomic-write.js\";\nimport { createBackup } from \"../lib/backup.js\";\nimport { listBlocks, removeBlock } from \"../lib/markers.js\";\nimport { hasArgosFileMarker, hasArgosShellFileMarker } from \"../lib/managed-files.js\";\nimport { resolveArgosHome, resolveClaudeDir } from \"../lib/paths.js\";\nimport { removeAllArgosHooksFromSettings } from \"../lib/settings-merge.js\";\n\n/**\n * Uninstaller for `argos init`: the mirror image of `runInit` (see\n * commands/init.ts). Removes only what Argos itself owns — a managed\n * CLAUDE.md block, a file carrying the `argos:file`/shell marker, or a\n * settings.json hook entry pointing at an Argos script — and leaves every\n * foreign file, block, and entry byte-identical.\n *\n * Scope: this command only touches `~/.claude` (via `resolveClaudeDir()`)\n * and, with `--purge`, `~/.argos` (via `resolveArgosHome()`) — the global\n * Argos engine and its registry. Repo-side artifacts are intentionally out\n * of scope and are NEVER touched here: a repo's own `argos.config.json` and\n * the \"ficha\" managed block `argos adopt` writes into that repo's own\n * `CLAUDE.md` both survive `remove` untouched, including `remove --purge`.\n * (See the final \"scope\" row every report ends with.)\n */\n\nexport type RemoveRowStatus = \"removed\" | \"would-remove\" | \"skipped-foreign\" | \"warning\" | \"info\" | \"error\";\n\nexport type RemoveRowCategory =\n | \"claude-md-block\"\n | \"agents-file\"\n | \"skills-file\"\n | \"output-styles-file\"\n | \"hooks-file\"\n | \"settings-entries\"\n | \"argos-home\"\n | \"scope-note\";\n\nexport interface RemoveRow {\n path: string;\n category: RemoveRowCategory;\n status: RemoveRowStatus;\n detail?: string;\n}\n\nexport interface RemoveOptions {\n /** Actually perform the removal. Default false = dry-run preview, touches nothing on disk. */\n apply?: boolean;\n /** Also remove ~/.argos data (registry, global.json, backups). Backups are removed LAST. */\n purge?: boolean;\n}\n\nexport interface RemoveReport {\n rows: RemoveRow[];\n summary: string;\n exitCode: 0 | 1;\n backupPath?: string;\n /** Non-fatal warnings surfaced alongside the report, e.g. the --purge/backups tradeoff. */\n warnings: string[];\n}\n\nconst STATUS_COUNT_ORDER: RemoveRowStatus[] = [\n \"removed\",\n \"would-remove\",\n \"skipped-foreign\",\n \"info\",\n \"warning\",\n \"error\",\n];\n\nfunction summarize(rows: RemoveRow[], apply: boolean): string {\n const counts: Record<RemoveRowStatus, number> = {\n removed: 0,\n \"would-remove\": 0,\n \"skipped-foreign\": 0,\n info: 0,\n warning: 0,\n error: 0,\n };\n for (const row of rows) counts[row.status]++;\n\n const parts = STATUS_COUNT_ORDER.filter((s) => counts[s] > 0).map((s) => `${counts[s]} ${s}`);\n const verb = apply ? \"argos remove\" : \"argos remove (preview — nada se tocó)\";\n return parts.length === 0 ? `${verb}: nada que hacer.` : `${verb}: ${parts.join(\", \")}.`;\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/** Strip every present managed block from CLAUDE.md; delete the file entirely if it becomes empty. */\nfunction processClaudeMd(claudeDir: string, apply: boolean, rows: RemoveRow[]): void {\n const claudeMdPath = join(claudeDir, \"CLAUDE.md\");\n if (!existsSync(claudeMdPath)) return;\n\n let claudeMd: string;\n try {\n claudeMd = readFileSync(claudeMdPath, \"utf-8\");\n } catch (err) {\n rows.push({ path: \"CLAUDE.md\", category: \"claude-md-block\", status: \"error\", detail: errorMessage(err) });\n return;\n }\n\n let next = claudeMd;\n const removedIds: string[] = [];\n for (const id of MANAGED_BLOCK_IDS) {\n const hadBlock = listBlocks(next).some((b) => b.id === id);\n if (!hadBlock) continue;\n const beforeThisId = next;\n // removeBlock only strips the first occurrence — loop to self-heal any\n // crash-residue duplicates left by injectBlock (see lib/markers.ts).\n // Progress-guarded: a dangling open marker with no matching close (see\n // lib/markers.ts's findBlock/listDanglingBlockIds) makes removeBlock a\n // no-op — its output equals its input — which would otherwise spin this\n // loop forever since listBlocks still reports the id as present. Break\n // and surface it as a warning instead of hanging.\n while (listBlocks(next).some((b) => b.id === id)) {\n const before = next;\n next = removeBlock(next, id);\n if (next === before) {\n rows.push({\n path: \"CLAUDE.md\",\n category: \"claude-md-block\",\n status: \"warning\",\n detail: \"marker argos huérfano sin cierre en CLAUDE.md — remuévelo a mano\",\n });\n break;\n }\n }\n if (next !== beforeThisId) removedIds.push(id);\n }\n\n if (removedIds.length === 0) return;\n for (const id of removedIds) {\n rows.push({ path: `CLAUDE.md#${id}`, category: \"claude-md-block\", status: apply ? \"removed\" : \"would-remove\" });\n }\n\n if (!apply) return;\n\n try {\n if (next.trim().length === 0) {\n rmSync(claudeMdPath, { force: true });\n } else {\n writeFileAtomic(claudeMdPath, next);\n }\n } catch (err) {\n rows.push({ path: \"CLAUDE.md\", category: \"claude-md-block\", status: \"error\", detail: errorMessage(err) });\n }\n}\n\nfunction walkFiles(dir: string): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) out.push(...walkFiles(full));\n else if (entry.isFile()) out.push(full);\n }\n return out;\n}\n\n/** Remove now-empty directories bottom-up under `dir`, leaving any dir that still holds foreign content. */\nfunction removeEmptyDirsUnder(dir: string): void {\n if (!existsSync(dir)) return;\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) removeEmptyDirsUnder(join(dir, entry.name));\n }\n const remaining = existsSync(dir) ? readdirSync(dir) : [];\n if (remaining.length === 0) {\n try {\n rmdirSync(dir);\n } catch {\n // Best-effort cleanup — a leftover empty dir is cosmetic, not an error.\n }\n }\n}\n\n/**\n * Remove every Argos-owned file (carrying the ownership marker) under\n * `claudeDir/<topDir>`, recursively — skills live in subdirectories, hence\n * the recursive walk. Foreign files (no marker) are reported\n * \"skipped-foreign\" and left byte-identical.\n */\nfunction processManagedDir(\n claudeDir: string,\n topDir: \"agents\" | \"output-styles\" | \"hooks\",\n category: RemoveRowCategory,\n hasMarker: (content: string) => boolean,\n apply: boolean,\n rows: RemoveRow[],\n): void {\n const dirPath = join(claudeDir, topDir);\n const files = walkFiles(dirPath);\n for (const file of files) {\n const relPath = relative(claudeDir, file);\n let content: string;\n try {\n content = readFileSync(file, \"utf-8\");\n } catch (err) {\n rows.push({ path: relPath, category, status: \"error\", detail: errorMessage(err) });\n continue;\n }\n\n if (!hasMarker(content)) {\n rows.push({ path: relPath, category, status: \"skipped-foreign\" });\n continue;\n }\n\n if (!apply) {\n rows.push({ path: relPath, category, status: \"would-remove\" });\n continue;\n }\n\n try {\n rmSync(file, { force: true });\n rows.push({ path: relPath, category, status: \"removed\" });\n } catch (err) {\n rows.push({ path: relPath, category, status: \"error\", detail: errorMessage(err) });\n }\n }\n\n if (apply) removeEmptyDirsUnder(dirPath);\n}\n\n/**\n * Remove Argos-owned skill directories under `claudeDir/skills/`.\n *\n * Unlike `processManagedDir` (per-file marker check), ownership here is\n * decided PER SKILL DIRECTORY: the skill's `SKILL.md` `argos:file` marker is\n * the sentinel (mirrors the install policy in commands/init.ts). Supporting\n * files (`references/*.md`, `phases/*.md`, etc.) never carry a marker of\n * their own, so a per-file marker check would wrongly treat every one of\n * them as foreign.\n * - `SKILL.md` missing, or present without the marker → the whole directory\n * is foreign (or not argos-installed at all); every file under it is left\n * untouched, reported \"skipped-foreign\".\n * - `SKILL.md` present with the marker → argos-owned. Only the files the\n * CURRENTLY shipped asset manifest lists for that skill id\n * (`listSkillFiles`) are removed; anything else in the directory — a\n * user-added extra file, or every file if this CLI version no longer\n * ships the skill at all — is left in place.\n */\nfunction processSkillsDir(claudeDir: string, apply: boolean, rows: RemoveRow[]): void {\n const skillsRoot = join(claudeDir, \"skills\");\n if (!existsSync(skillsRoot)) return;\n\n const assetsDir = resolveAssetsDir();\n const shippedSkillIds = new Set(listSkillIds(assetsDir));\n\n for (const entry of readdirSync(skillsRoot, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue; // skills/ only ever holds skill subdirectories\n const skillId = entry.name;\n const skillDir = join(skillsRoot, skillId);\n const skillMdPath = join(skillDir, \"SKILL.md\");\n\n let skillMdContent: string | null = null;\n if (existsSync(skillMdPath)) {\n try {\n skillMdContent = readFileSync(skillMdPath, \"utf-8\");\n } catch (err) {\n rows.push({\n path: relative(claudeDir, skillMdPath),\n category: \"skills-file\",\n status: \"error\",\n detail: errorMessage(err),\n });\n continue;\n }\n }\n\n const isArgosOwned = skillMdContent !== null && hasArgosFileMarker(skillMdContent);\n const manifest =\n isArgosOwned && shippedSkillIds.has(skillId) ? new Set(listSkillFiles(assetsDir, skillId)) : new Set<string>();\n\n for (const file of walkFiles(skillDir)) {\n const relToClaudeDir = relative(claudeDir, file);\n\n if (!isArgosOwned || !manifest.has(relative(skillDir, file).split(sep).join(\"/\"))) {\n rows.push({ path: relToClaudeDir, category: \"skills-file\", status: \"skipped-foreign\" });\n continue;\n }\n\n if (!apply) {\n rows.push({ path: relToClaudeDir, category: \"skills-file\", status: \"would-remove\" });\n continue;\n }\n\n try {\n rmSync(file, { force: true });\n rows.push({ path: relToClaudeDir, category: \"skills-file\", status: \"removed\" });\n } catch (err) {\n rows.push({ path: relToClaudeDir, category: \"skills-file\", status: \"error\", detail: errorMessage(err) });\n }\n }\n }\n\n if (apply) removeEmptyDirsUnder(skillsRoot);\n}\n\nconst PURGE_FILES = [\"global.json\", \"workspaces.json\"] as const;\n\nfunction processPurge(apply: boolean, rows: RemoveRow[], warnings: string[]): void {\n const argosHome = resolveArgosHome();\n\n for (const name of PURGE_FILES) {\n const p = join(argosHome, name);\n if (!existsSync(p)) continue;\n const label = join(\"~\", \".argos\", name);\n if (!apply) {\n rows.push({ path: label, category: \"argos-home\", status: \"would-remove\" });\n continue;\n }\n try {\n rmSync(p, { force: true });\n rows.push({ path: label, category: \"argos-home\", status: \"removed\" });\n } catch (err) {\n rows.push({ path: label, category: \"argos-home\", status: \"error\", detail: errorMessage(err) });\n }\n }\n\n // Backups LAST, and always explicitly flagged: they're the safety net for\n // every previous (and this very) destructive operation, so purging them\n // removes the one thing that could otherwise undo a mistake.\n const backupsDir = join(argosHome, \"backups\");\n const backupsLabel = join(\"~\", \".argos\", \"backups\");\n if (existsSync(backupsDir)) {\n warnings.push(\n \"--purge elimina ~/.argos/backups — se pierde la red de seguridad de esta y de toda operación anterior.\",\n );\n if (!apply) {\n rows.push({ path: backupsLabel, category: \"argos-home\", status: \"would-remove\" });\n } else {\n try {\n rmSync(backupsDir, { recursive: true, force: true });\n rows.push({ path: backupsLabel, category: \"argos-home\", status: \"removed\" });\n } catch (err) {\n rows.push({ path: backupsLabel, category: \"argos-home\", status: \"error\", detail: errorMessage(err) });\n }\n }\n }\n}\n\n/**\n * Core, testable implementation of `argos remove`: uninstalls everything\n * `runInit` (commands/init.ts) installs into `resolveClaudeDir()`. Pure\n * function of the filesystem — no process.exit, no console output.\n *\n * Preview by default (`apply: false`): computes the full report without\n * writing anything. `apply: true` performs the removal, backing up\n * everything affected first (same `createBackup` call `runInit` makes,\n * before any mutation). `purge: true` additionally removes `~/.argos` data\n * (kept by default) — backups are removed last and always warned about.\n */\nexport function runRemove(options: RemoveOptions = {}): RemoveReport {\n const apply = options.apply ?? false;\n const purge = options.purge ?? false;\n const claudeDir = resolveClaudeDir();\n const rows: RemoveRow[] = [];\n const warnings: string[] = [];\n\n let backupPath: string | undefined;\n if (apply) {\n try {\n backupPath = createBackup(claudeDir, [\n \"CLAUDE.md\",\n \"agents\",\n \"skills\",\n \"output-styles\",\n \"hooks\",\n \"settings.json\",\n ]);\n } catch (err) {\n const detail = errorMessage(err);\n rows.push({ path: \"backup\", category: \"argos-home\", status: \"error\", detail });\n return { rows, summary: `backup falló — no se tocó nada (${detail}).`, exitCode: 1, warnings };\n }\n }\n\n processClaudeMd(claudeDir, apply, rows);\n\n processManagedDir(claudeDir, \"agents\", \"agents-file\", hasArgosFileMarker, apply, rows);\n processSkillsDir(claudeDir, apply, rows);\n processManagedDir(claudeDir, \"output-styles\", \"output-styles-file\", hasArgosFileMarker, apply, rows);\n processManagedDir(claudeDir, \"hooks\", \"hooks-file\", hasArgosShellFileMarker, apply, rows);\n\n const settingsPath = join(claudeDir, \"settings.json\");\n const settingsResult = removeAllArgosHooksFromSettings(settingsPath, join(claudeDir, \"hooks\"), { dryRun: !apply });\n if (settingsResult.status === \"error\") {\n rows.push({ path: \"settings.json\", category: \"settings-entries\", status: \"error\", detail: settingsResult.detail });\n } else if (settingsResult.removedCount > 0) {\n const noun = settingsResult.removedCount === 1 ? \"entry\" : \"entries\";\n rows.push({\n path: \"settings.json\",\n category: \"settings-entries\",\n status: apply ? \"removed\" : \"would-remove\",\n detail: `${settingsResult.removedCount} hook ${noun}`,\n });\n }\n\n if (purge) processPurge(apply, rows, warnings);\n\n // Always-present closing note: repo-side artifacts (argos.config.json, the\n // ficha block in a repo's own CLAUDE.md) are out of scope for `remove` —\n // see the module doc comment above.\n rows.push({\n path: \"scope\",\n category: \"scope-note\",\n status: \"info\",\n detail: \"los repos adoptados conservan su argos.config.json y ficha — este comando solo limpia ~/.claude y ~/.argos\",\n });\n\n const exitCode: 0 | 1 = rows.some((r) => r.status === \"error\") ? 1 : 0;\n return { rows, summary: summarize(rows, apply), exitCode, backupPath, warnings };\n}\n\nexport const removeCommand = defineCommand({\n meta: {\n name: \"remove\",\n description: \"Uninstall the Argos engine from the global Claude Code home (preview by default).\",\n },\n args: {\n apply: {\n type: \"boolean\",\n default: false,\n description: \"Actually perform the removal (default: dry-run preview, touches nothing).\",\n },\n purge: {\n type: \"boolean\",\n default: false,\n description: \"Also remove ~/.argos data (registry, global.json, backups). Irreversible.\",\n },\n },\n run({ args }) {\n const report = runRemove({ apply: args.apply, purge: args.purge });\n\n const colorize = (status: RemoveRowStatus): string => {\n const padded = status.padEnd(18);\n switch (status) {\n case \"skipped-foreign\":\n return pc.yellow(padded);\n case \"removed\":\n return pc.cyan(padded);\n case \"would-remove\":\n return pc.dim(padded);\n case \"warning\":\n return pc.yellow(padded);\n case \"info\":\n return pc.dim(padded);\n case \"error\":\n return pc.red(padded);\n default:\n return padded;\n }\n };\n for (const row of report.rows) {\n const suffix = row.detail ? ` (${row.detail})` : \"\";\n console.log(`${colorize(row.status)} ${row.path}${suffix}`);\n }\n console.log(\"\");\n console.log(report.summary);\n if (report.backupPath) console.log(`backup en ${report.backupPath}`);\n for (const warning of report.warnings) console.log(pc.yellow(`aviso: ${warning}`));\n\n process.exit(report.exitCode);\n },\n});\n"],"names":["defineCommand","existsSync","readdirSync","readFileSync","rmSync","rmdirSync","join","relative","sep","pc","listSkillFiles","listSkillIds","MANAGED_BLOCK_IDS","resolveAssetsDir","writeFileAtomic","createBackup","listBlocks","removeBlock","hasArgosFileMarker","hasArgosShellFileMarker","resolveArgosHome","resolveClaudeDir","removeAllArgosHooksFromSettings","STATUS_COUNT_ORDER","summarize","rows","apply","counts","removed","info","warning","error","row","status","parts","filter","s","map","verb","length","errorMessage","err","Error","message","String","processClaudeMd","claudeDir","claudeMdPath","claudeMd","push","path","category","detail","next","removedIds","id","hadBlock","some","b","beforeThisId","before","trim","force","walkFiles","dir","out","entry","withFileTypes","full","name","isDirectory","isFile","removeEmptyDirsUnder","remaining","processManagedDir","topDir","hasMarker","dirPath","files","file","relPath","content","processSkillsDir","skillsRoot","assetsDir","shippedSkillIds","Set","skillId","skillDir","skillMdPath","skillMdContent","isArgosOwned","manifest","has","relToClaudeDir","split","PURGE_FILES","processPurge","warnings","argosHome","p","label","backupsDir","backupsLabel","recursive","runRemove","options","purge","backupPath","summary","exitCode","settingsPath","settingsResult","dryRun","removedCount","noun","r","removeCommand","meta","description","args","type","default","run","report","colorize","padded","padEnd","yellow","cyan","dim","red","suffix","console","log","process","exit"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/commands/remove.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { existsSync, readdirSync, readFileSync, rmSync, rmdirSync } from \"node:fs\";\nimport { join, relative, sep } from \"node:path\";\nimport pc from \"picocolors\";\nimport { listSkillFiles, listSkillIds, MANAGED_BLOCK_IDS, resolveAssetsDir } from \"../lib/assets.js\";\nimport { writeFileAtomic } from \"../lib/atomic-write.js\";\nimport { createBackup } from \"../lib/backup.js\";\nimport { listBlocks, removeBlock } from \"../lib/markers.js\";\nimport { hasArgosFileMarker, hasArgosShellFileMarker } from \"../lib/managed-files.js\";\nimport { resolveArgosHome, resolveClaudeDir } from \"../lib/paths.js\";\nimport { isInteractive, clackPrompter, type Prompter } from \"../lib/prompter.js\";\nimport { removeAllArgosHooksFromSettings, removeOutputStyleIfArgos } from \"../lib/settings-merge.js\";\n\n/**\n * Uninstaller for `argos init`: the mirror image of `runInit` (see\n * commands/init.ts). Removes only what Argos itself owns — a managed\n * CLAUDE.md block, a file carrying the `argos:file`/shell marker, or a\n * settings.json hook entry pointing at an Argos script — and leaves every\n * foreign file, block, and entry byte-identical.\n *\n * Scope: this command only touches `~/.claude` (via `resolveClaudeDir()`)\n * and, with `--purge`, `~/.argos` (via `resolveArgosHome()`) — the global\n * Argos engine and its registry. Repo-side artifacts are intentionally out\n * of scope and are NEVER touched here: a repo's own `argos.config.json` and\n * the \"ficha\" managed block `argos adopt` writes into that repo's own\n * `CLAUDE.md` both survive `remove` untouched, including `remove --purge`.\n * (See the final \"scope\" row every report ends with.)\n */\n\nexport type RemoveRowStatus = \"removed\" | \"would-remove\" | \"skipped-foreign\" | \"warning\" | \"info\" | \"error\";\n\nexport type RemoveRowCategory =\n | \"claude-md-block\"\n | \"agents-file\"\n | \"skills-file\"\n | \"output-styles-file\"\n | \"hooks-file\"\n | \"settings-entries\"\n | \"argos-home\"\n | \"scope-note\";\n\nexport interface RemoveRow {\n path: string;\n category: RemoveRowCategory;\n status: RemoveRowStatus;\n detail?: string;\n}\n\nexport interface RemoveOptions {\n /** Actually perform the removal. Default false = dry-run preview, touches nothing on disk. */\n apply?: boolean;\n /** Also remove ~/.argos data (registry, global.json, backups). Backups are removed LAST. */\n purge?: boolean;\n}\n\nexport interface RemoveReport {\n rows: RemoveRow[];\n summary: string;\n exitCode: 0 | 1;\n backupPath?: string;\n /** Non-fatal warnings surfaced alongside the report, e.g. the --purge/backups tradeoff. */\n warnings: string[];\n}\n\nconst STATUS_COUNT_ORDER: RemoveRowStatus[] = [\n \"removed\",\n \"would-remove\",\n \"skipped-foreign\",\n \"info\",\n \"warning\",\n \"error\",\n];\n\nfunction summarize(rows: RemoveRow[], apply: boolean): string {\n const counts: Record<RemoveRowStatus, number> = {\n removed: 0,\n \"would-remove\": 0,\n \"skipped-foreign\": 0,\n info: 0,\n warning: 0,\n error: 0,\n };\n for (const row of rows) counts[row.status]++;\n\n const parts = STATUS_COUNT_ORDER.filter((s) => counts[s] > 0).map((s) => `${counts[s]} ${s}`);\n const verb = apply ? \"argos remove\" : \"argos remove (preview — nada se tocó)\";\n return parts.length === 0 ? `${verb}: nada que hacer.` : `${verb}: ${parts.join(\", \")}.`;\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/** Strip every present managed block from CLAUDE.md; delete the file entirely if it becomes empty. */\nfunction processClaudeMd(claudeDir: string, apply: boolean, rows: RemoveRow[]): void {\n const claudeMdPath = join(claudeDir, \"CLAUDE.md\");\n if (!existsSync(claudeMdPath)) return;\n\n let claudeMd: string;\n try {\n claudeMd = readFileSync(claudeMdPath, \"utf-8\");\n } catch (err) {\n rows.push({ path: \"CLAUDE.md\", category: \"claude-md-block\", status: \"error\", detail: errorMessage(err) });\n return;\n }\n\n let next = claudeMd;\n const removedIds: string[] = [];\n for (const id of MANAGED_BLOCK_IDS) {\n const hadBlock = listBlocks(next).some((b) => b.id === id);\n if (!hadBlock) continue;\n const beforeThisId = next;\n // removeBlock only strips the first occurrence — loop to self-heal any\n // crash-residue duplicates left by injectBlock (see lib/markers.ts).\n // Progress-guarded: a dangling open marker with no matching close (see\n // lib/markers.ts's findBlock/listDanglingBlockIds) makes removeBlock a\n // no-op — its output equals its input — which would otherwise spin this\n // loop forever since listBlocks still reports the id as present. Break\n // and surface it as a warning instead of hanging.\n while (listBlocks(next).some((b) => b.id === id)) {\n const before = next;\n next = removeBlock(next, id);\n if (next === before) {\n rows.push({\n path: \"CLAUDE.md\",\n category: \"claude-md-block\",\n status: \"warning\",\n detail: \"marker argos huérfano sin cierre en CLAUDE.md — remuévelo a mano\",\n });\n break;\n }\n }\n if (next !== beforeThisId) removedIds.push(id);\n }\n\n if (removedIds.length === 0) return;\n for (const id of removedIds) {\n rows.push({ path: `CLAUDE.md#${id}`, category: \"claude-md-block\", status: apply ? \"removed\" : \"would-remove\" });\n }\n\n if (!apply) return;\n\n try {\n if (next.trim().length === 0) {\n rmSync(claudeMdPath, { force: true });\n } else {\n writeFileAtomic(claudeMdPath, next);\n }\n } catch (err) {\n rows.push({ path: \"CLAUDE.md\", category: \"claude-md-block\", status: \"error\", detail: errorMessage(err) });\n }\n}\n\nfunction walkFiles(dir: string): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) out.push(...walkFiles(full));\n else if (entry.isFile()) out.push(full);\n }\n return out;\n}\n\n/** Remove now-empty directories bottom-up under `dir`, leaving any dir that still holds foreign content. */\nfunction removeEmptyDirsUnder(dir: string): void {\n if (!existsSync(dir)) return;\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) removeEmptyDirsUnder(join(dir, entry.name));\n }\n const remaining = existsSync(dir) ? readdirSync(dir) : [];\n if (remaining.length === 0) {\n try {\n rmdirSync(dir);\n } catch {\n // Best-effort cleanup — a leftover empty dir is cosmetic, not an error.\n }\n }\n}\n\n/**\n * Remove every Argos-owned file (carrying the ownership marker) under\n * `claudeDir/<topDir>`, recursively — skills live in subdirectories, hence\n * the recursive walk. Foreign files (no marker) are reported\n * \"skipped-foreign\" and left byte-identical.\n */\nfunction processManagedDir(\n claudeDir: string,\n topDir: \"agents\" | \"output-styles\" | \"hooks\",\n category: RemoveRowCategory,\n hasMarker: (content: string) => boolean,\n apply: boolean,\n rows: RemoveRow[],\n): void {\n const dirPath = join(claudeDir, topDir);\n const files = walkFiles(dirPath);\n for (const file of files) {\n const relPath = relative(claudeDir, file);\n let content: string;\n try {\n content = readFileSync(file, \"utf-8\");\n } catch (err) {\n rows.push({ path: relPath, category, status: \"error\", detail: errorMessage(err) });\n continue;\n }\n\n if (!hasMarker(content)) {\n rows.push({ path: relPath, category, status: \"skipped-foreign\" });\n continue;\n }\n\n if (!apply) {\n rows.push({ path: relPath, category, status: \"would-remove\" });\n continue;\n }\n\n try {\n rmSync(file, { force: true });\n rows.push({ path: relPath, category, status: \"removed\" });\n } catch (err) {\n rows.push({ path: relPath, category, status: \"error\", detail: errorMessage(err) });\n }\n }\n\n if (apply) removeEmptyDirsUnder(dirPath);\n}\n\n/**\n * Remove Argos-owned skill directories under `claudeDir/skills/`.\n *\n * Unlike `processManagedDir` (per-file marker check), ownership here is\n * decided PER SKILL DIRECTORY: the skill's `SKILL.md` `argos:file` marker is\n * the sentinel (mirrors the install policy in commands/init.ts). Supporting\n * files (`references/*.md`, `phases/*.md`, etc.) never carry a marker of\n * their own, so a per-file marker check would wrongly treat every one of\n * them as foreign.\n * - `SKILL.md` missing, or present without the marker → the whole directory\n * is foreign (or not argos-installed at all); every file under it is left\n * untouched, reported \"skipped-foreign\".\n * - `SKILL.md` present with the marker → argos-owned. Only the files the\n * CURRENTLY shipped asset manifest lists for that skill id\n * (`listSkillFiles`) are removed; anything else in the directory — a\n * user-added extra file, or every file if this CLI version no longer\n * ships the skill at all — is left in place.\n */\nfunction processSkillsDir(claudeDir: string, apply: boolean, rows: RemoveRow[]): void {\n const skillsRoot = join(claudeDir, \"skills\");\n if (!existsSync(skillsRoot)) return;\n\n const assetsDir = resolveAssetsDir();\n const shippedSkillIds = new Set(listSkillIds(assetsDir));\n\n for (const entry of readdirSync(skillsRoot, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue; // skills/ only ever holds skill subdirectories\n const skillId = entry.name;\n const skillDir = join(skillsRoot, skillId);\n const skillMdPath = join(skillDir, \"SKILL.md\");\n\n let skillMdContent: string | null = null;\n if (existsSync(skillMdPath)) {\n try {\n skillMdContent = readFileSync(skillMdPath, \"utf-8\");\n } catch (err) {\n rows.push({\n path: relative(claudeDir, skillMdPath),\n category: \"skills-file\",\n status: \"error\",\n detail: errorMessage(err),\n });\n continue;\n }\n }\n\n const isArgosOwned = skillMdContent !== null && hasArgosFileMarker(skillMdContent);\n const manifest =\n isArgosOwned && shippedSkillIds.has(skillId) ? new Set(listSkillFiles(assetsDir, skillId)) : new Set<string>();\n\n for (const file of walkFiles(skillDir)) {\n const relToClaudeDir = relative(claudeDir, file);\n\n if (!isArgosOwned || !manifest.has(relative(skillDir, file).split(sep).join(\"/\"))) {\n rows.push({ path: relToClaudeDir, category: \"skills-file\", status: \"skipped-foreign\" });\n continue;\n }\n\n if (!apply) {\n rows.push({ path: relToClaudeDir, category: \"skills-file\", status: \"would-remove\" });\n continue;\n }\n\n try {\n rmSync(file, { force: true });\n rows.push({ path: relToClaudeDir, category: \"skills-file\", status: \"removed\" });\n } catch (err) {\n rows.push({ path: relToClaudeDir, category: \"skills-file\", status: \"error\", detail: errorMessage(err) });\n }\n }\n }\n\n if (apply) removeEmptyDirsUnder(skillsRoot);\n}\n\nconst PURGE_FILES = [\"global.json\", \"workspaces.json\"] as const;\n\nfunction processPurge(apply: boolean, rows: RemoveRow[], warnings: string[]): void {\n const argosHome = resolveArgosHome();\n\n for (const name of PURGE_FILES) {\n const p = join(argosHome, name);\n if (!existsSync(p)) continue;\n const label = join(\"~\", \".argos\", name);\n if (!apply) {\n rows.push({ path: label, category: \"argos-home\", status: \"would-remove\" });\n continue;\n }\n try {\n rmSync(p, { force: true });\n rows.push({ path: label, category: \"argos-home\", status: \"removed\" });\n } catch (err) {\n rows.push({ path: label, category: \"argos-home\", status: \"error\", detail: errorMessage(err) });\n }\n }\n\n // Backups LAST, and always explicitly flagged: they're the safety net for\n // every previous (and this very) destructive operation, so purging them\n // removes the one thing that could otherwise undo a mistake.\n const backupsDir = join(argosHome, \"backups\");\n const backupsLabel = join(\"~\", \".argos\", \"backups\");\n if (existsSync(backupsDir)) {\n warnings.push(\n \"--purge elimina ~/.argos/backups — se pierde la red de seguridad de esta y de toda operación anterior.\",\n );\n if (!apply) {\n rows.push({ path: backupsLabel, category: \"argos-home\", status: \"would-remove\" });\n } else {\n try {\n rmSync(backupsDir, { recursive: true, force: true });\n rows.push({ path: backupsLabel, category: \"argos-home\", status: \"removed\" });\n } catch (err) {\n rows.push({ path: backupsLabel, category: \"argos-home\", status: \"error\", detail: errorMessage(err) });\n }\n }\n }\n}\n\n/**\n * Core, testable implementation of `argos remove`: uninstalls everything\n * `runInit` (commands/init.ts) installs into `resolveClaudeDir()`. Pure\n * function of the filesystem — no process.exit, no console output.\n *\n * Preview by default (`apply: false`): computes the full report without\n * writing anything. `apply: true` performs the removal, backing up\n * everything affected first (same `createBackup` call `runInit` makes,\n * before any mutation). `purge: true` additionally removes `~/.argos` data\n * (kept by default) — backups are removed last and always warned about.\n */\nexport function runRemove(options: RemoveOptions = {}): RemoveReport {\n const apply = options.apply ?? false;\n const purge = options.purge ?? false;\n const claudeDir = resolveClaudeDir();\n const rows: RemoveRow[] = [];\n const warnings: string[] = [];\n\n let backupPath: string | undefined;\n if (apply) {\n try {\n backupPath = createBackup(claudeDir, [\n \"CLAUDE.md\",\n \"agents\",\n \"skills\",\n \"output-styles\",\n \"hooks\",\n \"settings.json\",\n ]);\n } catch (err) {\n const detail = errorMessage(err);\n rows.push({ path: \"backup\", category: \"argos-home\", status: \"error\", detail });\n return { rows, summary: `backup falló — no se tocó nada (${detail}).`, exitCode: 1, warnings };\n }\n }\n\n processClaudeMd(claudeDir, apply, rows);\n\n processManagedDir(claudeDir, \"agents\", \"agents-file\", hasArgosFileMarker, apply, rows);\n processSkillsDir(claudeDir, apply, rows);\n processManagedDir(claudeDir, \"output-styles\", \"output-styles-file\", hasArgosFileMarker, apply, rows);\n processManagedDir(claudeDir, \"hooks\", \"hooks-file\", hasArgosShellFileMarker, apply, rows);\n\n const settingsPath = join(claudeDir, \"settings.json\");\n const settingsResult = removeAllArgosHooksFromSettings(settingsPath, join(claudeDir, \"hooks\"), { dryRun: !apply });\n if (settingsResult.status === \"error\") {\n rows.push({ path: \"settings.json\", category: \"settings-entries\", status: \"error\", detail: settingsResult.detail });\n } else if (settingsResult.removedCount > 0) {\n const noun = settingsResult.removedCount === 1 ? \"entry\" : \"entries\";\n rows.push({\n path: \"settings.json\",\n category: \"settings-entries\",\n status: apply ? \"removed\" : \"would-remove\",\n detail: `${settingsResult.removedCount} hook ${noun}`,\n });\n }\n\n // Voice activation (spec 0004): remove settings.json.outputStyle ONLY when\n // it's still exactly \"Argos\" — the value argos init wrote. Any other\n // voice (a foreign one init never touched, or the key simply absent) is\n // left byte-identical; this is `argos remove`'s own value to clean up\n // after, never the user's.\n const outputStyleResult = removeOutputStyleIfArgos(settingsPath, { dryRun: !apply });\n if (outputStyleResult.status === \"error\") {\n rows.push({\n path: \"settings.json#outputStyle\",\n category: \"settings-entries\",\n status: \"error\",\n detail: outputStyleResult.detail,\n });\n } else if (outputStyleResult.status === \"removed\") {\n rows.push({\n path: \"settings.json#outputStyle\",\n category: \"settings-entries\",\n status: apply ? \"removed\" : \"would-remove\",\n });\n }\n\n if (purge) processPurge(apply, rows, warnings);\n\n // Always-present closing note: repo-side artifacts (argos.config.json, the\n // ficha block in a repo's own CLAUDE.md) are out of scope for `remove` —\n // see the module doc comment above.\n rows.push({\n path: \"scope\",\n category: \"scope-note\",\n status: \"info\",\n detail: \"los repos adoptados conservan su argos.config.json y ficha — este comando solo limpia ~/.claude y ~/.argos\",\n });\n\n const exitCode: 0 | 1 = rows.some((r) => r.status === \"error\") ? 1 : 0;\n return { rows, summary: summarize(rows, apply), exitCode, backupPath, warnings };\n}\n\nexport interface RemoveInteractiveOptions extends RemoveOptions {\n /** `--yes`: forces non-interactive behavior even under a real TTY. */\n yes?: boolean;\n /** Injectable for tests; defaults to the real `@clack/prompts`-backed prompter. */\n prompter?: Prompter;\n}\n\n/**\n * A cancelled confirmation's report: identical shape to a run that touched\n * nothing. `exitCode: 1` — a cancel is neither a successful write nor\n * silently indistinguishable from one by exit code alone (matches\n * `runWorkspaceLinkInteractive`'s convention for its own cancel paths).\n */\nfunction cancelledRemoveReport(reason: string): RemoveReport {\n return {\n rows: [{ path: \"cancel\", category: \"scope-note\", status: \"info\", detail: reason }],\n summary: `argos remove: cancelado — no se tocó nada (${reason}).`,\n exitCode: 1,\n warnings: [],\n };\n}\n\n/**\n * Interactive layer over `runRemove` (spec 0004 F5 \"argos remove\"). A pure\n * additive wrapper — the core `runRemove` never changes behavior or\n * contract. Without a real TTY, with `--yes`, or for a plain preview\n * (`apply: false`, the default) this delegates to `runRemove(options)`\n * unchanged — no prompt library call is ever reached on those paths. With a\n * TTY AND `apply: true`, requires the operator to type the exact target\n * directory (`resolveClaudeDir()`) before proceeding; `purge: true` on top\n * of that requires a SECOND, separate confirmation mentioning backups.\n * Either confirmation failing/cancelling aborts with zero writes.\n */\nexport async function runRemoveInteractive(options: RemoveInteractiveOptions = {}): Promise<RemoveReport> {\n const apply = options.apply ?? false;\n const purge = options.purge ?? false;\n\n if (!isInteractive({ yes: options.yes }) || !apply) {\n return runRemove(options);\n }\n\n const prompter = options.prompter ?? clackPrompter;\n const claudeDir = resolveClaudeDir();\n\n const typed = await prompter.text({\n message: `Esto desinstala el motor Argos de ${claudeDir}. Escribí \"${claudeDir}\" para confirmar:`,\n });\n if (prompter.isCancel(typed) || typed !== claudeDir) {\n prompter.cancel(\"argos remove cancelado — no se tocó nada.\");\n return cancelledRemoveReport(\"confirmación de directorio no coincide o fue cancelada\");\n }\n\n if (purge) {\n const confirmPurge = await prompter.confirm({\n message:\n \"--purge también borra ~/.argos/backups — se pierde la red de seguridad de esta y de toda operación anterior. ¿Confirmás?\",\n initialValue: false,\n });\n if (prompter.isCancel(confirmPurge) || !confirmPurge) {\n prompter.cancel(\"argos remove cancelado — no se tocó nada.\");\n return cancelledRemoveReport(\"--purge no confirmado\");\n }\n }\n\n const report = runRemove(options);\n prompter.outro(report.summary);\n return report;\n}\n\nexport const removeCommand = defineCommand({\n meta: {\n name: \"remove\",\n description: \"Uninstall the Argos engine from the global Claude Code home (preview by default).\",\n },\n args: {\n apply: {\n type: \"boolean\",\n default: false,\n description: \"Actually perform the removal (default: dry-run preview, touches nothing).\",\n },\n purge: {\n type: \"boolean\",\n default: false,\n description: \"Also remove ~/.argos data (registry, global.json, backups). Irreversible.\",\n },\n yes: {\n type: \"boolean\",\n default: false,\n description: \"Fuerza modo no interactivo aunque haya una TTY real (salta las confirmaciones tipadas).\",\n },\n },\n async run({ args }) {\n const report = await runRemoveInteractive({ apply: args.apply, purge: args.purge, yes: Boolean(args.yes) });\n\n const colorize = (status: RemoveRowStatus): string => {\n const padded = status.padEnd(18);\n switch (status) {\n case \"skipped-foreign\":\n return pc.yellow(padded);\n case \"removed\":\n return pc.cyan(padded);\n case \"would-remove\":\n return pc.dim(padded);\n case \"warning\":\n return pc.yellow(padded);\n case \"info\":\n return pc.dim(padded);\n case \"error\":\n return pc.red(padded);\n default:\n return padded;\n }\n };\n for (const row of report.rows) {\n const suffix = row.detail ? ` (${row.detail})` : \"\";\n console.log(`${colorize(row.status)} ${row.path}${suffix}`);\n }\n console.log(\"\");\n console.log(report.summary);\n if (report.backupPath) console.log(`backup en ${report.backupPath}`);\n for (const warning of report.warnings) console.log(pc.yellow(`aviso: ${warning}`));\n\n process.exit(report.exitCode);\n },\n});\n"],"names":["defineCommand","existsSync","readdirSync","readFileSync","rmSync","rmdirSync","join","relative","sep","pc","listSkillFiles","listSkillIds","MANAGED_BLOCK_IDS","resolveAssetsDir","writeFileAtomic","createBackup","listBlocks","removeBlock","hasArgosFileMarker","hasArgosShellFileMarker","resolveArgosHome","resolveClaudeDir","isInteractive","clackPrompter","removeAllArgosHooksFromSettings","removeOutputStyleIfArgos","STATUS_COUNT_ORDER","summarize","rows","apply","counts","removed","info","warning","error","row","status","parts","filter","s","map","verb","length","errorMessage","err","Error","message","String","processClaudeMd","claudeDir","claudeMdPath","claudeMd","push","path","category","detail","next","removedIds","id","hadBlock","some","b","beforeThisId","before","trim","force","walkFiles","dir","out","entry","withFileTypes","full","name","isDirectory","isFile","removeEmptyDirsUnder","remaining","processManagedDir","topDir","hasMarker","dirPath","files","file","relPath","content","processSkillsDir","skillsRoot","assetsDir","shippedSkillIds","Set","skillId","skillDir","skillMdPath","skillMdContent","isArgosOwned","manifest","has","relToClaudeDir","split","PURGE_FILES","processPurge","warnings","argosHome","p","label","backupsDir","backupsLabel","recursive","runRemove","options","purge","backupPath","summary","exitCode","settingsPath","settingsResult","dryRun","removedCount","noun","outputStyleResult","r","cancelledRemoveReport","reason","runRemoveInteractive","yes","prompter","typed","text","isCancel","cancel","confirmPurge","confirm","initialValue","report","outro","removeCommand","meta","description","args","type","default","run","Boolean","colorize","padded","padEnd","yellow","cyan","dim","red","suffix","console","log","process","exit"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { type OpenclawRunner, type WorkspaceAgentRow } from "../lib/openclaw-agents.js";
2
+ import { type Prompter } from "../lib/prompter.js";
2
3
  import { type LinkAction } from "../lib/workspaces.js";
3
4
  export interface WorkspaceLinkOptions {
4
5
  cwd: string;
@@ -7,6 +8,12 @@ export interface WorkspaceLinkOptions {
7
8
  /** Overwrite a name collision (same config.name, different physical repo) instead of refusing. */
8
9
  force?: boolean;
9
10
  }
11
+ export interface WorkspaceLinkCollision {
12
+ workspaceName: string;
13
+ repoName: string;
14
+ oldPath: string;
15
+ newPath: string;
16
+ }
10
17
  export interface WorkspaceLinkReport {
11
18
  exitCode: 0 | 1;
12
19
  error?: string;
@@ -16,6 +23,15 @@ export interface WorkspaceLinkReport {
16
23
  createdWorkspace?: boolean;
17
24
  /** Remote identity persisted as a new match rule, if the offer fired. */
18
25
  matchRuleAdded?: string;
26
+ /**
27
+ * Populated instead of a bare `error` string when `linkRepo` refused with
28
+ * `WorkspaceNameCollisionError` (see lib/workspaces.ts) — lets the
29
+ * interactive layer offer overwrite/cancel (the equivalent of `--force`)
30
+ * without having to string-parse `error`. Additive: `error` is still set
31
+ * alongside it, so any caller only reading `error` behaves exactly as
32
+ * before.
33
+ */
34
+ collision?: WorkspaceLinkCollision;
19
35
  }
20
36
  /**
21
37
  * Core, testable implementation of `argos workspace link [nombre]`: resolves
@@ -25,6 +41,22 @@ export interface WorkspaceLinkReport {
25
41
  * remote as a match rule so future repos under the same identity auto-link.
26
42
  */
27
43
  export declare function runWorkspaceLink(options: WorkspaceLinkOptions): WorkspaceLinkReport;
44
+ export interface WorkspaceLinkInteractiveOptions extends WorkspaceLinkOptions {
45
+ /** Injectable for tests; defaults to the real `@clack/prompts`-backed prompter. */
46
+ prompter?: Prompter;
47
+ }
48
+ /**
49
+ * Interactive layer over `runWorkspaceLink` (spec 0004 F5 "argos workspace
50
+ * link"). A pure additive wrapper — the core `runWorkspaceLink` never
51
+ * changes behavior or contract. Without a real TTY this delegates to
52
+ * `runWorkspaceLink(options)` unchanged (there's no `--yes` on this command:
53
+ * absence of a real TTY is itself sufficient gate, per spec 0004). With a
54
+ * TTY: an ambiguous match-rule resolution is resolved via `select` instead
55
+ * of erroring, and a name collision (`WorkspaceNameCollisionError`) is
56
+ * offered as an overwrite/cancel prompt — the interactive equivalent of
57
+ * `--force`, which stays the non-interactive escape hatch unchanged.
58
+ */
59
+ export declare function runWorkspaceLinkInteractive(options: WorkspaceLinkInteractiveOptions): Promise<WorkspaceLinkReport>;
28
60
  export interface WorkspaceShowRepoRow {
29
61
  workspace: string;
30
62
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/commands/workspace.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,iBAAiB,EAEvB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAML,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAS9B,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kGAAkG;IAClG,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CA4EnF;AAiDD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,oBAAoB,EAAE,CAAC;IAC7B,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,4DAA4D;IAC5D,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACxC;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,mBAAmB,CA8BvG;AAkCD,MAAM,WAAW,yBAAyB;IACxC,iFAAiF;IACjF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACxC;AAED,MAAM,MAAM,6BAA6B,GAAG,qBAAqB,GAAG,UAAU,GAAG,gBAAgB,CAAC;AAElG,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,6BAA6B,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,iBAAiB,EAAE,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,yBAA8B,GACtC,wBAAwB,CAsC1B;AAkED,eAAO,MAAM,gBAAgB,qDAU3B,CAAC"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/commands/workspace.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,8 @@ import pc from "picocolors";
4
4
  import { hasConfig, readConfig } from "../lib/config.js";
5
5
  import { getRemoteOriginUrl } from "../lib/git.js";
6
6
  import { OPENCLAW_BINARY, planWorkspaceAgents } from "../lib/openclaw-agents.js";
7
- import { addRemoteMatchRule, linkRepo, loadRegistry, offerMatchRule, resolveWorkspaceForRepo } from "../lib/workspaces.js";
7
+ import { isInteractive, clackPrompter } from "../lib/prompter.js";
8
+ import { addRemoteMatchRule, linkRepo, loadRegistry, offerMatchRule, resolveWorkspaceForRepo, WorkspaceNameCollisionError } from "../lib/workspaces.js";
8
9
  import { hasBinary as hasBinaryDefault } from "../lib/which.js";
9
10
  function errorMessage(err) {
10
11
  return err instanceof Error ? err.message : String(err);
@@ -70,6 +71,18 @@ function errorMessage(err) {
70
71
  force
71
72
  });
72
73
  } catch (err) {
74
+ if (err instanceof WorkspaceNameCollisionError) {
75
+ return {
76
+ exitCode: 1,
77
+ error: errorMessage(err),
78
+ collision: {
79
+ workspaceName: err.workspaceName,
80
+ repoName: err.repoName,
81
+ oldPath: err.oldPath,
82
+ newPath: err.newPath
83
+ }
84
+ };
85
+ }
73
86
  return {
74
87
  exitCode: 1,
75
88
  error: errorMessage(err)
@@ -100,6 +113,87 @@ function errorMessage(err) {
100
113
  matchRuleAdded
101
114
  };
102
115
  }
116
+ /**
117
+ * Interactive layer over `runWorkspaceLink` (spec 0004 F5 "argos workspace
118
+ * link"). A pure additive wrapper — the core `runWorkspaceLink` never
119
+ * changes behavior or contract. Without a real TTY this delegates to
120
+ * `runWorkspaceLink(options)` unchanged (there's no `--yes` on this command:
121
+ * absence of a real TTY is itself sufficient gate, per spec 0004). With a
122
+ * TTY: an ambiguous match-rule resolution is resolved via `select` instead
123
+ * of erroring, and a name collision (`WorkspaceNameCollisionError`) is
124
+ * offered as an overwrite/cancel prompt — the interactive equivalent of
125
+ * `--force`, which stays the non-interactive escape hatch unchanged.
126
+ */ export async function runWorkspaceLinkInteractive(options) {
127
+ if (!isInteractive({})) {
128
+ return runWorkspaceLink(options);
129
+ }
130
+ const prompter = options.prompter ?? clackPrompter;
131
+ const { cwd, explicit, force } = options;
132
+ // Resolve ambiguity read-only first, mirroring runWorkspaceLink's own
133
+ // resolution chain, before ever calling the writing core — an explicit
134
+ // name (whether passed on the CLI or picked here) always short-circuits
135
+ // resolveWorkspaceForRepo straight to "resolved", so no duplicate
136
+ // ambiguity handling happens inside the core call below.
137
+ let effectiveExplicit = explicit;
138
+ if (!explicit) {
139
+ if (!hasConfig(cwd)) return runWorkspaceLink(options); // identical error path, no prompts needed
140
+ let config;
141
+ try {
142
+ config = readConfig(cwd);
143
+ } catch {
144
+ return runWorkspaceLink(options); // identical error path
145
+ }
146
+ const remoteUrl = getRemoteOriginUrl(cwd);
147
+ let registry;
148
+ try {
149
+ registry = loadRegistry();
150
+ } catch {
151
+ return runWorkspaceLink(options); // identical error path
152
+ }
153
+ const resolution = resolveWorkspaceForRepo(registry, {
154
+ configWorkspace: config.workspace,
155
+ remoteUrl,
156
+ repoPath: cwd
157
+ });
158
+ if (resolution.kind === "ambiguous") {
159
+ const chosen = await prompter.select({
160
+ message: `Match ambiguo entre workspaces (${resolution.source}) — elegí uno:`,
161
+ options: resolution.candidates.map((c)=>({
162
+ value: c
163
+ }))
164
+ });
165
+ if (prompter.isCancel(chosen)) {
166
+ prompter.cancel("argos workspace link cancelado — no se tocó nada.");
167
+ return {
168
+ exitCode: 1,
169
+ error: "argos workspace link cancelado por el usuario."
170
+ };
171
+ }
172
+ effectiveExplicit = chosen;
173
+ }
174
+ }
175
+ let report = runWorkspaceLink({
176
+ cwd,
177
+ explicit: effectiveExplicit,
178
+ force
179
+ });
180
+ if (report.collision && !force) {
181
+ const overwrite = await prompter.confirm({
182
+ message: `El repo '${report.collision.repoName}' ya está registrado en el workspace '${report.collision.workspaceName}' ` + `apuntando a otro path.\n actual: ${report.collision.oldPath}\n nuevo: ${report.collision.newPath}\n` + "¿Sobrescribir con el path nuevo?",
183
+ initialValue: false
184
+ });
185
+ if (prompter.isCancel(overwrite) || !overwrite) {
186
+ prompter.cancel("argos workspace link cancelado — no se tocó nada.");
187
+ return report; // original failed report — nothing further was touched
188
+ }
189
+ report = runWorkspaceLink({
190
+ cwd,
191
+ explicit: effectiveExplicit,
192
+ force: true
193
+ });
194
+ }
195
+ return report;
196
+ }
103
197
  const linkSubCommand = defineCommand({
104
198
  meta: {
105
199
  name: "link",
@@ -117,8 +211,8 @@ const linkSubCommand = defineCommand({
117
211
  description: "Sobrescribe un choque de nombre (mismo config.name, repo físico distinto)."
118
212
  }
119
213
  },
120
- run ({ args }) {
121
- const report = runWorkspaceLink({
214
+ async run ({ args }) {
215
+ const report = await runWorkspaceLinkInteractive({
122
216
  cwd: process.cwd(),
123
217
  explicit: args.name?.trim() || undefined,
124
218
  force: Boolean(args.force)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/workspace.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { existsSync } from \"node:fs\";\nimport pc from \"picocolors\";\nimport { hasConfig, readConfig, type ArgosConfig } from \"../lib/config.js\";\nimport { getRemoteOriginUrl } from \"../lib/git.js\";\nimport {\n OPENCLAW_BINARY,\n planWorkspaceAgents,\n type OpenclawRunner,\n type WorkspaceAgentRow,\n type WorkspaceAgentStatus,\n} from \"../lib/openclaw-agents.js\";\nimport {\n addRemoteMatchRule,\n linkRepo,\n loadRegistry,\n offerMatchRule,\n resolveWorkspaceForRepo,\n type LinkAction,\n} from \"../lib/workspaces.js\";\nimport { hasBinary as hasBinaryDefault } from \"../lib/which.js\";\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n// --- link --------------------------------------------------------------\n\nexport interface WorkspaceLinkOptions {\n cwd: string;\n /** Explicit workspace name passed on the command line, if any. */\n explicit?: string;\n /** Overwrite a name collision (same config.name, different physical repo) instead of refusing. */\n force?: boolean;\n}\n\nexport interface WorkspaceLinkReport {\n exitCode: 0 | 1;\n error?: string;\n ambiguousCandidates?: string[];\n workspaceName?: string;\n action?: LinkAction;\n createdWorkspace?: boolean;\n /** Remote identity persisted as a new match rule, if the offer fired. */\n matchRuleAdded?: string;\n}\n\n/**\n * Core, testable implementation of `argos workspace link [nombre]`: resolves\n * which workspace the repo at `cwd` belongs to (explicit name > config >\n * match rules) and registers it. When a brand-new workspace was created via\n * an explicit name and the repo has a remote, teaches the registry that\n * remote as a match rule so future repos under the same identity auto-link.\n */\nexport function runWorkspaceLink(options: WorkspaceLinkOptions): WorkspaceLinkReport {\n const { cwd, explicit, force } = options;\n\n if (!hasConfig(cwd)) {\n return {\n exitCode: 1,\n error: \"No se encontró argos.config.json en este directorio — corre `argos adopt` primero.\",\n };\n }\n\n let config: ArgosConfig;\n try {\n config = readConfig(cwd);\n } catch (err) {\n return { exitCode: 1, error: `argos.config.json inválido — ${errorMessage(err)}` };\n }\n\n const remoteUrl = getRemoteOriginUrl(cwd);\n let registry;\n try {\n registry = loadRegistry();\n } catch (err) {\n return { exitCode: 1, error: errorMessage(err) };\n }\n const resolution = resolveWorkspaceForRepo(registry, {\n explicit,\n configWorkspace: config.workspace,\n remoteUrl,\n repoPath: cwd,\n });\n\n if (resolution.kind === \"unresolved\") {\n return {\n exitCode: 1,\n error:\n \"No se pudo resolver un workspace para este repo — pasá un nombre explícito: \" +\n \"`argos workspace link <nombre>`.\",\n };\n }\n if (resolution.kind === \"ambiguous\") {\n return {\n exitCode: 1,\n error: `Match ambiguo entre workspaces (${resolution.candidates.join(\", \")}) — pasá un nombre explícito.`,\n ambiguousCandidates: resolution.candidates,\n };\n }\n\n let linkResult;\n try {\n linkResult = linkRepo(resolution.name, { name: config.name, path: cwd }, { force });\n } catch (err) {\n return { exitCode: 1, error: errorMessage(err) };\n }\n\n let matchRuleAdded: string | undefined;\n if (resolution.source === \"explicit\") {\n const currentMatch = loadRegistry()[resolution.name]?.match ?? { remotes: [], paths: [] };\n const offer = offerMatchRule({\n createdWorkspace: linkResult.createdWorkspace,\n viaExplicitName: true,\n remoteUrl,\n currentMatch,\n });\n if (offer.shouldPersist && offer.identity) {\n addRemoteMatchRule(resolution.name, offer.identity);\n matchRuleAdded = offer.identity;\n }\n }\n\n return {\n exitCode: 0,\n workspaceName: resolution.name,\n action: linkResult.action,\n createdWorkspace: linkResult.createdWorkspace,\n matchRuleAdded,\n };\n}\n\nconst linkSubCommand = defineCommand({\n meta: {\n name: \"link\",\n description: \"Vincula el repo actual a un workspace (lo crea si no existe).\",\n },\n args: {\n name: { type: \"positional\", description: \"Nombre de workspace explícito\", required: false },\n force: {\n type: \"boolean\",\n default: false,\n description: \"Sobrescribe un choque de nombre (mismo config.name, repo físico distinto).\",\n },\n },\n run({ args }) {\n const report = runWorkspaceLink({\n cwd: process.cwd(),\n explicit: (args.name as string | undefined)?.trim() || undefined,\n force: Boolean(args.force),\n });\n\n if (report.error) {\n console.error(pc.red(report.error));\n process.exit(report.exitCode);\n }\n\n if (report.createdWorkspace) {\n console.log(pc.dim(`Workspace '${report.workspaceName}' creado.`));\n }\n const actionLabel: Record<LinkAction, string> = {\n added: \"registrado\",\n \"updated-path\": \"path actualizado\",\n unchanged: \"sin cambios\",\n };\n console.log(\n `${pc.green(\"✓\")} repo ${actionLabel[report.action as LinkAction]} en workspace '${report.workspaceName}'.`,\n );\n if (report.matchRuleAdded) {\n console.log(\n pc.dim(`El remote '${report.matchRuleAdded}' se guardó como match rule del workspace.`),\n );\n }\n process.exit(report.exitCode);\n },\n});\n\n// --- show ----------------------------------------------------------------\n\nexport interface WorkspaceShowRepoRow {\n workspace: string;\n name: string;\n path: string;\n missing: boolean;\n}\n\nexport interface WorkspaceShowReport {\n rows: WorkspaceShowRepoRow[];\n exitCode: 0 | 1;\n error?: string;\n}\n\nexport interface WorkspaceShowOptions {\n /** Injectable for tests; defaults to node:fs existsSync. */\n pathExists?: (path: string) => boolean;\n}\n\n/** Core, testable implementation of `argos workspace show [nombre]`. */\nexport function runWorkspaceShow(name?: string, options: WorkspaceShowOptions = {}): WorkspaceShowReport {\n const pathExists = options.pathExists ?? existsSync;\n let registry;\n try {\n registry = loadRegistry();\n } catch (err) {\n return { rows: [], exitCode: 1, error: errorMessage(err) };\n }\n\n if (name) {\n const workspace = registry[name];\n if (!workspace) {\n return { rows: [], exitCode: 1, error: `Workspace '${name}' no encontrado.` };\n }\n const rows = workspace.repos.map((r) => ({\n workspace: name,\n name: r.name,\n path: r.path,\n missing: !pathExists(r.path),\n }));\n return { rows, exitCode: 0 };\n }\n\n const rows: WorkspaceShowRepoRow[] = [];\n for (const [wsName, workspace] of Object.entries(registry)) {\n for (const repo of workspace.repos) {\n rows.push({ workspace: wsName, name: repo.name, path: repo.path, missing: !pathExists(repo.path) });\n }\n }\n return { rows, exitCode: 0 };\n}\n\nconst showSubCommand = defineCommand({\n meta: {\n name: \"show\",\n description: \"Muestra los repos registrados en uno o todos los workspaces.\",\n },\n args: {\n name: { type: \"positional\", description: \"Nombre de workspace (default: todos)\", required: false },\n },\n run({ args }) {\n const name = (args.name as string | undefined)?.trim() || undefined;\n const report = runWorkspaceShow(name);\n\n if (report.error) {\n console.error(pc.red(report.error));\n process.exit(report.exitCode);\n }\n\n if (report.rows.length === 0) {\n console.log(\"Ningún repo registrado todavía. Corre `argos workspace link` desde un repo.\");\n process.exit(0);\n }\n\n for (const row of report.rows) {\n const flag = row.missing ? pc.red(\"(path inexistente)\") : \"\";\n console.log(`${pc.dim(row.workspace.padEnd(16))} ${row.name.padEnd(24)} ${row.path} ${flag}`.trimEnd());\n }\n process.exit(0);\n },\n});\n\n// --- agents ----------------------------------------------------------------\n\nexport interface RunWorkspaceAgentsOptions {\n /** false (default) = preview only; true = actually run `openclaw agents add`. */\n apply?: boolean;\n prefix?: string;\n /** Injectable for tests; defaults to lib/which.ts hasBinary. */\n hasBinary?: (name: string) => boolean;\n /** Injectable for tests; forwarded to planWorkspaceAgents. */\n runner?: OpenclawRunner;\n /** Injectable for tests; forwarded to planWorkspaceAgents. */\n pathExists?: (path: string) => boolean;\n}\n\nexport type RunWorkspaceAgentsEarlyReason = \"workspace-not-found\" | \"no-repos\" | \"binary-missing\";\n\nexport interface RunWorkspaceAgentsResult {\n exitCode: 0 | 1;\n preview: boolean;\n reason?: RunWorkspaceAgentsEarlyReason;\n error?: string;\n rows: WorkspaceAgentRow[];\n}\n\n/**\n * Core logic for `workspace agents <nombre>`. Preview (default) never\n * spawns anything — it only formats the commands that would run. `--apply`\n * requires the `openclaw` binary on PATH; a per-repo failure never aborts\n * the rest of the workspace (planWorkspaceAgents already guarantees this),\n * so the exit code reflects the honest partial summary.\n */\nexport function runWorkspaceAgents(\n name: string,\n options: RunWorkspaceAgentsOptions = {},\n): RunWorkspaceAgentsResult {\n const apply = Boolean(options.apply);\n const preview = !apply;\n\n let registry;\n try {\n registry = loadRegistry();\n } catch (err) {\n return { exitCode: 1, preview, error: errorMessage(err), rows: [] };\n }\n const workspace = registry[name];\n if (!workspace) {\n return {\n exitCode: 1,\n preview,\n reason: \"workspace-not-found\",\n error: `Workspace '${name}' no encontrado.`,\n rows: [],\n };\n }\n\n if (workspace.repos.length === 0) {\n return { exitCode: 0, preview, reason: \"no-repos\", rows: [] };\n }\n\n const checkBinary = options.hasBinary ?? hasBinaryDefault;\n if (apply && !checkBinary(OPENCLAW_BINARY)) {\n return { exitCode: 1, preview, reason: \"binary-missing\", rows: [] };\n }\n\n const rows = planWorkspaceAgents(workspace.repos, {\n preview,\n prefix: options.prefix ?? \"\",\n runner: options.runner,\n pathExists: options.pathExists,\n });\n const failed = rows.filter((r) => r.status === \"error\" || r.status === \"missing\").length;\n return { exitCode: failed > 0 ? 1 : 0, preview, rows };\n}\n\nconst agentsSubCommand = defineCommand({\n meta: {\n name: \"agents\",\n description: \"Crea un agente OpenClaw por repo registrado en el workspace.\",\n },\n args: {\n name: { type: \"positional\", description: \"Nombre de workspace\", required: true },\n apply: {\n type: \"boolean\",\n default: false,\n description: \"Ejecuta 'openclaw agents add' de verdad. Sin esto, todo se previsualiza.\",\n },\n prefix: {\n type: \"string\",\n description: \"Prefijo para cada nombre de agente OpenClaw.\",\n },\n },\n run({ args }) {\n const name = args.name as string;\n const apply = Boolean(args.apply);\n const prefix = (args.prefix as string | undefined) ?? \"\";\n\n const result = runWorkspaceAgents(name, { apply, prefix });\n\n if (result.reason === \"workspace-not-found\") {\n console.error(pc.red(result.error ?? `Workspace '${name}' no encontrado.`));\n process.exit(result.exitCode);\n }\n if (result.reason === \"no-repos\") {\n console.log(\"Ningún repo registrado en este workspace. Corre `argos workspace link` desde un repo.\");\n process.exit(0);\n }\n if (result.reason === \"binary-missing\") {\n console.error(\n pc.red(\n `No se encontró el binario '${OPENCLAW_BINARY}' en PATH. Este comando crea agentes OpenClaw ` +\n `y está pensado para correr donde OpenClaw está instalado (típicamente el VPS de agentes).`,\n ),\n );\n process.exit(result.exitCode);\n }\n\n const marker: Record<WorkspaceAgentStatus, string> = {\n created: pc.green(\"✓\"),\n \"would-create\": pc.yellow(\"•\"),\n exists: pc.dim(\"•\"),\n missing: pc.red(\"✗\"),\n error: pc.red(\"✗\"),\n };\n for (const row of result.rows) {\n console.log(`${marker[row.status]} ${row.name.padEnd(24)} ${pc.dim(row.status)} ${row.detail}`);\n }\n\n const failed = result.rows.filter((r) => r.status === \"error\" || r.status === \"missing\").length;\n const ok = result.rows.length - failed;\n const summary = result.preview\n ? `${ok}/${result.rows.length} ok · ${failed} fallidos`\n : `${ok}/${result.rows.length} ok · ${failed} fallidos`;\n console.log(\"\");\n console.log(result.preview ? pc.yellow(`Preview — ${summary}`) : pc.green(`Listo — ${summary}`));\n process.exit(result.exitCode);\n },\n});\n\nexport const workspaceCommand = defineCommand({\n meta: {\n name: \"workspace\",\n description: \"Registro machine-local de workspaces (match rules + flota OpenClaw).\",\n },\n subCommands: {\n link: linkSubCommand,\n show: showSubCommand,\n agents: agentsSubCommand,\n },\n});\n"],"names":["defineCommand","existsSync","pc","hasConfig","readConfig","getRemoteOriginUrl","OPENCLAW_BINARY","planWorkspaceAgents","addRemoteMatchRule","linkRepo","loadRegistry","offerMatchRule","resolveWorkspaceForRepo","hasBinary","hasBinaryDefault","errorMessage","err","Error","message","String","runWorkspaceLink","options","cwd","explicit","force","exitCode","error","config","remoteUrl","registry","resolution","configWorkspace","workspace","repoPath","kind","candidates","join","ambiguousCandidates","linkResult","name","path","matchRuleAdded","source","currentMatch","match","remotes","paths","offer","createdWorkspace","viaExplicitName","shouldPersist","identity","workspaceName","action","linkSubCommand","meta","description","args","type","required","default","run","report","process","trim","undefined","Boolean","console","red","exit","log","dim","actionLabel","added","unchanged","green","runWorkspaceShow","pathExists","rows","repos","map","r","missing","wsName","Object","entries","repo","push","showSubCommand","length","row","flag","padEnd","trimEnd","runWorkspaceAgents","apply","preview","reason","checkBinary","prefix","runner","failed","filter","status","agentsSubCommand","result","marker","created","yellow","exists","detail","ok","summary","workspaceCommand","subCommands","link","show","agents"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/commands/workspace.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { existsSync } from \"node:fs\";\nimport pc from \"picocolors\";\nimport { hasConfig, readConfig, type ArgosConfig } from \"../lib/config.js\";\nimport { getRemoteOriginUrl } from \"../lib/git.js\";\nimport {\n OPENCLAW_BINARY,\n planWorkspaceAgents,\n type OpenclawRunner,\n type WorkspaceAgentRow,\n type WorkspaceAgentStatus,\n} from \"../lib/openclaw-agents.js\";\nimport { isInteractive, clackPrompter, type Prompter } from \"../lib/prompter.js\";\nimport {\n addRemoteMatchRule,\n linkRepo,\n loadRegistry,\n offerMatchRule,\n resolveWorkspaceForRepo,\n WorkspaceNameCollisionError,\n type LinkAction,\n} from \"../lib/workspaces.js\";\nimport { hasBinary as hasBinaryDefault } from \"../lib/which.js\";\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n// --- link --------------------------------------------------------------\n\nexport interface WorkspaceLinkOptions {\n cwd: string;\n /** Explicit workspace name passed on the command line, if any. */\n explicit?: string;\n /** Overwrite a name collision (same config.name, different physical repo) instead of refusing. */\n force?: boolean;\n}\n\nexport interface WorkspaceLinkCollision {\n workspaceName: string;\n repoName: string;\n oldPath: string;\n newPath: string;\n}\n\nexport interface WorkspaceLinkReport {\n exitCode: 0 | 1;\n error?: string;\n ambiguousCandidates?: string[];\n workspaceName?: string;\n action?: LinkAction;\n createdWorkspace?: boolean;\n /** Remote identity persisted as a new match rule, if the offer fired. */\n matchRuleAdded?: string;\n /**\n * Populated instead of a bare `error` string when `linkRepo` refused with\n * `WorkspaceNameCollisionError` (see lib/workspaces.ts) — lets the\n * interactive layer offer overwrite/cancel (the equivalent of `--force`)\n * without having to string-parse `error`. Additive: `error` is still set\n * alongside it, so any caller only reading `error` behaves exactly as\n * before.\n */\n collision?: WorkspaceLinkCollision;\n}\n\n/**\n * Core, testable implementation of `argos workspace link [nombre]`: resolves\n * which workspace the repo at `cwd` belongs to (explicit name > config >\n * match rules) and registers it. When a brand-new workspace was created via\n * an explicit name and the repo has a remote, teaches the registry that\n * remote as a match rule so future repos under the same identity auto-link.\n */\nexport function runWorkspaceLink(options: WorkspaceLinkOptions): WorkspaceLinkReport {\n const { cwd, explicit, force } = options;\n\n if (!hasConfig(cwd)) {\n return {\n exitCode: 1,\n error: \"No se encontró argos.config.json en este directorio — corre `argos adopt` primero.\",\n };\n }\n\n let config: ArgosConfig;\n try {\n config = readConfig(cwd);\n } catch (err) {\n return { exitCode: 1, error: `argos.config.json inválido — ${errorMessage(err)}` };\n }\n\n const remoteUrl = getRemoteOriginUrl(cwd);\n let registry;\n try {\n registry = loadRegistry();\n } catch (err) {\n return { exitCode: 1, error: errorMessage(err) };\n }\n const resolution = resolveWorkspaceForRepo(registry, {\n explicit,\n configWorkspace: config.workspace,\n remoteUrl,\n repoPath: cwd,\n });\n\n if (resolution.kind === \"unresolved\") {\n return {\n exitCode: 1,\n error:\n \"No se pudo resolver un workspace para este repo — pasá un nombre explícito: \" +\n \"`argos workspace link <nombre>`.\",\n };\n }\n if (resolution.kind === \"ambiguous\") {\n return {\n exitCode: 1,\n error: `Match ambiguo entre workspaces (${resolution.candidates.join(\", \")}) — pasá un nombre explícito.`,\n ambiguousCandidates: resolution.candidates,\n };\n }\n\n let linkResult;\n try {\n linkResult = linkRepo(resolution.name, { name: config.name, path: cwd }, { force });\n } catch (err) {\n if (err instanceof WorkspaceNameCollisionError) {\n return {\n exitCode: 1,\n error: errorMessage(err),\n collision: {\n workspaceName: err.workspaceName,\n repoName: err.repoName,\n oldPath: err.oldPath,\n newPath: err.newPath,\n },\n };\n }\n return { exitCode: 1, error: errorMessage(err) };\n }\n\n let matchRuleAdded: string | undefined;\n if (resolution.source === \"explicit\") {\n const currentMatch = loadRegistry()[resolution.name]?.match ?? { remotes: [], paths: [] };\n const offer = offerMatchRule({\n createdWorkspace: linkResult.createdWorkspace,\n viaExplicitName: true,\n remoteUrl,\n currentMatch,\n });\n if (offer.shouldPersist && offer.identity) {\n addRemoteMatchRule(resolution.name, offer.identity);\n matchRuleAdded = offer.identity;\n }\n }\n\n return {\n exitCode: 0,\n workspaceName: resolution.name,\n action: linkResult.action,\n createdWorkspace: linkResult.createdWorkspace,\n matchRuleAdded,\n };\n}\n\nexport interface WorkspaceLinkInteractiveOptions extends WorkspaceLinkOptions {\n /** Injectable for tests; defaults to the real `@clack/prompts`-backed prompter. */\n prompter?: Prompter;\n}\n\n/**\n * Interactive layer over `runWorkspaceLink` (spec 0004 F5 \"argos workspace\n * link\"). A pure additive wrapper — the core `runWorkspaceLink` never\n * changes behavior or contract. Without a real TTY this delegates to\n * `runWorkspaceLink(options)` unchanged (there's no `--yes` on this command:\n * absence of a real TTY is itself sufficient gate, per spec 0004). With a\n * TTY: an ambiguous match-rule resolution is resolved via `select` instead\n * of erroring, and a name collision (`WorkspaceNameCollisionError`) is\n * offered as an overwrite/cancel prompt — the interactive equivalent of\n * `--force`, which stays the non-interactive escape hatch unchanged.\n */\nexport async function runWorkspaceLinkInteractive(\n options: WorkspaceLinkInteractiveOptions,\n): Promise<WorkspaceLinkReport> {\n if (!isInteractive({})) {\n return runWorkspaceLink(options);\n }\n\n const prompter = options.prompter ?? clackPrompter;\n const { cwd, explicit, force } = options;\n\n // Resolve ambiguity read-only first, mirroring runWorkspaceLink's own\n // resolution chain, before ever calling the writing core — an explicit\n // name (whether passed on the CLI or picked here) always short-circuits\n // resolveWorkspaceForRepo straight to \"resolved\", so no duplicate\n // ambiguity handling happens inside the core call below.\n let effectiveExplicit = explicit;\n if (!explicit) {\n if (!hasConfig(cwd)) return runWorkspaceLink(options); // identical error path, no prompts needed\n let config: ArgosConfig;\n try {\n config = readConfig(cwd);\n } catch {\n return runWorkspaceLink(options); // identical error path\n }\n const remoteUrl = getRemoteOriginUrl(cwd);\n let registry: ReturnType<typeof loadRegistry>;\n try {\n registry = loadRegistry();\n } catch {\n return runWorkspaceLink(options); // identical error path\n }\n const resolution = resolveWorkspaceForRepo(registry, { configWorkspace: config.workspace, remoteUrl, repoPath: cwd });\n if (resolution.kind === \"ambiguous\") {\n const chosen = await prompter.select<string>({\n message: `Match ambiguo entre workspaces (${resolution.source}) — elegí uno:`,\n options: resolution.candidates.map((c) => ({ value: c })),\n });\n if (prompter.isCancel(chosen)) {\n prompter.cancel(\"argos workspace link cancelado — no se tocó nada.\");\n return { exitCode: 1, error: \"argos workspace link cancelado por el usuario.\" };\n }\n effectiveExplicit = chosen;\n }\n }\n\n let report = runWorkspaceLink({ cwd, explicit: effectiveExplicit, force });\n\n if (report.collision && !force) {\n const overwrite = await prompter.confirm({\n message:\n `El repo '${report.collision.repoName}' ya está registrado en el workspace '${report.collision.workspaceName}' ` +\n `apuntando a otro path.\\n actual: ${report.collision.oldPath}\\n nuevo: ${report.collision.newPath}\\n` +\n \"¿Sobrescribir con el path nuevo?\",\n initialValue: false,\n });\n if (prompter.isCancel(overwrite) || !overwrite) {\n prompter.cancel(\"argos workspace link cancelado — no se tocó nada.\");\n return report; // original failed report — nothing further was touched\n }\n report = runWorkspaceLink({ cwd, explicit: effectiveExplicit, force: true });\n }\n\n return report;\n}\n\nconst linkSubCommand = defineCommand({\n meta: {\n name: \"link\",\n description: \"Vincula el repo actual a un workspace (lo crea si no existe).\",\n },\n args: {\n name: { type: \"positional\", description: \"Nombre de workspace explícito\", required: false },\n force: {\n type: \"boolean\",\n default: false,\n description: \"Sobrescribe un choque de nombre (mismo config.name, repo físico distinto).\",\n },\n },\n async run({ args }) {\n const report = await runWorkspaceLinkInteractive({\n cwd: process.cwd(),\n explicit: (args.name as string | undefined)?.trim() || undefined,\n force: Boolean(args.force),\n });\n\n if (report.error) {\n console.error(pc.red(report.error));\n process.exit(report.exitCode);\n }\n\n if (report.createdWorkspace) {\n console.log(pc.dim(`Workspace '${report.workspaceName}' creado.`));\n }\n const actionLabel: Record<LinkAction, string> = {\n added: \"registrado\",\n \"updated-path\": \"path actualizado\",\n unchanged: \"sin cambios\",\n };\n console.log(\n `${pc.green(\"✓\")} repo ${actionLabel[report.action as LinkAction]} en workspace '${report.workspaceName}'.`,\n );\n if (report.matchRuleAdded) {\n console.log(\n pc.dim(`El remote '${report.matchRuleAdded}' se guardó como match rule del workspace.`),\n );\n }\n process.exit(report.exitCode);\n },\n});\n\n// --- show ----------------------------------------------------------------\n\nexport interface WorkspaceShowRepoRow {\n workspace: string;\n name: string;\n path: string;\n missing: boolean;\n}\n\nexport interface WorkspaceShowReport {\n rows: WorkspaceShowRepoRow[];\n exitCode: 0 | 1;\n error?: string;\n}\n\nexport interface WorkspaceShowOptions {\n /** Injectable for tests; defaults to node:fs existsSync. */\n pathExists?: (path: string) => boolean;\n}\n\n/** Core, testable implementation of `argos workspace show [nombre]`. */\nexport function runWorkspaceShow(name?: string, options: WorkspaceShowOptions = {}): WorkspaceShowReport {\n const pathExists = options.pathExists ?? existsSync;\n let registry;\n try {\n registry = loadRegistry();\n } catch (err) {\n return { rows: [], exitCode: 1, error: errorMessage(err) };\n }\n\n if (name) {\n const workspace = registry[name];\n if (!workspace) {\n return { rows: [], exitCode: 1, error: `Workspace '${name}' no encontrado.` };\n }\n const rows = workspace.repos.map((r) => ({\n workspace: name,\n name: r.name,\n path: r.path,\n missing: !pathExists(r.path),\n }));\n return { rows, exitCode: 0 };\n }\n\n const rows: WorkspaceShowRepoRow[] = [];\n for (const [wsName, workspace] of Object.entries(registry)) {\n for (const repo of workspace.repos) {\n rows.push({ workspace: wsName, name: repo.name, path: repo.path, missing: !pathExists(repo.path) });\n }\n }\n return { rows, exitCode: 0 };\n}\n\nconst showSubCommand = defineCommand({\n meta: {\n name: \"show\",\n description: \"Muestra los repos registrados en uno o todos los workspaces.\",\n },\n args: {\n name: { type: \"positional\", description: \"Nombre de workspace (default: todos)\", required: false },\n },\n run({ args }) {\n const name = (args.name as string | undefined)?.trim() || undefined;\n const report = runWorkspaceShow(name);\n\n if (report.error) {\n console.error(pc.red(report.error));\n process.exit(report.exitCode);\n }\n\n if (report.rows.length === 0) {\n console.log(\"Ningún repo registrado todavía. Corre `argos workspace link` desde un repo.\");\n process.exit(0);\n }\n\n for (const row of report.rows) {\n const flag = row.missing ? pc.red(\"(path inexistente)\") : \"\";\n console.log(`${pc.dim(row.workspace.padEnd(16))} ${row.name.padEnd(24)} ${row.path} ${flag}`.trimEnd());\n }\n process.exit(0);\n },\n});\n\n// --- agents ----------------------------------------------------------------\n\nexport interface RunWorkspaceAgentsOptions {\n /** false (default) = preview only; true = actually run `openclaw agents add`. */\n apply?: boolean;\n prefix?: string;\n /** Injectable for tests; defaults to lib/which.ts hasBinary. */\n hasBinary?: (name: string) => boolean;\n /** Injectable for tests; forwarded to planWorkspaceAgents. */\n runner?: OpenclawRunner;\n /** Injectable for tests; forwarded to planWorkspaceAgents. */\n pathExists?: (path: string) => boolean;\n}\n\nexport type RunWorkspaceAgentsEarlyReason = \"workspace-not-found\" | \"no-repos\" | \"binary-missing\";\n\nexport interface RunWorkspaceAgentsResult {\n exitCode: 0 | 1;\n preview: boolean;\n reason?: RunWorkspaceAgentsEarlyReason;\n error?: string;\n rows: WorkspaceAgentRow[];\n}\n\n/**\n * Core logic for `workspace agents <nombre>`. Preview (default) never\n * spawns anything — it only formats the commands that would run. `--apply`\n * requires the `openclaw` binary on PATH; a per-repo failure never aborts\n * the rest of the workspace (planWorkspaceAgents already guarantees this),\n * so the exit code reflects the honest partial summary.\n */\nexport function runWorkspaceAgents(\n name: string,\n options: RunWorkspaceAgentsOptions = {},\n): RunWorkspaceAgentsResult {\n const apply = Boolean(options.apply);\n const preview = !apply;\n\n let registry;\n try {\n registry = loadRegistry();\n } catch (err) {\n return { exitCode: 1, preview, error: errorMessage(err), rows: [] };\n }\n const workspace = registry[name];\n if (!workspace) {\n return {\n exitCode: 1,\n preview,\n reason: \"workspace-not-found\",\n error: `Workspace '${name}' no encontrado.`,\n rows: [],\n };\n }\n\n if (workspace.repos.length === 0) {\n return { exitCode: 0, preview, reason: \"no-repos\", rows: [] };\n }\n\n const checkBinary = options.hasBinary ?? hasBinaryDefault;\n if (apply && !checkBinary(OPENCLAW_BINARY)) {\n return { exitCode: 1, preview, reason: \"binary-missing\", rows: [] };\n }\n\n const rows = planWorkspaceAgents(workspace.repos, {\n preview,\n prefix: options.prefix ?? \"\",\n runner: options.runner,\n pathExists: options.pathExists,\n });\n const failed = rows.filter((r) => r.status === \"error\" || r.status === \"missing\").length;\n return { exitCode: failed > 0 ? 1 : 0, preview, rows };\n}\n\nconst agentsSubCommand = defineCommand({\n meta: {\n name: \"agents\",\n description: \"Crea un agente OpenClaw por repo registrado en el workspace.\",\n },\n args: {\n name: { type: \"positional\", description: \"Nombre de workspace\", required: true },\n apply: {\n type: \"boolean\",\n default: false,\n description: \"Ejecuta 'openclaw agents add' de verdad. Sin esto, todo se previsualiza.\",\n },\n prefix: {\n type: \"string\",\n description: \"Prefijo para cada nombre de agente OpenClaw.\",\n },\n },\n run({ args }) {\n const name = args.name as string;\n const apply = Boolean(args.apply);\n const prefix = (args.prefix as string | undefined) ?? \"\";\n\n const result = runWorkspaceAgents(name, { apply, prefix });\n\n if (result.reason === \"workspace-not-found\") {\n console.error(pc.red(result.error ?? `Workspace '${name}' no encontrado.`));\n process.exit(result.exitCode);\n }\n if (result.reason === \"no-repos\") {\n console.log(\"Ningún repo registrado en este workspace. Corre `argos workspace link` desde un repo.\");\n process.exit(0);\n }\n if (result.reason === \"binary-missing\") {\n console.error(\n pc.red(\n `No se encontró el binario '${OPENCLAW_BINARY}' en PATH. Este comando crea agentes OpenClaw ` +\n `y está pensado para correr donde OpenClaw está instalado (típicamente el VPS de agentes).`,\n ),\n );\n process.exit(result.exitCode);\n }\n\n const marker: Record<WorkspaceAgentStatus, string> = {\n created: pc.green(\"✓\"),\n \"would-create\": pc.yellow(\"•\"),\n exists: pc.dim(\"•\"),\n missing: pc.red(\"✗\"),\n error: pc.red(\"✗\"),\n };\n for (const row of result.rows) {\n console.log(`${marker[row.status]} ${row.name.padEnd(24)} ${pc.dim(row.status)} ${row.detail}`);\n }\n\n const failed = result.rows.filter((r) => r.status === \"error\" || r.status === \"missing\").length;\n const ok = result.rows.length - failed;\n const summary = result.preview\n ? `${ok}/${result.rows.length} ok · ${failed} fallidos`\n : `${ok}/${result.rows.length} ok · ${failed} fallidos`;\n console.log(\"\");\n console.log(result.preview ? pc.yellow(`Preview — ${summary}`) : pc.green(`Listo — ${summary}`));\n process.exit(result.exitCode);\n },\n});\n\nexport const workspaceCommand = defineCommand({\n meta: {\n name: \"workspace\",\n description: \"Registro machine-local de workspaces (match rules + flota OpenClaw).\",\n },\n subCommands: {\n link: linkSubCommand,\n show: showSubCommand,\n agents: agentsSubCommand,\n },\n});\n"],"names":["defineCommand","existsSync","pc","hasConfig","readConfig","getRemoteOriginUrl","OPENCLAW_BINARY","planWorkspaceAgents","isInteractive","clackPrompter","addRemoteMatchRule","linkRepo","loadRegistry","offerMatchRule","resolveWorkspaceForRepo","WorkspaceNameCollisionError","hasBinary","hasBinaryDefault","errorMessage","err","Error","message","String","runWorkspaceLink","options","cwd","explicit","force","exitCode","error","config","remoteUrl","registry","resolution","configWorkspace","workspace","repoPath","kind","candidates","join","ambiguousCandidates","linkResult","name","path","collision","workspaceName","repoName","oldPath","newPath","matchRuleAdded","source","currentMatch","match","remotes","paths","offer","createdWorkspace","viaExplicitName","shouldPersist","identity","action","runWorkspaceLinkInteractive","prompter","effectiveExplicit","chosen","select","map","c","value","isCancel","cancel","report","overwrite","confirm","initialValue","linkSubCommand","meta","description","args","type","required","default","run","process","trim","undefined","Boolean","console","red","exit","log","dim","actionLabel","added","unchanged","green","runWorkspaceShow","pathExists","rows","repos","r","missing","wsName","Object","entries","repo","push","showSubCommand","length","row","flag","padEnd","trimEnd","runWorkspaceAgents","apply","preview","reason","checkBinary","prefix","runner","failed","filter","status","agentsSubCommand","result","marker","created","yellow","exists","detail","ok","summary","workspaceCommand","subCommands","link","show","agents"],"mappings":"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"}