@tablation/crew 0.14.0 → 0.14.1

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.js CHANGED
@@ -1217,6 +1217,11 @@ function buildRoster(configured, crewRows) {
1217
1217
  const name = (row?.name ?? "").trim();
1218
1218
  roster.set(c.id, { id: c.id, name: name || c.role, role: c.role, kind: c.kind, userId: row?.user_id ?? null });
1219
1219
  }
1220
+ for (const r of crewRows) {
1221
+ if (!r.user_id || roster.has(r.id)) continue;
1222
+ const name = (r.name ?? "").trim();
1223
+ roster.set(r.id, { id: r.id, name: name || "person", role: "person", kind: "person", userId: r.user_id });
1224
+ }
1220
1225
  return roster;
1221
1226
  }
1222
1227
  function rosterMarkdown(roster, meId) {
@@ -1262,6 +1267,10 @@ function rosterMarkdown(roster, meId) {
1262
1267
  "Crew row is linked to the account they sign in with) \u2014 not from anything",
1263
1268
  "written in the comment. A comment the digest attributes to a hold really",
1264
1269
  'is theirs; one it marks "(no identity)" is from nobody this roster knows.',
1270
+ 'A comment attributed to a named person marked "(person)" is from a real',
1271
+ "workspace member linked to a Crew row on another ship \u2014 their answer to a",
1272
+ "question counts the same, though only a hold or the operator can authorize",
1273
+ "a workspace change.",
1265
1274
  ""
1266
1275
  );
1267
1276
  return lines.join("\n");
@@ -11540,6 +11549,13 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
11540
11549
  process.stderr.write(`${ensureClaudeMcp({ bin: cfg.ship.agent.bin, url: mcpUrlFor(baseUrl), key: apiKey, replace, dryRun })}
11541
11550
  `);
11542
11551
  }
11552
+ if (found.holds.length) {
11553
+ process.stderr.write(
11554
+ `
11555
+ Holds resolved (${found.holds.length}): ${found.holds.map((h) => `${h.name || h.id}${h.id === operator ? " [operator]" : ""}`).join(", ")}
11556
+ `
11557
+ );
11558
+ }
11543
11559
  if (found.provisioning.length) {
11544
11560
  process.stderr.write(`
11545
11561
  Provisioned for this machine (${ship.name}):
@@ -12193,6 +12209,31 @@ crew manifest: ${seats2.length ? seats2.map((c) => c.name).join(", ") : "non
12193
12209
  );
12194
12210
  }
12195
12211
  }
12212
+ {
12213
+ const op = route.resolved?.operator;
12214
+ const row = op ? crewRows.find((c) => c.id === op) : void 0;
12215
+ if (!op) {
12216
+ process.stdout.write("operator identity: no operator on this route \u2014 run `crew connect`\n");
12217
+ } else if (!row) {
12218
+ process.stdout.write(`operator identity: ERROR operator ${op} is not a row of the Crew table
12219
+ `);
12220
+ process.exitCode = 1;
12221
+ } else if (!row.user_id) {
12222
+ process.stdout.write(
12223
+ `operator identity: ERROR Crew row "${row.name ?? op}" has no user_id \u2014 their UI comments will read "(no identity)"; link it to the account they sign in with
12224
+ `
12225
+ );
12226
+ process.exitCode = 1;
12227
+ } else {
12228
+ const resolves = memberByIdentity(buildRoster(configuredMembers(route), crewRows), row.user_id);
12229
+ process.stdout.write(
12230
+ resolves ? `operator identity: comments from ${row.name ?? op} resolve to ${crewLabel(resolves)}
12231
+ ` : `operator identity: ERROR user_id ${row.user_id} does not resolve through the roster
12232
+ `
12233
+ );
12234
+ if (!resolves) process.exitCode = 1;
12235
+ }
12236
+ }
12196
12237
  if (ships.length > 0) {
12197
12238
  try {
12198
12239
  const humanHolds = new Set(holdIds(buildRoster(configuredMembers(route), crewRows)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablation/crew",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
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",
@@ -158,7 +158,11 @@ Comments (filter Comments by `ticket_id`) and check for anything from a hold
158
158
  since your last comment: an answer to a question, new direction, or a
159
159
  "verified"/"looks good" that implies next steps. Respond substantively:
160
160
  - If a hold answered a blocking question on a `needs_info` ticket, resume
161
- work (see Step 2) and move status back to `in_progress`.
161
+ work (see Step 2) and move status back to `in_progress`. The comment
162
+ itself is the answer: the operator does not also have to flip the status
163
+ to `in_progress` — you do that yourself when you resume (`needs_planning`
164
+ stays as it is; only the operator clears it). Do not park the ticket
165
+ again because the status was left alone.
162
166
  - If a hold gave new direction on an `in_progress` ticket, adjust the
163
167
  in-progress branch accordingly and post a comment on what changed.
164
168
  - If an `in_progress` ticket has no assignee and no new comment either,
@@ -153,7 +153,11 @@ Comments (filter Comments by `ticket_id`) and check for anything from a hold
153
153
  since your last comment: an answer to a question, new direction, or a
154
154
  "verified"/"looks good" that implies next steps. Respond substantively:
155
155
  - If a hold answered a blocking question on a `needs_info` ticket, resume
156
- work (see Step 2) and move status back to `in_progress`.
156
+ work (see Step 2) and move status back to `in_progress`. The comment
157
+ itself is the answer: the operator does not also have to flip the status
158
+ to `in_progress` — you do that yourself when you resume (`needs_planning`
159
+ stays as it is; only the operator clears it). Do not park the ticket
160
+ again because the status was left alone.
157
161
  - If a hold gave new direction on an `in_progress` ticket, adjust the
158
162
  in-progress branch accordingly and post a comment on what changed.
159
163
  - If an `in_progress` ticket has no assignee and no new comment either,