@cleocode/cleo 2026.4.17 → 2026.4.19

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/dist/cli/index.js CHANGED
@@ -11114,13 +11114,54 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable, logSubsyst
11114
11114
  }
11115
11115
  }
11116
11116
  }
11117
+ if (tableExists(nativeDb, "__drizzle_migrations") && tableExists(nativeDb, existenceTable)) {
11118
+ const localMigrations = readMigrationFiles({ migrationsFolder });
11119
+ const journalEntries = nativeDb.prepare('SELECT hash FROM "__drizzle_migrations"').all();
11120
+ const journaledHashes = new Set(journalEntries.map((e) => e.hash));
11121
+ for (const migration of localMigrations) {
11122
+ if (journaledHashes.has(migration.hash)) continue;
11123
+ const alterColumnRegex = /ALTER\s+TABLE\s+[`"]?(\w+)[`"]?\s+ADD\s+COLUMN\s+[`"]?(\w+)[`"]?/gi;
11124
+ const alterMatches = [];
11125
+ const sqlStatements = Array.isArray(migration.sql) ? migration.sql : [migration.sql ?? ""];
11126
+ const fullSql = sqlStatements.join("\n");
11127
+ for (const m2 of fullSql.matchAll(alterColumnRegex)) {
11128
+ alterMatches.push({ table: m2[1], column: m2[2] });
11129
+ }
11130
+ if (alterMatches.length === 0) continue;
11131
+ const allColumnsExist = alterMatches.every(({ table, column }) => {
11132
+ if (!tableExists(nativeDb, table)) return false;
11133
+ const cols = nativeDb.prepare(`PRAGMA table_info(${table})`).all();
11134
+ return cols.some((c) => c.name === column);
11135
+ });
11136
+ if (allColumnsExist) {
11137
+ const log11 = getLogger(logSubsystem);
11138
+ log11.warn(
11139
+ { migration: migration.name, columns: alterMatches },
11140
+ `Detected partially-applied migration ${migration.name} \u2014 columns exist but journal entry missing. Auto-reconciling.`
11141
+ );
11142
+ nativeDb.exec(
11143
+ `INSERT INTO "__drizzle_migrations" ("hash", "created_at") VALUES ('${migration.hash}', ${migration.folderMillis})`
11144
+ );
11145
+ }
11146
+ }
11147
+ }
11148
+ }
11149
+ function isDuplicateColumnError(err) {
11150
+ if (!(err instanceof Error)) return false;
11151
+ return /duplicate column name/i.test(err.message);
11117
11152
  }
11118
- function migrateWithRetry(db, migrationsFolder) {
11153
+ function migrateWithRetry(db, migrationsFolder, nativeDb, existenceTable, logSubsystem) {
11154
+ let duplicateColumnReconciled = false;
11119
11155
  for (let attempt = 1; attempt <= MAX_MIGRATION_RETRIES; attempt++) {
11120
11156
  try {
11121
11157
  migrate(db, { migrationsFolder });
11122
11158
  return;
11123
11159
  } catch (err) {
11160
+ if (isDuplicateColumnError(err) && !duplicateColumnReconciled && nativeDb !== void 0 && existenceTable !== void 0 && logSubsystem !== void 0) {
11161
+ duplicateColumnReconciled = true;
11162
+ reconcileJournal(nativeDb, migrationsFolder, existenceTable, logSubsystem);
11163
+ continue;
11164
+ }
11124
11165
  if (!isSqliteBusy(err) || attempt === MAX_MIGRATION_RETRIES) {
11125
11166
  throw err;
11126
11167
  }
@@ -13478,7 +13519,7 @@ function runMigrations(nativeDb, db) {
13478
13519
  }
13479
13520
  reconcileJournal(nativeDb, migrationsFolder, "tasks", "sqlite");
13480
13521
  ensureColumns(nativeDb, "sessions", REQUIRED_SESSION_COLUMNS, "sqlite");
13481
- migrateWithRetry(db, migrationsFolder);
13522
+ migrateWithRetry(db, migrationsFolder, nativeDb, "tasks", "sqlite");
13482
13523
  ensureColumns(nativeDb, "tasks", REQUIRED_TASK_COLUMNS, "sqlite");
13483
13524
  }
13484
13525
  function closeDb() {
@@ -13604,7 +13645,7 @@ function runBrainMigrations(nativeDb, db) {
13604
13645
  createSafetyBackup(_dbPath2);
13605
13646
  }
13606
13647
  reconcileJournal(nativeDb, migrationsFolder, "brain_decisions", "brain");
13607
- migrateWithRetry(db, migrationsFolder);
13648
+ migrateWithRetry(db, migrationsFolder, nativeDb, "brain_decisions", "brain");
13608
13649
  }
13609
13650
  function loadBrainVecExtension(nativeDb) {
13610
13651
  try {
@@ -34416,9 +34457,15 @@ async function addTask(options, cwd, accessor) {
34416
34457
  if (lifecycleMode === "strict") {
34417
34458
  throw new CleoError(
34418
34459
  6 /* VALIDATION_ERROR */,
34419
- 'Tasks must have a parent (epic or task) in strict mode. Use --parent <epicId> or set lifecycle.mode to "advisory".',
34460
+ 'Tasks must have a parent (epic or task) in strict mode. Use --parent <epicId>, --type epic for a root-level epic, or set lifecycle.mode to "advisory".',
34420
34461
  {
34421
- fix: 'cleo add "Task title" --parent T### --acceptance "AC1|AC2|AC3"'
34462
+ fix: 'cleo add "Task title" --parent T### --acceptance "AC1|AC2|AC3"',
34463
+ alternatives: [
34464
+ {
34465
+ action: "Create as epic",
34466
+ command: 'cleo add "Epic title" --type epic --priority high'
34467
+ }
34468
+ ]
34422
34469
  }
34423
34470
  );
34424
34471
  }
@@ -74007,6 +74054,57 @@ async function initProject(opts = {}) {
74007
74054
  ".cleo/ was found in root .gitignore and has been removed. CLEO uses .cleo/.gitignore for selective tracking."
74008
74055
  );
74009
74056
  }
74057
+ try {
74058
+ const cantDir = join105(cleoDir, "cant");
74059
+ const cantAgentsDir = join105(cantDir, "agents");
74060
+ const hasCantFiles = existsSync106(cantDir) && readdirSync36(cantDir, { recursive: true }).some(
74061
+ (f2) => typeof f2 === "string" && f2.endsWith(".cant")
74062
+ );
74063
+ if (!hasCantFiles) {
74064
+ let starterBundleSrc = null;
74065
+ try {
74066
+ const { createRequire: createRequire13 } = await import("node:module");
74067
+ const req = createRequire13(import.meta.url);
74068
+ const cleoOsPkgMain = req.resolve("@cleocode/cleo-os/package.json");
74069
+ const cleoOsPkgRoot = dirname21(cleoOsPkgMain);
74070
+ const candidate = join105(cleoOsPkgRoot, "starter-bundle");
74071
+ if (existsSync106(candidate)) {
74072
+ starterBundleSrc = candidate;
74073
+ }
74074
+ } catch {
74075
+ }
74076
+ if (!starterBundleSrc) {
74077
+ const packageRoot = getPackageRoot();
74078
+ const fallbacks = [
74079
+ join105(packageRoot, "..", "cleo-os", "starter-bundle"),
74080
+ join105(packageRoot, "..", "..", "packages", "cleo-os", "starter-bundle")
74081
+ ];
74082
+ starterBundleSrc = fallbacks.find((p2) => existsSync106(p2)) ?? null;
74083
+ }
74084
+ if (starterBundleSrc) {
74085
+ await mkdir16(cantDir, { recursive: true });
74086
+ await mkdir16(cantAgentsDir, { recursive: true });
74087
+ const teamSrc = join105(starterBundleSrc, "team.cant");
74088
+ const teamDst = join105(cantDir, "team.cant");
74089
+ if (existsSync106(teamSrc) && !existsSync106(teamDst)) {
74090
+ await copyFile4(teamSrc, teamDst);
74091
+ }
74092
+ const agentsSrc = join105(starterBundleSrc, "agents");
74093
+ if (existsSync106(agentsSrc)) {
74094
+ const agentFiles = readdirSync36(agentsSrc).filter((f2) => f2.endsWith(".cant"));
74095
+ for (const agentFile of agentFiles) {
74096
+ const dst = join105(cantAgentsDir, agentFile);
74097
+ if (!existsSync106(dst)) {
74098
+ await copyFile4(join105(agentsSrc, agentFile), dst);
74099
+ }
74100
+ }
74101
+ }
74102
+ created.push("starter-bundle: team + agent .cant files deployed to .cleo/cant/");
74103
+ }
74104
+ }
74105
+ } catch (err) {
74106
+ warnings.push(`Starter bundle deploy: ${err instanceof Error ? err.message : String(err)}`);
74107
+ }
74010
74108
  if (opts.installSeedAgents) {
74011
74109
  try {
74012
74110
  const seedDir = await resolveSeedAgentsDir();
@@ -100331,7 +100429,7 @@ var init_normalizer = __esm({
100331
100429
  });
100332
100430
 
100333
100431
  // packages/cleo/src/cli/renderers/colors.ts
100334
- function ansi(code) {
100432
+ function ansi2(code) {
100335
100433
  return colorsEnabled ? code : "";
100336
100434
  }
100337
100435
  function statusSymbol(status) {
@@ -100424,15 +100522,15 @@ var init_colors = __esm({
100424
100522
  if (lang === "C" || lang === "POSIX") return false;
100425
100523
  return lang.includes("UTF") || process.platform === "darwin";
100426
100524
  })();
100427
- BOLD = ansi("\x1B[1m");
100428
- DIM = ansi("\x1B[2m");
100429
- NC = ansi("\x1B[0m");
100430
- RED = ansi("\x1B[0;31m");
100431
- GREEN = ansi("\x1B[0;32m");
100432
- YELLOW = ansi("\x1B[1;33m");
100433
- BLUE = ansi("\x1B[0;34m");
100434
- MAGENTA = ansi("\x1B[0;35m");
100435
- CYAN = ansi("\x1B[0;36m");
100525
+ BOLD = ansi2("\x1B[1m");
100526
+ DIM = ansi2("\x1B[2m");
100527
+ NC = ansi2("\x1B[0m");
100528
+ RED = ansi2("\x1B[0;31m");
100529
+ GREEN = ansi2("\x1B[0;32m");
100530
+ YELLOW = ansi2("\x1B[1;33m");
100531
+ BLUE = ansi2("\x1B[0;34m");
100532
+ MAGENTA = ansi2("\x1B[0;35m");
100533
+ CYAN = ansi2("\x1B[0;36m");
100436
100534
  BOX = unicodeEnabled ? {
100437
100535
  tl: "\u256D",
100438
100536
  tr: "\u256E",
@@ -111593,6 +111691,12 @@ async function orchestrateClassify(request, context, projectRoot) {
111593
111691
  };
111594
111692
  }
111595
111693
  }
111694
+ function evictFanoutManifest() {
111695
+ while (fanoutManifestStore.size > FANOUT_MANIFEST_MAX_SIZE) {
111696
+ const oldest = fanoutManifestStore.keys().next().value;
111697
+ if (oldest !== void 0) fanoutManifestStore.delete(oldest);
111698
+ }
111699
+ }
111596
111700
  async function orchestrateFanout(items, projectRoot) {
111597
111701
  const manifestEntryId = `fanout-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
111598
111702
  try {
@@ -111637,6 +111741,7 @@ async function orchestrateFanout(items, projectRoot) {
111637
111741
  results,
111638
111742
  completedAt: (/* @__PURE__ */ new Date()).toISOString()
111639
111743
  });
111744
+ evictFanoutManifest();
111640
111745
  return {
111641
111746
  success: true,
111642
111747
  data: {
@@ -111738,7 +111843,7 @@ async function orchestrateAnalyzeParallelSafety(taskIds, projectRoot) {
111738
111843
  };
111739
111844
  }
111740
111845
  }
111741
- var OrchestrateHandler, fanoutManifestStore;
111846
+ var OrchestrateHandler, FANOUT_MANIFEST_MAX_SIZE, fanoutManifestStore;
111742
111847
  var init_orchestrate2 = __esm({
111743
111848
  "packages/cleo/src/dispatch/domains/orchestrate.ts"() {
111744
111849
  "use strict";
@@ -112222,6 +112327,7 @@ var init_orchestrate2 = __esm({
112222
112327
  };
112223
112328
  }
112224
112329
  };
112330
+ FANOUT_MANIFEST_MAX_SIZE = 64;
112225
112331
  fanoutManifestStore = /* @__PURE__ */ new Map();
112226
112332
  }
112227
112333
  });
@@ -116140,11 +116246,11 @@ var CLIError = class extends Error {
116140
116246
  function parseRawArgs(args = [], opts = {}) {
116141
116247
  const booleans = new Set(opts.boolean || []);
116142
116248
  const strings = new Set(opts.string || []);
116143
- const aliasMap = opts.alias || {};
116249
+ const aliasMap2 = opts.alias || {};
116144
116250
  const defaults = opts.default || {};
116145
116251
  const aliasToMain = /* @__PURE__ */ new Map();
116146
116252
  const mainToAliases = /* @__PURE__ */ new Map();
116147
- for (const [key, value] of Object.entries(aliasMap)) {
116253
+ for (const [key, value] of Object.entries(aliasMap2)) {
116148
116254
  const targets = value;
116149
116255
  for (const target of targets) {
116150
116256
  aliasToMain.set(key, target);
@@ -116165,8 +116271,8 @@ function parseRawArgs(args = [], opts = {}) {
116165
116271
  const allOptions = /* @__PURE__ */ new Set([
116166
116272
  ...booleans,
116167
116273
  ...strings,
116168
- ...Object.keys(aliasMap),
116169
- ...Object.values(aliasMap).flat(),
116274
+ ...Object.keys(aliasMap2),
116275
+ ...Object.values(aliasMap2).flat(),
116170
116276
  ...Object.keys(defaults)
116171
116277
  ]);
116172
116278
  for (const name2 of allOptions) if (!options[name2]) options[name2] = {
@@ -116582,6 +116688,237 @@ function camelToKebab2(str) {
116582
116688
  init_field_context();
116583
116689
  init_format_context();
116584
116690
 
116691
+ // packages/cleo/src/cli/help-renderer.ts
116692
+ var noColor2 = (() => {
116693
+ const env = globalThis.process?.env ?? {};
116694
+ return env.NO_COLOR === "1" || env.TERM === "dumb" || env.TEST || env.CI;
116695
+ })();
116696
+ var ansi = (code, reset = 39) => (t) => noColor2 ? t : `\x1B[${code}m${t}\x1B[${reset}m`;
116697
+ var bold2 = ansi(1, 22);
116698
+ var cyan2 = ansi(36);
116699
+ var gray2 = ansi(90);
116700
+ var underline2 = ansi(4, 24);
116701
+ var IMPLICIT_ALIASES = {
116702
+ tags: "labels"
116703
+ };
116704
+ var NATIVE_COMMAND_DESCS = {
116705
+ version: "Display CLEO version",
116706
+ code: "Code analysis via tree-sitter AST"
116707
+ };
116708
+ var COMMAND_GROUPS = [
116709
+ {
116710
+ name: "Task Management",
116711
+ commands: [
116712
+ "add",
116713
+ "show",
116714
+ "find",
116715
+ "list",
116716
+ "update",
116717
+ "complete",
116718
+ "delete",
116719
+ "start",
116720
+ "stop",
116721
+ "current",
116722
+ "next",
116723
+ "exists",
116724
+ "bug"
116725
+ ]
116726
+ },
116727
+ {
116728
+ name: "Task Organization",
116729
+ commands: [
116730
+ "archive",
116731
+ "labels",
116732
+ "promote",
116733
+ "relates",
116734
+ "reorder",
116735
+ "reparent",
116736
+ "deps",
116737
+ "tree",
116738
+ "blockers"
116739
+ ]
116740
+ },
116741
+ {
116742
+ name: "Sessions & Planning",
116743
+ commands: ["session", "briefing", "dash", "plan", "safestop", "context"]
116744
+ },
116745
+ {
116746
+ name: "Phases & Lifecycle",
116747
+ commands: ["phase", "phases", "lifecycle", "release", "roadmap"]
116748
+ },
116749
+ {
116750
+ name: "Memory & Notes",
116751
+ commands: ["memory", "brain", "observe", "refresh-memory", "sticky", "reason"]
116752
+ },
116753
+ {
116754
+ name: "Analysis & Stats",
116755
+ commands: ["analyze", "stats", "history", "archive-stats"]
116756
+ },
116757
+ {
116758
+ name: "Validation & Compliance",
116759
+ commands: [
116760
+ "check",
116761
+ "validate",
116762
+ "verify",
116763
+ "testing",
116764
+ "compliance",
116765
+ "implementation",
116766
+ "specification",
116767
+ "consensus",
116768
+ "contribution",
116769
+ "decomposition",
116770
+ "backfill"
116771
+ ]
116772
+ },
116773
+ {
116774
+ name: "Code & Documentation",
116775
+ commands: ["code", "docs", "detect-drift", "map"]
116776
+ },
116777
+ {
116778
+ name: "Research & Orchestration",
116779
+ commands: ["research", "orchestrate"]
116780
+ },
116781
+ {
116782
+ name: "Import / Export",
116783
+ commands: ["export", "import", "export-tasks", "import-tasks", "snapshot", "inject"]
116784
+ },
116785
+ {
116786
+ name: "Collaboration",
116787
+ commands: ["nexus", "remote", "push", "pull", "checkpoint"]
116788
+ },
116789
+ {
116790
+ name: "Agents",
116791
+ commands: ["agent", "grade"]
116792
+ },
116793
+ {
116794
+ name: "System & Admin",
116795
+ commands: [
116796
+ "version",
116797
+ "init",
116798
+ "config",
116799
+ "env",
116800
+ "admin",
116801
+ "doctor",
116802
+ "upgrade",
116803
+ "self-update",
116804
+ "commands",
116805
+ "ops",
116806
+ "schema",
116807
+ "log",
116808
+ "sequence",
116809
+ "adr",
116810
+ "cant",
116811
+ "token",
116812
+ "otel",
116813
+ "migrate",
116814
+ "detect",
116815
+ "generate-changelog",
116816
+ "issue",
116817
+ "skills",
116818
+ "web",
116819
+ "backup",
116820
+ "restore"
116821
+ ]
116822
+ }
116823
+ ];
116824
+ function buildAliasMap(shims) {
116825
+ const map2 = /* @__PURE__ */ new Map();
116826
+ for (const shim of shims) {
116827
+ for (const alias of shim._aliases) {
116828
+ map2.set(alias, shim._name);
116829
+ }
116830
+ }
116831
+ for (const [alias, primary] of Object.entries(IMPLICIT_ALIASES)) {
116832
+ map2.set(alias, primary);
116833
+ }
116834
+ return map2;
116835
+ }
116836
+ function getShortDescription(desc7) {
116837
+ if (!desc7) return "";
116838
+ const match = desc7.match(/^Description:\s*(.+)/);
116839
+ if (match) return match[1].trim();
116840
+ const firstLine = desc7.split("\n").find((l) => l.trim().length > 0);
116841
+ return firstLine?.trim() ?? desc7.trim();
116842
+ }
116843
+ function renderGroupedHelp(version2, shims, aliasMap2) {
116844
+ const descMap = /* @__PURE__ */ new Map();
116845
+ for (const shim of shims) {
116846
+ descMap.set(shim._name, getShortDescription(shim._description));
116847
+ }
116848
+ for (const [name2, desc7] of Object.entries(NATIVE_COMMAND_DESCS)) {
116849
+ if (!descMap.has(name2)) {
116850
+ descMap.set(name2, desc7);
116851
+ }
116852
+ }
116853
+ const cmdAliases = /* @__PURE__ */ new Map();
116854
+ for (const [alias, primary] of aliasMap2) {
116855
+ const existing = cmdAliases.get(primary) ?? [];
116856
+ existing.push(alias);
116857
+ cmdAliases.set(primary, existing);
116858
+ }
116859
+ let maxCmdWidth = 0;
116860
+ const allGroupedCmds = COMMAND_GROUPS.flatMap((g2) => g2.commands);
116861
+ const allCmds = [.../* @__PURE__ */ new Set([...allGroupedCmds, ...shims.map((s3) => s3._name), "version"])];
116862
+ for (const cmd of allCmds) {
116863
+ if (!descMap.has(cmd) || aliasMap2.has(cmd)) continue;
116864
+ const aliases = cmdAliases.get(cmd);
116865
+ const display = aliases && aliases.length > 0 ? `${cmd} (${aliases.join(", ")})` : cmd;
116866
+ if (display.length > maxCmdWidth) maxCmdWidth = display.length;
116867
+ }
116868
+ const lines = [];
116869
+ lines.push(gray2(`CLEO V2 - Task management for AI coding agents (cleo v${version2})`));
116870
+ lines.push("");
116871
+ lines.push(`${underline2(bold2("USAGE"))} ${cyan2("cleo <command> [OPTIONS]")}`);
116872
+ lines.push("");
116873
+ const rendered = /* @__PURE__ */ new Set();
116874
+ for (const group of COMMAND_GROUPS) {
116875
+ const groupLines = [];
116876
+ for (const cmd of group.commands) {
116877
+ if (!descMap.has(cmd)) continue;
116878
+ rendered.add(cmd);
116879
+ const aliases = cmdAliases.get(cmd);
116880
+ const display = aliases && aliases.length > 0 ? `${cmd} (${aliases.join(", ")})` : cmd;
116881
+ const desc7 = descMap.get(cmd) ?? "";
116882
+ groupLines.push(` ${cyan2(display.padEnd(maxCmdWidth + 2))}${desc7}`);
116883
+ }
116884
+ if (groupLines.length > 0) {
116885
+ lines.push(underline2(bold2(group.name.toUpperCase())));
116886
+ lines.push(...groupLines);
116887
+ lines.push("");
116888
+ }
116889
+ }
116890
+ const ungrouped = [];
116891
+ for (const shim of shims) {
116892
+ if (!rendered.has(shim._name) && !aliasMap2.has(shim._name)) {
116893
+ ungrouped.push(shim._name);
116894
+ }
116895
+ }
116896
+ if (ungrouped.length > 0) {
116897
+ lines.push(underline2(bold2("OTHER")));
116898
+ for (const cmd of ungrouped) {
116899
+ const aliases = cmdAliases.get(cmd);
116900
+ const display = aliases && aliases.length > 0 ? `${cmd} (${aliases.join(", ")})` : cmd;
116901
+ const desc7 = descMap.get(cmd) ?? "";
116902
+ lines.push(` ${cyan2(display.padEnd(maxCmdWidth + 2))}${desc7}`);
116903
+ }
116904
+ lines.push("");
116905
+ }
116906
+ lines.push(`Use ${cyan2("cleo <command> --help")} for more information about a command.`);
116907
+ return lines.join("\n");
116908
+ }
116909
+ function createCustomShowUsage(version2, shims, aliasMap2) {
116910
+ return async (cmd, parent) => {
116911
+ if (!parent) {
116912
+ const meta3 = await (typeof cmd.meta === "function" ? cmd.meta() : cmd.meta);
116913
+ if (meta3?.name === "cleo") {
116914
+ console.log(renderGroupedHelp(version2, shims, aliasMap2) + "\n");
116915
+ return;
116916
+ }
116917
+ }
116918
+ await showUsage(cmd, parent);
116919
+ };
116920
+ }
116921
+
116585
116922
  // packages/cleo/src/cli/middleware/output-format.ts
116586
116923
  import { resolveOutputFormat } from "@cleocode/lafs";
116587
116924
  function resolveFormat2(opts, defaults) {
@@ -118220,6 +118557,786 @@ Task ${taskId} reassigned to you by ${active.agentId}. Run: cleo show ${taskId}
118220
118557
  { command: "agent health" }
118221
118558
  );
118222
118559
  });
118560
+ agent.command("install <path>").description("Install an agent from a .cantz archive or agent directory").option("--global", "Install to global tier (~/.local/share/cleo/cant/agents/)").action(async (sourcePath, opts) => {
118561
+ try {
118562
+ const { existsSync: existsSync131, mkdirSync: mkdirSync31, cpSync, readFileSync: readFileSync101, rmSync: rmSync3, statSync: statSync22 } = await import("node:fs");
118563
+ const { join: join131, basename: basename19, resolve: resolve16 } = await import("node:path");
118564
+ const { homedir: homedir7 } = await import("node:os");
118565
+ const { tmpdir: tmpdir3 } = await import("node:os");
118566
+ const resolvedPath = resolve16(sourcePath);
118567
+ if (!existsSync131(resolvedPath)) {
118568
+ cliOutput(
118569
+ {
118570
+ success: false,
118571
+ error: {
118572
+ code: "E_NOT_FOUND",
118573
+ message: `Path does not exist: ${resolvedPath}`
118574
+ }
118575
+ },
118576
+ { command: "agent install" }
118577
+ );
118578
+ process.exitCode = 4;
118579
+ return;
118580
+ }
118581
+ let agentDir;
118582
+ let agentName;
118583
+ let tempDir = null;
118584
+ const isCantzArchive = resolvedPath.endsWith(".cantz") && statSync22(resolvedPath).isFile();
118585
+ if (isCantzArchive) {
118586
+ const { execFileSync: execFileSync19 } = await import("node:child_process");
118587
+ tempDir = join131(tmpdir3(), `cleo-agent-install-${Date.now()}`);
118588
+ mkdirSync31(tempDir, { recursive: true });
118589
+ try {
118590
+ execFileSync19("unzip", ["-o", "-q", resolvedPath, "-d", tempDir], {
118591
+ encoding: "utf-8",
118592
+ timeout: 3e4
118593
+ });
118594
+ } catch (unzipErr) {
118595
+ if (tempDir) rmSync3(tempDir, { recursive: true, force: true });
118596
+ cliOutput(
118597
+ {
118598
+ success: false,
118599
+ error: {
118600
+ code: "E_VALIDATION",
118601
+ message: `Failed to extract .cantz archive: ${String(unzipErr)}`
118602
+ }
118603
+ },
118604
+ { command: "agent install" }
118605
+ );
118606
+ process.exitCode = 6;
118607
+ return;
118608
+ }
118609
+ const { readdirSync: readdirSync42 } = await import("node:fs");
118610
+ const topLevel = readdirSync42(tempDir).filter((entry) => {
118611
+ const entryPath = join131(tempDir, entry);
118612
+ return statSync22(entryPath).isDirectory();
118613
+ });
118614
+ if (topLevel.length !== 1) {
118615
+ if (tempDir) rmSync3(tempDir, { recursive: true, force: true });
118616
+ cliOutput(
118617
+ {
118618
+ success: false,
118619
+ error: {
118620
+ code: "E_VALIDATION",
118621
+ message: `Archive must contain exactly one top-level directory, found ${topLevel.length}`
118622
+ }
118623
+ },
118624
+ { command: "agent install" }
118625
+ );
118626
+ process.exitCode = 6;
118627
+ return;
118628
+ }
118629
+ agentName = topLevel[0];
118630
+ agentDir = join131(tempDir, agentName);
118631
+ } else if (statSync22(resolvedPath).isDirectory()) {
118632
+ agentDir = resolvedPath;
118633
+ agentName = basename19(resolvedPath);
118634
+ } else {
118635
+ cliOutput(
118636
+ {
118637
+ success: false,
118638
+ error: {
118639
+ code: "E_VALIDATION",
118640
+ message: `Path must be a .cantz file or a directory: ${resolvedPath}`
118641
+ }
118642
+ },
118643
+ { command: "agent install" }
118644
+ );
118645
+ process.exitCode = 6;
118646
+ return;
118647
+ }
118648
+ const personaPath = join131(agentDir, "persona.cant");
118649
+ if (!existsSync131(personaPath)) {
118650
+ if (tempDir) rmSync3(tempDir, { recursive: true, force: true });
118651
+ cliOutput(
118652
+ {
118653
+ success: false,
118654
+ error: {
118655
+ code: "E_VALIDATION",
118656
+ message: `Agent directory must contain persona.cant: ${personaPath}`
118657
+ }
118658
+ },
118659
+ { command: "agent install" }
118660
+ );
118661
+ process.exitCode = 6;
118662
+ return;
118663
+ }
118664
+ const isGlobal = opts["global"] === true;
118665
+ let targetRoot;
118666
+ if (isGlobal) {
118667
+ const home = homedir7();
118668
+ const xdgData = process.env["XDG_DATA_HOME"] ?? join131(home, ".local", "share");
118669
+ targetRoot = join131(xdgData, "cleo", "cant", "agents");
118670
+ } else {
118671
+ targetRoot = join131(process.cwd(), ".cleo", "cant", "agents");
118672
+ }
118673
+ const targetDir = join131(targetRoot, agentName);
118674
+ mkdirSync31(targetRoot, { recursive: true });
118675
+ cpSync(agentDir, targetDir, { recursive: true, force: true });
118676
+ if (tempDir) {
118677
+ rmSync3(tempDir, { recursive: true, force: true });
118678
+ }
118679
+ let registered = false;
118680
+ try {
118681
+ const persona = readFileSync101(join131(targetDir, "persona.cant"), "utf-8");
118682
+ const descMatch = persona.match(/description:\s*"([^"]+)"/);
118683
+ const displayName = descMatch?.[1] ?? agentName;
118684
+ const { AgentRegistryAccessor: AgentRegistryAccessor2, getDb: getDb4 } = await Promise.resolve().then(() => (init_internal(), internal_exports));
118685
+ await getDb4();
118686
+ const registry2 = new AgentRegistryAccessor2(process.cwd());
118687
+ const existing = await registry2.get(agentName);
118688
+ if (!existing) {
118689
+ await registry2.register({
118690
+ agentId: agentName,
118691
+ displayName,
118692
+ apiKey: "local-installed",
118693
+ apiBaseUrl: "local",
118694
+ classification: "specialist",
118695
+ privacyTier: "private",
118696
+ capabilities: [],
118697
+ skills: [],
118698
+ transportType: "http",
118699
+ transportConfig: {},
118700
+ isActive: false
118701
+ });
118702
+ registered = true;
118703
+ }
118704
+ } catch {
118705
+ }
118706
+ cliOutput(
118707
+ {
118708
+ success: true,
118709
+ data: {
118710
+ agent: agentName,
118711
+ tier: isGlobal ? "global" : "project",
118712
+ path: targetDir,
118713
+ registered
118714
+ }
118715
+ },
118716
+ { command: "agent install" }
118717
+ );
118718
+ } catch (err) {
118719
+ cliOutput(
118720
+ { success: false, error: { code: "E_INSTALL", message: String(err) } },
118721
+ { command: "agent install" }
118722
+ );
118723
+ process.exitCode = 1;
118724
+ }
118725
+ });
118726
+ agent.command("pack <dir>").description("Package an agent directory as a .cantz archive").action(async (dir) => {
118727
+ try {
118728
+ const { existsSync: existsSync131, statSync: statSync22 } = await import("node:fs");
118729
+ const { resolve: resolve16, basename: basename19, dirname: dirname29 } = await import("node:path");
118730
+ const { execFileSync: execFileSync19 } = await import("node:child_process");
118731
+ const resolvedDir = resolve16(dir);
118732
+ if (!existsSync131(resolvedDir) || !statSync22(resolvedDir).isDirectory()) {
118733
+ cliOutput(
118734
+ {
118735
+ success: false,
118736
+ error: {
118737
+ code: "E_NOT_FOUND",
118738
+ message: `Directory does not exist: ${resolvedDir}`
118739
+ }
118740
+ },
118741
+ { command: "agent pack" }
118742
+ );
118743
+ process.exitCode = 4;
118744
+ return;
118745
+ }
118746
+ const { join: join131 } = await import("node:path");
118747
+ const personaPath = join131(resolvedDir, "persona.cant");
118748
+ if (!existsSync131(personaPath)) {
118749
+ cliOutput(
118750
+ {
118751
+ success: false,
118752
+ error: {
118753
+ code: "E_VALIDATION",
118754
+ message: `Agent directory must contain persona.cant: ${personaPath}`
118755
+ }
118756
+ },
118757
+ { command: "agent pack" }
118758
+ );
118759
+ process.exitCode = 6;
118760
+ return;
118761
+ }
118762
+ const agentName = basename19(resolvedDir);
118763
+ const archiveName = `${agentName}.cantz`;
118764
+ const archivePath = resolve16(archiveName);
118765
+ const parentDir = dirname29(resolvedDir);
118766
+ try {
118767
+ execFileSync19("zip", ["-r", archivePath, agentName], {
118768
+ cwd: parentDir,
118769
+ encoding: "utf-8",
118770
+ timeout: 3e4
118771
+ });
118772
+ } catch (zipErr) {
118773
+ cliOutput(
118774
+ {
118775
+ success: false,
118776
+ error: {
118777
+ code: "E_PACK",
118778
+ message: `Failed to create archive: ${String(zipErr)}`
118779
+ }
118780
+ },
118781
+ { command: "agent pack" }
118782
+ );
118783
+ process.exitCode = 1;
118784
+ return;
118785
+ }
118786
+ const archiveStats = statSync22(archivePath);
118787
+ const { readdirSync: readdirSync42 } = await import("node:fs");
118788
+ let fileCount = 0;
118789
+ const countFiles2 = (dirPath) => {
118790
+ const entries = readdirSync42(dirPath, { withFileTypes: true });
118791
+ for (const entry of entries) {
118792
+ if (entry.isFile()) {
118793
+ fileCount++;
118794
+ } else if (entry.isDirectory()) {
118795
+ countFiles2(join131(dirPath, entry.name));
118796
+ }
118797
+ }
118798
+ };
118799
+ countFiles2(resolvedDir);
118800
+ cliOutput(
118801
+ {
118802
+ success: true,
118803
+ data: {
118804
+ archive: archivePath,
118805
+ agent: agentName,
118806
+ files: fileCount,
118807
+ size: archiveStats.size
118808
+ }
118809
+ },
118810
+ { command: "agent pack" }
118811
+ );
118812
+ } catch (err) {
118813
+ cliOutput(
118814
+ { success: false, error: { code: "E_PACK", message: String(err) } },
118815
+ { command: "agent pack" }
118816
+ );
118817
+ process.exitCode = 1;
118818
+ }
118819
+ });
118820
+ agent.command("create").description("Scaffold a new agent package with persona.cant and manifest.json").requiredOption("--name <name>", "Agent name (kebab-case)").requiredOption("--role <role>", "Agent role: orchestrator, lead, worker, or docs-worker").option("--tier <tier>", "Agent tier: low, mid, or high (defaults based on role)").option("--team <teamName>", "Team this agent belongs to").option("--domain <description>", "Domain description for file permissions and context").option("--global", "Create in global tier (~/.local/share/cleo/cant/agents/)").option("--seed-brain", "Create expertise/mental-model-seed.md and seed a BRAIN observation").option("--parent <parentAgent>", "Parent agent name in the hierarchy").action(async (opts) => {
118821
+ try {
118822
+ const { existsSync: existsSync131, mkdirSync: mkdirSync31, writeFileSync: writeFileSync25 } = await import("node:fs");
118823
+ const { join: join131 } = await import("node:path");
118824
+ const { homedir: homedir7 } = await import("node:os");
118825
+ const name2 = opts["name"];
118826
+ const role = opts["role"];
118827
+ const tier = opts["tier"] ?? inferTierFromRole(role);
118828
+ const team = opts["team"];
118829
+ const domain2 = opts["domain"];
118830
+ const isGlobal = opts["global"] === true;
118831
+ const seedBrain = opts["seedBrain"] === true;
118832
+ const parent = opts["parent"];
118833
+ const validRoles = ["orchestrator", "lead", "worker", "docs-worker"];
118834
+ if (!validRoles.includes(role)) {
118835
+ cliOutput(
118836
+ {
118837
+ success: false,
118838
+ error: {
118839
+ code: "E_VALIDATION",
118840
+ message: `Invalid role "${role}". Must be one of: ${validRoles.join(", ")}`,
118841
+ fix: `cleo agent create --name ${name2} --role worker`
118842
+ }
118843
+ },
118844
+ { command: "agent create" }
118845
+ );
118846
+ process.exitCode = 6;
118847
+ return;
118848
+ }
118849
+ const validTiers = ["low", "mid", "high"];
118850
+ if (!validTiers.includes(tier)) {
118851
+ cliOutput(
118852
+ {
118853
+ success: false,
118854
+ error: {
118855
+ code: "E_VALIDATION",
118856
+ message: `Invalid tier "${tier}". Must be one of: ${validTiers.join(", ")}`,
118857
+ fix: `cleo agent create --name ${name2} --role ${role} --tier mid`
118858
+ }
118859
+ },
118860
+ { command: "agent create" }
118861
+ );
118862
+ process.exitCode = 6;
118863
+ return;
118864
+ }
118865
+ if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(name2)) {
118866
+ cliOutput(
118867
+ {
118868
+ success: false,
118869
+ error: {
118870
+ code: "E_VALIDATION",
118871
+ message: `Agent name must be kebab-case: "${name2}"`,
118872
+ fix: "Use lowercase letters, numbers, and hyphens. Must start with a letter."
118873
+ }
118874
+ },
118875
+ { command: "agent create" }
118876
+ );
118877
+ process.exitCode = 6;
118878
+ return;
118879
+ }
118880
+ let targetRoot;
118881
+ if (isGlobal) {
118882
+ const home = homedir7();
118883
+ const xdgData = process.env["XDG_DATA_HOME"] ?? join131(home, ".local", "share");
118884
+ targetRoot = join131(xdgData, "cleo", "cant", "agents");
118885
+ } else {
118886
+ targetRoot = join131(process.cwd(), ".cleo", "cant", "agents");
118887
+ }
118888
+ const agentDir = join131(targetRoot, name2);
118889
+ if (existsSync131(agentDir)) {
118890
+ cliOutput(
118891
+ {
118892
+ success: false,
118893
+ error: {
118894
+ code: "E_VALIDATION",
118895
+ message: `Agent directory already exists: ${agentDir}`,
118896
+ fix: "Remove the existing directory or choose a different name."
118897
+ }
118898
+ },
118899
+ { command: "agent create" }
118900
+ );
118901
+ process.exitCode = 6;
118902
+ return;
118903
+ }
118904
+ mkdirSync31(agentDir, { recursive: true });
118905
+ const personaContent = generatePersonaCant({
118906
+ name: name2,
118907
+ role,
118908
+ tier,
118909
+ team,
118910
+ domain: domain2,
118911
+ parent
118912
+ });
118913
+ writeFileSync25(join131(agentDir, "persona.cant"), personaContent, "utf-8");
118914
+ const manifest = generateManifest2({ name: name2, role, tier, domain: domain2 });
118915
+ writeFileSync25(
118916
+ join131(agentDir, "manifest.json"),
118917
+ `${JSON.stringify(manifest, null, 2)}
118918
+ `,
118919
+ "utf-8"
118920
+ );
118921
+ const createdFiles = [
118922
+ join131(agentDir, "persona.cant"),
118923
+ join131(agentDir, "manifest.json")
118924
+ ];
118925
+ if (team) {
118926
+ const teamConfigContent = generateTeamConfig(name2, role, team);
118927
+ writeFileSync25(join131(agentDir, "team-config.cant"), teamConfigContent, "utf-8");
118928
+ createdFiles.push(join131(agentDir, "team-config.cant"));
118929
+ }
118930
+ if (seedBrain) {
118931
+ const expertiseDir = join131(agentDir, "expertise");
118932
+ mkdirSync31(expertiseDir, { recursive: true });
118933
+ const seedContent = generateMentalModelSeed(name2, role, domain2);
118934
+ writeFileSync25(join131(expertiseDir, "mental-model-seed.md"), seedContent, "utf-8");
118935
+ createdFiles.push(join131(expertiseDir, "mental-model-seed.md"));
118936
+ try {
118937
+ const { execFile: execFile9 } = await import("node:child_process");
118938
+ const { promisify: promisify9 } = await import("node:util");
118939
+ const execFileAsync6 = promisify9(execFile9);
118940
+ await execFileAsync6(
118941
+ "cleo",
118942
+ [
118943
+ "observe",
118944
+ `Agent ${name2} created with role ${role}`,
118945
+ "--title",
118946
+ `Agent creation: ${name2}`
118947
+ ],
118948
+ { encoding: "utf-8", timeout: 1e4 }
118949
+ ).catch(() => {
118950
+ });
118951
+ } catch {
118952
+ }
118953
+ }
118954
+ let registered = false;
118955
+ try {
118956
+ const { AgentRegistryAccessor: AgentRegistryAccessor2, getDb: getDb4 } = await Promise.resolve().then(() => (init_internal(), internal_exports));
118957
+ await getDb4();
118958
+ const registry2 = new AgentRegistryAccessor2(process.cwd());
118959
+ const existing = await registry2.get(name2);
118960
+ if (!existing) {
118961
+ const descMatch = personaContent.match(/description:\s*"([^"]+)"/);
118962
+ const displayName = descMatch?.[1] ?? name2;
118963
+ await registry2.register({
118964
+ agentId: name2,
118965
+ displayName,
118966
+ apiKey: "local-created",
118967
+ apiBaseUrl: "local",
118968
+ classification: role,
118969
+ privacyTier: "private",
118970
+ capabilities: [],
118971
+ skills: [],
118972
+ transportType: "http",
118973
+ transportConfig: {},
118974
+ isActive: false
118975
+ });
118976
+ registered = true;
118977
+ }
118978
+ } catch {
118979
+ }
118980
+ cliOutput(
118981
+ {
118982
+ success: true,
118983
+ data: {
118984
+ agent: name2,
118985
+ role,
118986
+ tier,
118987
+ directory: agentDir,
118988
+ scope: isGlobal ? "global" : "project",
118989
+ files: createdFiles,
118990
+ registered,
118991
+ brainSeeded: seedBrain
118992
+ }
118993
+ },
118994
+ { command: "agent create" }
118995
+ );
118996
+ } catch (err) {
118997
+ cliOutput(
118998
+ { success: false, error: { code: "E_CREATE", message: String(err) } },
118999
+ { command: "agent create" }
119000
+ );
119001
+ process.exitCode = 1;
119002
+ }
119003
+ });
119004
+ }
119005
+ function inferTierFromRole(role) {
119006
+ if (role === "orchestrator") return "high";
119007
+ return "mid";
119008
+ }
119009
+ function generatePersonaCant(params) {
119010
+ const { name: name2, role, tier, team, domain: domain2, parent } = params;
119011
+ switch (role) {
119012
+ case "orchestrator":
119013
+ return generateOrchestratorPersona(name2, tier, team, parent);
119014
+ case "lead":
119015
+ return generateLeadPersona(name2, tier, team, domain2, parent);
119016
+ case "worker":
119017
+ return generateWorkerPersona(name2, tier, team, domain2, parent);
119018
+ case "docs-worker":
119019
+ return generateDocsWorkerPersona(name2, tier, team, domain2, parent);
119020
+ default:
119021
+ return generateWorkerPersona(name2, tier, team, domain2, parent);
119022
+ }
119023
+ }
119024
+ function generateOrchestratorPersona(name2, tier, team, parent) {
119025
+ const parentLine = parent ? `
119026
+ parent: ${parent}` : "";
119027
+ const teamComment = team ? `
119028
+ # Team: ${team}` : "";
119029
+ return `---
119030
+ kind: agent
119031
+ version: "1"
119032
+ ---
119033
+
119034
+ # ${name2} \u2014 orchestrator agent.${teamComment}
119035
+ # Coordinates the team, classifies work, dispatches to leads/workers.
119036
+
119037
+ agent ${name2}:
119038
+ role: orchestrator${parentLine}
119039
+ tier: ${tier}
119040
+ description: "Orchestrator agent. Reads task context, classifies work, dispatches to leads, and synthesizes results. Does not execute code \u2014 coordinates."
119041
+ consult-when: "Cross-team decisions, scope changes, human-in-the-loop escalation, or when a lead reports a blocking ambiguity"
119042
+
119043
+ context_sources:
119044
+ - source: decisions
119045
+ query: "recent architectural and project decisions"
119046
+ max_entries: 5
119047
+ - source: patterns
119048
+ query: "project conventions and established patterns"
119049
+ max_entries: 3
119050
+ on_overflow: escalate_tier
119051
+
119052
+ mental_model:
119053
+ scope: project
119054
+ max_tokens: 2000
119055
+ on_load:
119056
+ validate: true
119057
+
119058
+ permissions:
119059
+ tasks: read, write
119060
+ session: read, write
119061
+ memory: read, write
119062
+
119063
+ skills:
119064
+ - ct-cleo
119065
+ - ct-task-executor
119066
+
119067
+ tools:
119068
+ core: [Read, Grep, Glob]
119069
+ dispatch: [dispatch_worker, report_to_user]
119070
+
119071
+ on SessionStart:
119072
+ session "Read active tasks and recent decisions to build situational awareness"
119073
+ context: [active-tasks, memory-bridge, recent-decisions]
119074
+
119075
+ on TaskCompleted:
119076
+ if **the completed task unblocks downstream work**:
119077
+ session "Reassess task queue and dispatch next work"
119078
+ `;
119079
+ }
119080
+ function generateLeadPersona(name2, tier, team, domain2, parent) {
119081
+ const parentLine = parent ? `
119082
+ parent: ${parent}` : "\n parent: cleo-orchestrator";
119083
+ const teamComment = team ? `
119084
+ # Team: ${team}` : "";
119085
+ const domainDesc = domain2 ? ` Specializes in ${domain2}.` : "";
119086
+ return `---
119087
+ kind: agent
119088
+ version: "1"
119089
+ ---
119090
+
119091
+ # ${name2} \u2014 lead agent.${teamComment}
119092
+ # Decomposes tasks, reviews worker output, decides technical approach.
119093
+ # MUST NOT hold Edit/Write/Bash tools (TEAM-002 / ULTRAPLAN 10.3).
119094
+
119095
+ agent ${name2}:
119096
+ role: lead${parentLine}
119097
+ tier: ${tier}
119098
+ description: "Development lead.${domainDesc} Decomposes tasks into concrete implementation steps, reviews worker output, and decides technical approach. Does not write code directly."
119099
+ consult-when: "Implementation strategy, code architecture, refactoring direction, task decomposition, or when workers need clarification"
119100
+
119101
+ context_sources:
119102
+ - source: patterns
119103
+ query: "codebase conventions and architecture patterns"
119104
+ max_entries: 5
119105
+ - source: decisions
119106
+ query: "technical decisions affecting implementation"
119107
+ max_entries: 3
119108
+ on_overflow: escalate_tier
119109
+
119110
+ mental_model:
119111
+ scope: project
119112
+ max_tokens: 1000
119113
+ on_load:
119114
+ validate: true
119115
+
119116
+ permissions:
119117
+ files:
119118
+ read: ["**/*"]
119119
+
119120
+ skills:
119121
+ - ct-cleo
119122
+ - ct-dev-workflow
119123
+ - ct-task-executor
119124
+
119125
+ tools:
119126
+ core: [Read, Grep, Glob]
119127
+ dispatch: [dispatch_worker, report_to_orchestrator]
119128
+
119129
+ on SessionStart:
119130
+ session "Review current task assignments and worker availability"
119131
+ context: [active-tasks, memory-bridge]
119132
+
119133
+ on TaskCompleted:
119134
+ if **the completed task introduced new code**:
119135
+ session "Review worker output for quality and completeness before reporting to orchestrator"
119136
+ `;
119137
+ }
119138
+ function generateWorkerPersona(name2, tier, team, domain2, parent) {
119139
+ const parentLine = parent ? `
119140
+ parent: ${parent}` : "\n parent: dev-lead";
119141
+ const teamComment = team ? `
119142
+ # Team: ${team}` : "";
119143
+ const domainDesc = domain2 ? ` Specializes in ${domain2}.` : "";
119144
+ const writeGlobs = deriveWriteGlobs(domain2);
119145
+ return `---
119146
+ kind: agent
119147
+ version: "1"
119148
+ ---
119149
+
119150
+ # ${name2} \u2014 worker agent.${teamComment}
119151
+ # Executes code changes within declared file globs.
119152
+
119153
+ agent ${name2}:
119154
+ role: worker${parentLine}
119155
+ tier: ${tier}
119156
+ description: "Code worker.${domainDesc} Reads requirements, writes code, runs tests, and validates changes. Operates within declared file permission globs."
119157
+ consult-when: "Writing code, fixing bugs, running tests, formatting, or any file modification task"
119158
+
119159
+ context_sources:
119160
+ - source: patterns
119161
+ query: "coding conventions and testing patterns"
119162
+ max_entries: 5
119163
+ - source: learnings
119164
+ query: "past implementation mistakes and fixes"
119165
+ max_entries: 3
119166
+ on_overflow: escalate_tier
119167
+
119168
+ mental_model:
119169
+ scope: project
119170
+ max_tokens: 1000
119171
+ on_load:
119172
+ validate: true
119173
+
119174
+ permissions:
119175
+ files:
119176
+ write: ${JSON.stringify(writeGlobs)}
119177
+ read: ["**/*"]
119178
+ delete: ${JSON.stringify(writeGlobs)}
119179
+
119180
+ skills:
119181
+ - ct-cleo
119182
+ - ct-dev-workflow
119183
+ - ct-task-executor
119184
+
119185
+ tools:
119186
+ core: [Read, Edit, Write, Bash, Glob, Grep]
119187
+
119188
+ on SessionStart:
119189
+ session "Check assigned task and read relevant source files before starting work"
119190
+ context: [active-tasks, memory-bridge]
119191
+
119192
+ on PostToolUse:
119193
+ if tool.name == "Write" or tool.name == "Edit":
119194
+ session "Verify the change compiles and passes lint before proceeding"
119195
+ `;
119196
+ }
119197
+ function generateDocsWorkerPersona(name2, tier, team, domain2, parent) {
119198
+ const parentLine = parent ? `
119199
+ parent: ${parent}` : "\n parent: dev-lead";
119200
+ const teamComment = team ? `
119201
+ # Team: ${team}` : "";
119202
+ const domainDesc = domain2 ? ` Specializes in ${domain2} documentation.` : "";
119203
+ return `---
119204
+ kind: agent
119205
+ version: "1"
119206
+ ---
119207
+
119208
+ # ${name2} \u2014 documentation worker agent.${teamComment}
119209
+ # Writes and maintains documentation within declared globs.
119210
+
119211
+ agent ${name2}:
119212
+ role: worker${parentLine}
119213
+ tier: ${tier}
119214
+ description: "Documentation worker.${domainDesc} Writes READMEs, updates guides, adds TSDoc comments, and maintains project documentation. Operates within declared documentation file globs."
119215
+ consult-when: "Writing documentation, updating READMEs, adding TSDoc comments, or improving existing docs"
119216
+
119217
+ context_sources:
119218
+ - source: patterns
119219
+ query: "documentation conventions and style patterns"
119220
+ max_entries: 3
119221
+ - source: decisions
119222
+ query: "architectural decisions needing documentation"
119223
+ max_entries: 3
119224
+ on_overflow: escalate_tier
119225
+
119226
+ mental_model:
119227
+ scope: project
119228
+ max_tokens: 1000
119229
+ on_load:
119230
+ validate: true
119231
+
119232
+ permissions:
119233
+ files:
119234
+ write: ["docs/**", "**/*.md", "**/*.mdx"]
119235
+ read: ["**/*"]
119236
+ delete: ["docs/**"]
119237
+
119238
+ skills:
119239
+ - ct-cleo
119240
+ - ct-documentor
119241
+ - ct-docs-write
119242
+
119243
+ tools:
119244
+ core: [Read, Edit, Write, Bash, Glob, Grep]
119245
+
119246
+ on SessionStart:
119247
+ session "Check assigned documentation task and review existing docs for context"
119248
+ context: [active-tasks, memory-bridge]
119249
+
119250
+ on PostToolUse:
119251
+ if tool.name == "Write" or tool.name == "Edit":
119252
+ session "Verify markdown renders correctly and follows project style conventions"
119253
+ `;
119254
+ }
119255
+ function deriveWriteGlobs(domain2) {
119256
+ const defaults = ["src/**", "packages/**", "lib/**", "test/**", "tests/**"];
119257
+ if (!domain2) return defaults;
119258
+ const lower = domain2.toLowerCase();
119259
+ if (lower.includes("frontend") || lower.includes("ui") || lower.includes("component")) {
119260
+ return ["src/**", "packages/**", "components/**", "styles/**", "public/**", "test/**"];
119261
+ }
119262
+ if (lower.includes("backend") || lower.includes("api") || lower.includes("server")) {
119263
+ return ["src/**", "packages/**", "lib/**", "api/**", "test/**", "tests/**"];
119264
+ }
119265
+ if (lower.includes("infra") || lower.includes("deploy") || lower.includes("ci")) {
119266
+ return [".github/**", "infra/**", "deploy/**", "scripts/**", "Dockerfile*"];
119267
+ }
119268
+ if (lower.includes("test") || lower.includes("qa") || lower.includes("quality")) {
119269
+ return ["test/**", "tests/**", "src/**/*.test.*", "src/**/*.spec.*", "packages/**/*.test.*"];
119270
+ }
119271
+ if (lower.includes("rust") || lower.includes("crate")) {
119272
+ return ["crates/**", "src/**", "Cargo.toml", "test/**"];
119273
+ }
119274
+ if (lower.includes("doc")) {
119275
+ return ["docs/**", "**/*.md", "**/*.mdx"];
119276
+ }
119277
+ return defaults;
119278
+ }
119279
+ function generateManifest2(params) {
119280
+ return {
119281
+ name: params.name,
119282
+ version: "1.0.0",
119283
+ description: `${capitalizeFirst(params.role)} agent${params.domain ? ` for ${params.domain}` : ""}`,
119284
+ cant: {
119285
+ minVersion: "1",
119286
+ tier: params.tier,
119287
+ role: params.role === "docs-worker" ? "worker" : params.role
119288
+ },
119289
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
119290
+ };
119291
+ }
119292
+ function generateTeamConfig(name2, role, team) {
119293
+ return `---
119294
+ kind: team-config
119295
+ version: "1"
119296
+ ---
119297
+
119298
+ # Team membership for ${name2}
119299
+
119300
+ team ${team}:
119301
+ member ${name2}:
119302
+ role: ${role}
119303
+ status: active
119304
+ `;
119305
+ }
119306
+ function generateMentalModelSeed(name2, role, domain2) {
119307
+ const domainSection = domain2 ? `## Domain
119308
+
119309
+ ${domain2}
119310
+ ` : `## Domain
119311
+
119312
+ TODO: Describe the domain this agent specializes in.
119313
+ `;
119314
+ return `# Mental Model Seed: ${name2}
119315
+
119316
+ > Auto-generated at ${(/* @__PURE__ */ new Date()).toISOString()}
119317
+ > Role: ${role}
119318
+
119319
+ ${domainSection}
119320
+ ## Key Patterns
119321
+
119322
+ TODO: Document recurring patterns this agent should recognize.
119323
+
119324
+ ## Known Pitfalls
119325
+
119326
+ TODO: Document common mistakes or anti-patterns in this domain.
119327
+
119328
+ ## Decision History
119329
+
119330
+ TODO: Track important decisions and their rationale.
119331
+
119332
+ ## Learning Log
119333
+
119334
+ TODO: Record discoveries and insights as the agent operates.
119335
+ `;
119336
+ }
119337
+ function capitalizeFirst(str) {
119338
+ if (str.length === 0) return str;
119339
+ return str.charAt(0).toUpperCase() + str.slice(1);
118223
119340
  }
118224
119341
 
118225
119342
  // packages/cleo/src/cli/commands/agents.ts
@@ -125330,5 +126447,7 @@ var main = defineCommand({
125330
126447
  },
125331
126448
  subCommands
125332
126449
  });
125333
- runMain(main);
126450
+ var aliasMap = buildAliasMap(rootShim._subcommands);
126451
+ var customShowUsage = createCustomShowUsage(CLI_VERSION, rootShim._subcommands, aliasMap);
126452
+ runMain(main, { showUsage: customShowUsage });
125334
126453
  //# sourceMappingURL=index.js.map