@tablation/crew 0.1.7 → 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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +48 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -211,7 +211,7 @@ crew pause|resume [route] [R] pause everything, or one role
211
211
  crew log [route] tail the log
212
212
  crew inbox [--member NAME] your tickets across every workspace
213
213
  crew connect WS[/PROJECT] resolve a workspace/project's ids into the state tree
214
- crew repos add ROUTE PATH attach a local checkout to a route in crew.yaml, creating its Repos row if missing (--dry-run previews)
214
+ crew repos add [ROUTE] [NAME] [PATH] attach a local checkout to a route in crew.yaml, creating its Repos row if missing (--dry-run previews)
215
215
  crew repos list ROUTE the checkouts a route has, and the tracker Repos row each matches
216
216
  crew install write and load this platform's scheduler unit
217
217
  crew uninstall unload and remove it
package/dist/cli.js CHANGED
@@ -7042,6 +7042,27 @@ function matchRepoName(origin, resolved) {
7042
7042
  }
7043
7043
  return void 0;
7044
7044
  }
7045
+ function routeNamesOf(text) {
7046
+ const routes = parseDocument(text).get("routes", true);
7047
+ if (!isSeq(routes)) return [];
7048
+ return routes.items.flatMap((i) => isMap(i) && typeof i.get("route") === "string" ? [i.get("route")] : []);
7049
+ }
7050
+ function parseAddArgs(args, routes, isDir) {
7051
+ const rest = [...args];
7052
+ let route;
7053
+ if (rest.length > 0 && routes.includes(rest[0])) route = rest.shift();
7054
+ else if (rest.length > 0 && /^[^/\s]+\/[^/\s]+$/.test(rest[0]) && !isDir(rest[0])) {
7055
+ throw new ReposError(`no route "${rest[0]}" in the config (have: ${routes.join(", ") || "none"})`);
7056
+ }
7057
+ if (!route) {
7058
+ if (routes.length === 1) route = routes[0];
7059
+ else throw new ReposError(routes.length === 0 ? "the config has no routes \u2014 run `crew connect` first" : `several routes are configured; name one: ${routes.join(", ")}`);
7060
+ }
7061
+ if (rest.length > 2) throw new ReposError("too many arguments: expected [route] [name] [path]");
7062
+ if (rest.length === 2) return { route, name: rest[0], path: rest[1] };
7063
+ if (rest.length === 1) return isDir(rest[0]) ? { route, path: rest[0] } : { route, name: rest[0], path: "." };
7064
+ return { route, path: "." };
7065
+ }
7045
7066
  function expandDir(p, base) {
7046
7067
  const home = p === "~" ? homedir3() : p.startsWith("~/") ? `${homedir3()}/${p.slice(2)}` : p;
7047
7068
  return resolve3(base, home);
@@ -7081,7 +7102,7 @@ function planRepoAdd(i) {
7081
7102
  throw new ReposError(`${target} is already configured on route ${i.route}`);
7082
7103
  }
7083
7104
  const matched = matchRepoName(i.origin, i.resolved);
7084
- const name = matched ?? i.name ?? basename5(target);
7105
+ const name = matched ?? i.name ?? normalizeRemote(i.origin)?.split("/").pop() ?? basename5(target);
7085
7106
  let warning;
7086
7107
  if (!matched) {
7087
7108
  const known = Object.values(i.resolved?.repoNames ?? {});
@@ -8327,7 +8348,7 @@ function usage() {
8327
8348
  crew agents sync [route] [--force] push crew's personas AND skill files into the workspace Agents/Agent Skills tables (--force overwrites even a diverged persona)
8328
8349
  crew agents prompt R [route] print one persona's current prompt (e.g. R=pair, for a SessionStart hook)
8329
8350
  crew skills sync [route] push only crew's skill files (e.g. grill-me) into the workspace Agent Skills table
8330
- crew repos add ROUTE PATH attach a local checkout to a route in crew.yaml (--dry-run previews)
8351
+ crew repos add [ROUTE] [NAME] [PATH] attach a local checkout to a route in crew.yaml (--dry-run previews)
8331
8352
  crew repos list ROUTE the checkouts a route has, with the tracker's Repos row each matches
8332
8353
  crew logbook list [route] recent Agent Log entries, filterable by --role/--ticket
8333
8354
  crew logbook show [route] ID [--prompt] one entry; --prompt reconstructs and verifies its prompt
@@ -9613,12 +9634,31 @@ ${changed2.map((c) => ` - ${c}
9613
9634
  }
9614
9635
  case "repos": {
9615
9636
  const sub = positional[1];
9616
- const routeName = positional[2];
9617
9637
  const usage2 = () => {
9618
- process.stderr.write("crew repos add <workspace/project> <path> [--name N] [--project P] [--dry-run] [--no-create]\ncrew repos list <workspace/project>\n");
9638
+ process.stderr.write("crew repos add [workspace/project] [name] [path] [--name N] [--project P] [--dry-run] [--no-create]\ncrew repos list <workspace/project>\n");
9619
9639
  process.exit(2);
9620
9640
  };
9621
- if (sub !== "add" && sub !== "list" || !routeName || sub === "add" && !positional[3]) usage2();
9641
+ if (sub !== "add" && sub !== "list") usage2();
9642
+ const configText = readFileSync12(cfg.configFile, "utf8");
9643
+ let routeName = positional[2];
9644
+ let addPath = ".";
9645
+ let addName;
9646
+ if (sub === "list" && !routeName) usage2();
9647
+ if (sub === "add") {
9648
+ try {
9649
+ const a = parseAddArgs(positional.slice(2), routeNamesOf(configText), (p) => existsSync18(resolvePath(p.replace(/^~(?=\/|$)/, homedir4()))));
9650
+ routeName = a.route;
9651
+ addPath = a.path;
9652
+ addName = a.name;
9653
+ } catch (e) {
9654
+ if (e instanceof ReposError) {
9655
+ process.stderr.write(`crew repos: ${e.message}
9656
+ `);
9657
+ process.exit(2);
9658
+ }
9659
+ throw e;
9660
+ }
9661
+ }
9622
9662
  const resolvedFile = resolvedPathFor(cfg.ship.stateDir, routeName);
9623
9663
  let resolvedRemotes;
9624
9664
  if (existsSync18(resolvedFile)) {
@@ -9628,7 +9668,7 @@ ${changed2.map((c) => ` - ${c}
9628
9668
  }
9629
9669
  }
9630
9670
  const originOf = (dir) => gitOk(dir, ["remote", "get-url", "origin"]) ?? void 0;
9631
- const text = readFileSync12(cfg.configFile, "utf8");
9671
+ const text = configText;
9632
9672
  const base = dirname9(cfg.configFile);
9633
9673
  try {
9634
9674
  if (sub === "list") {
@@ -9644,7 +9684,7 @@ ${changed2.map((c) => ` - ${c}
9644
9684
  }
9645
9685
  break;
9646
9686
  }
9647
- const target = resolvePath(positional[3].replace(/^~(?=\/|$)/, homedir4()));
9687
+ const target = resolvePath(addPath.replace(/^~(?=\/|$)/, homedir4()));
9648
9688
  const top = existsSync18(target) ? gitOk(target, ["rev-parse", "--show-toplevel"]) : null;
9649
9689
  if (!top) throw new ReposError(`${target} is not a git checkout`);
9650
9690
  const origin = originOf(top);
@@ -9655,7 +9695,7 @@ ${changed2.map((c) => ` - ${c}
9655
9695
  path: top,
9656
9696
  origin,
9657
9697
  resolved: resolvedRemotes,
9658
- name: value("name"),
9698
+ name: value("name") ?? addName,
9659
9699
  nameForExisting: (d) => matchRepoName(originOf(d), resolvedRemotes)
9660
9700
  });
9661
9701
  let rowTracker;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablation/crew",
3
- "version": "0.1.7",
3
+ "version": "0.2.0",
4
4
  "description": "A standing team of headless agents that picks work off a Tablation board, does it on a machine you control, and reports back.",
5
5
  "type": "module",
6
6
  "license": "MIT",