@tablation/crew 0.53.6 → 0.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -177,6 +177,13 @@ reality: the checkouts, the tools on PATH, the agent binary, the repo's hooks,
177
177
  and whether the board answers. Nothing writes, wakes an agent or deploys until
178
178
  a route has `enabled: true`.
179
179
 
180
+ A secondary workspace is addressed as `<primary>:<slug>`:
181
+ `crew connect paradium:issues` (or `paradium:issues/<project>`, or
182
+ `--workspace-id paradium:issues`) connects to it, and the route, keychain
183
+ entry, seat-key name and repos directory all carry that segment verbatim
184
+ (`paradium:issues/issues`, `~/Crew/paradium:issues/<repo>`). Finder shows
185
+ the colon in that directory as a slash; `--dir` overrides the location.
186
+
180
187
  Then install it as a real service:
181
188
 
182
189
  ```sh
package/dist/cli.js CHANGED
@@ -91,6 +91,11 @@ function pickWorktreeRoute(ticketNumber, candidates) {
91
91
  error: `no open ticket ISSUE-${ticketNumber} served by this ship \u2014 looked on ${looked}` + (found.length ? `; found it only on ${found.join(", ")}, which has no checkout for its repo` : "")
92
92
  };
93
93
  }
94
+ function splitConnectArg(arg) {
95
+ if (!arg?.includes("/")) return [arg, void 0];
96
+ const i = arg.indexOf("/");
97
+ return [arg.slice(0, i), arg.slice(i + 1)];
98
+ }
94
99
 
95
100
  // src/config.ts
96
101
  import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
@@ -11359,7 +11364,7 @@ async function listWorkspaces(o) {
11359
11364
  o,
11360
11365
  "/auth/my-workspaces"
11361
11366
  );
11362
- return res.workspaces.map((w) => ({ slug: w.slug, name: w.name, role: w.role }));
11367
+ return res.workspaces.map((w) => ({ slug: w.path ?? w.slug, name: w.name, role: w.role }));
11363
11368
  }
11364
11369
  var eq = (a, b) => (a ?? "").trim().toLowerCase() === b.trim().toLowerCase();
11365
11370
  function seatFor(rows, role) {
@@ -11374,10 +11379,10 @@ async function missingTables(o, projectId) {
11374
11379
  async function discover(o) {
11375
11380
  const problems = [];
11376
11381
  const provisioning = [];
11377
- const ws = await get(o, `/workspaces/${o.workspace}`);
11382
+ const ws = await get(o, `/workspaces/${encodeURIComponent(o.workspace).replace(/%3A/gi, ":")}`);
11378
11383
  const out = {
11379
11384
  workspaceId: ws.id,
11380
- workspaceSlug: ws.slug,
11385
+ workspaceSlug: ws.path ?? ws.slug,
11381
11386
  workspaceName: ws.name,
11382
11387
  models: {},
11383
11388
  seats: {},
@@ -15836,7 +15841,7 @@ ${reconstruction.prompt}
15836
15841
  }
15837
15842
  case "connect": {
15838
15843
  const arg = positional[1];
15839
- const [argWorkspace, argProject] = arg?.includes("/") ? arg.split(/\/(.*)/s) : [arg, void 0];
15844
+ const [argWorkspace, argProject] = splitConnectArg(arg);
15840
15845
  let workspace = argWorkspace ?? value("workspace-id") ?? value("workspace");
15841
15846
  const project = argProject ?? value("project");
15842
15847
  const baseUrl = value("base-url") ?? cfg.routes[0]?.baseUrl ?? DEFAULT_BASE_URL;
@@ -15905,10 +15910,11 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
15905
15910
  );
15906
15911
  apiKey = result.apiKey.key;
15907
15912
  mintedFromDevice = true;
15908
- if (!workspace) workspace = result.workspace.slug;
15913
+ const deviceWorkspace = "path" in result.workspace && typeof result.workspace.path === "string" ? result.workspace.path : result.workspace.slug;
15914
+ if (!workspace) workspace = deviceWorkspace;
15909
15915
  if (store) {
15910
15916
  try {
15911
- await store.set(hostFromUrl3(baseUrl), result.workspace.slug, {
15917
+ await store.set(hostFromUrl3(baseUrl), deviceWorkspace, {
15912
15918
  apiKey: result.apiKey.key,
15913
15919
  shipId: getOrCreateShipId(),
15914
15920
  workspaceId: result.workspace.id,
@@ -15917,7 +15923,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
15917
15923
  });
15918
15924
  keychainBacked = true;
15919
15925
  process.stderr.write(
15920
- `API key stored in the OS keychain for ${hostFromUrl3(baseUrl)}/${result.workspace.slug}.
15926
+ `API key stored in the OS keychain for ${hostFromUrl3(baseUrl)}/${deviceWorkspace}.
15921
15927
  `
15922
15928
  );
15923
15929
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablation/crew",
3
- "version": "0.53.6",
3
+ "version": "0.54.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",
@@ -52,6 +52,16 @@ field. Do not retry the same write. If the missing value is yours to supply
52
52
  once more; otherwise leave the ticket where it is and say so in your
53
53
  hand-off comment.
54
54
 
55
+ A write that fails at the transport level (a session-expired error, a
56
+ timeout, a connection reset, an empty or non-JSON reply) is not a refusal:
57
+ it may have landed. Before you retry a create of a ticket, a comment or an
58
+ event, list the target table for a row with the same title (tickets) or the
59
+ same opening line (comments and events) written by your seat in the last two
60
+ minutes. If one exists, use it and create nothing new. A validation error (a
61
+ 400 or 422 with a field message) is a real failure: fix the body and write
62
+ again. The same check applies to a follow-up ticket you file while working and
63
+ to your hand-off comment.
64
+
55
65
  Your identity is the Crew row named for your seat in the `## Your crew`
56
66
  roster at the top of this prompt. Use its id as the assignee and as the
57
67
  comment author. Every agent and every person who touches this tracker has
@@ -53,6 +53,16 @@ field. Do not retry the same write. If the missing value is yours to supply
53
53
  once more; otherwise leave the ticket where it is and say so in your
54
54
  hand-off comment.
55
55
 
56
+ A write that fails at the transport level (a session-expired error, a
57
+ timeout, a connection reset, an empty or non-JSON reply) is not a refusal:
58
+ it may have landed. Before you retry a create of a ticket, a comment or an
59
+ event, list the target table for a row with the same title (tickets) or the
60
+ same opening line (comments and events) written by your seat in the last two
61
+ minutes. If one exists, use it and create nothing new. A validation error (a
62
+ 400 or 422 with a field message) is a real failure: fix the body and write
63
+ again. The same check applies to a follow-up ticket you file while working and
64
+ to your hand-off comment.
65
+
56
66
  Your identity is the Crew row named for your seat in the `## Your crew`
57
67
  roster at the top of this prompt. Use its id as the assignee and as the
58
68
  comment author. Every agent and every person who touches this tracker has