tines 0.0.78 → 0.0.80

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 (2) hide show
  1. package/dist/index.js +227 -133
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -143,7 +143,164 @@ function utilizationLabel(quota2, activeRuns, stateName = (id) => id) {
143
143
  if (!counts.has(stateId)) counts.set(stateId, { name: stateName(stateId), n: 0 });
144
144
  }
145
145
  if (counts.size === 0) return `no active runs (roster default ${quota2.default_limit} per state)`;
146
- return [...counts.entries()].map(([stateId, { name, n }]) => `${name} ${n}/${quota2.overrides[stateId] ?? quota2.default_limit}`).join(" \xB7 ");
146
+ return [...counts.entries()].map(([stateId, { name: name2, n }]) => `${name2} ${n}/${quota2.overrides[stateId] ?? quota2.default_limit}`).join(" \xB7 ");
147
+ }
148
+
149
+ // ../shared/src/events.ts
150
+ var text = (t) => ({ kind: "text", text: t });
151
+ var name = (t) => ({ kind: "name", text: str(t) });
152
+ var selfRef = () => ({ kind: "self-ref" });
153
+ function str(v) {
154
+ return v === null || v === void 0 ? "" : String(v);
155
+ }
156
+ function joinChanged(v, sep) {
157
+ return Array.isArray(v) ? v.join(sep) : "";
158
+ }
159
+ function action(type) {
160
+ return type.split(".")[1] ?? type;
161
+ }
162
+ function otherRef(p) {
163
+ return {
164
+ kind: "other-ref",
165
+ project_name: str(p.other_project_name),
166
+ number: Number(p.other_number)
167
+ };
168
+ }
169
+ function linkSegments(ev, p) {
170
+ const lead = ev.type === "issue.link_added" ? "marked" : "unmarked";
171
+ const duplicate = p.kind === "duplicate_of";
172
+ if (duplicate && p.role === "target") {
173
+ return [text(lead), otherRef(p), text("as a duplicate of"), selfRef()];
174
+ }
175
+ const middle = duplicate ? "as a duplicate of" : p.role === "target" ? "as blocked by" : "as blocking";
176
+ const segs = [text(lead), selfRef(), text(middle), otherRef(p)];
177
+ if (p.other_title) segs.push(text(`\u2014 ${str(p.other_title)}`));
178
+ return segs;
179
+ }
180
+ var DESCRIBERS = {
181
+ "issue.created": (_ev, p) => {
182
+ const segs = [text("created"), selfRef()];
183
+ if (p.title) segs.push(text(`\u2014 ${str(p.title)}`));
184
+ return segs;
185
+ },
186
+ "issue.updated": (_ev, p) => {
187
+ const changed = joinChanged(p.changed, " and ");
188
+ const segs = [text(changed ? `updated ${changed} of` : "updated"), selfRef()];
189
+ if (p.workflow_to_name) {
190
+ segs.push(text("from"), name(p.workflow_from_name), text("to"), name(p.workflow_to_name));
191
+ }
192
+ return segs;
193
+ },
194
+ "issue.transitioned": (_ev, p) => {
195
+ const segs = [text("moved"), selfRef()];
196
+ if (p.action) segs.push(text("via"), name(p.action));
197
+ else if (p.forced) segs.push(text("directly"));
198
+ segs.push({
199
+ kind: "state-transition",
200
+ from: str(p.from_state_name) || "?",
201
+ to: str(p.to_state_name) || "?"
202
+ });
203
+ return segs;
204
+ },
205
+ "issue.commented": () => [text("commented on"), selfRef()],
206
+ "issue.link_added": linkSegments,
207
+ "issue.link_removed": linkSegments,
208
+ "issue.parked": (_ev, p) => [
209
+ text("parked"),
210
+ selfRef(),
211
+ text(`after ${str(p.attempt_count)} strikes \u2014 needs attention`)
212
+ ],
213
+ "issue.resumed": () => [text("resumed"), selfRef(), text("(attempt count reset)")],
214
+ "project.created": (ev, p) => projectSegments(ev, p),
215
+ "project.updated": (ev, p) => projectSegments(ev, p),
216
+ "project.deleted": (ev, p) => projectSegments(ev, p),
217
+ "workflow.created": (ev, p) => [text(`${action(ev.type)} workflow`), name(p.name)],
218
+ "workflow.updated": (ev, p) => [text(`${action(ev.type)} workflow`), name(p.name)],
219
+ "workflow.deleted": (ev, p) => [text(`${action(ev.type)} workflow`), name(p.name)],
220
+ "api_key.created": (_ev, p) => [text("created API key"), name(p.name)],
221
+ "api_key.revoked": (_ev, p) => [text("revoked API key"), name(p.name)],
222
+ "scheduled_task.created": (ev, p) => [text(`${action(ev.type)} schedule`), name(p.name)],
223
+ "scheduled_task.updated": (ev, p) => [text(`${action(ev.type)} schedule`), name(p.name)],
224
+ "scheduled_task.deleted": (ev, p) => [text(`${action(ev.type)} schedule`), name(p.name)],
225
+ "scheduled_task.skipped": (_ev, p) => {
226
+ const blocking = Array.isArray(p.blocking) ? p.blocking.length : 0;
227
+ return [
228
+ text("skipped an occurrence of schedule"),
229
+ name(p.name),
230
+ text(`(${blocking} open instance${blocking === 1 ? "" : "s"})`)
231
+ ];
232
+ },
233
+ "context.created": (ev, p) => contextSegments(ev, p),
234
+ "context.updated": (ev, p) => contextSegments(ev, p),
235
+ "context.deleted": (ev, p) => contextSegments(ev, p),
236
+ "runner.registered": (ev, p) => [text(`${action(ev.type)} runner`), name(p.name)],
237
+ "runner.updated": (ev, p) => [text(`${action(ev.type)} runner`), name(p.name)],
238
+ "runner.removed": (ev, p) => [text(`${action(ev.type)} runner`), name(p.name)],
239
+ "runner.errored": (_ev, p) => [
240
+ text("saw runner"),
241
+ name(p.runner_name),
242
+ text(`fail to launch (${str(p.consecutive_failures)} consecutive): ${str(p.error)}`)
243
+ ],
244
+ "routing_rule.created": (ev, p) => [text(`${action(ev.type)} the ${str(p.scope_label)} routing rule`)],
245
+ "routing_rule.updated": (ev, p) => [text(`${action(ev.type)} the ${str(p.scope_label)} routing rule`)],
246
+ "routing_rule.deleted": (ev, p) => [text(`${action(ev.type)} the ${str(p.scope_label)} routing rule`)],
247
+ "settings.updated": (_ev, p) => [
248
+ text(`updated supervisor settings (${joinChanged(p.changed, ", ") || "no changes"})`)
249
+ ],
250
+ "agent_run.started": (_ev, p) => {
251
+ const segs = [text(`started a ${str(p.tier)} run`)];
252
+ if (p.model) segs.push(text(`(${str(p.model)})`));
253
+ segs.push(text("via"), name(p.runner_name), text("on"), selfRef());
254
+ return segs;
255
+ },
256
+ "agent_run.ended": (_ev, p) => {
257
+ const segs = [text(`run ${str(p.status).replaceAll("_", " ")}`)];
258
+ if (p.outcome) segs.push(text(`\u2014 ${str(p.outcome)}`));
259
+ segs.push(text("via"), name(p.runner_name), text("on"), selfRef());
260
+ return segs;
261
+ }
262
+ };
263
+ function projectSegments(ev, p) {
264
+ return [text(`${action(ev.type)} project`), name(p.name ?? ev.project_name)];
265
+ }
266
+ function contextSegments(ev, p) {
267
+ const segs = [text(`${action(ev.type)} ${str(p.kind)}`), name(p.name)];
268
+ if (ev.issue_ref) {
269
+ segs.push(text("on"), selfRef());
270
+ } else {
271
+ const label = p.scope?.label;
272
+ if (label) segs.push(text(`[${label}]`));
273
+ }
274
+ return segs;
275
+ }
276
+ function describeEvent(ev) {
277
+ const describe = DESCRIBERS[ev.type];
278
+ const segs = describe ? describe(ev, ev.payload ?? {}) : ev.issue_ref ? [text(ev.type), selfRef()] : [text(ev.type)];
279
+ return segs.filter((s) => s.kind === "text" || s.kind === "name" ? s.text !== "" : true);
280
+ }
281
+ function segmentText(ev, seg) {
282
+ switch (seg.kind) {
283
+ case "text":
284
+ return seg.text;
285
+ case "name":
286
+ return `"${seg.text}"`;
287
+ case "self-ref":
288
+ return ev.issue_ref ? `${ev.issue_ref.project_name}/#${ev.issue_ref.number}` : "this issue";
289
+ case "other-ref":
290
+ return `${seg.project_name}/#${seg.number}`;
291
+ case "state-transition":
292
+ return `${seg.from} \u2192 ${seg.to}`;
293
+ }
294
+ }
295
+ function eventSummary(ev) {
296
+ return describeEvent(ev).map((seg) => segmentText(ev, seg)).filter((s) => s !== "").join(" ");
297
+ }
298
+ function displayActor(ev) {
299
+ const p = ev.payload ?? {};
300
+ if (ev.type === "issue.created" && p.scheduled_task_name && !p.manual) {
301
+ return `${ev.actor.user_name} via schedule \u201C${str(p.scheduled_task_name)}\u201D`;
302
+ }
303
+ return actorLabel(ev.actor);
147
304
  }
148
305
 
149
306
  // ../shared/src/client.ts
@@ -206,7 +363,7 @@ function createApiClient(options) {
206
363
  }
207
364
  return res;
208
365
  }
209
- const artifactPath = (issueId, name, suffix = "") => `/api/v1/issues/${issueId}/artifacts/${encodeURIComponent(name)}${suffix}`;
366
+ const artifactPath = (issueId, name2, suffix = "") => `/api/v1/issues/${issueId}/artifacts/${encodeURIComponent(name2)}${suffix}`;
210
367
  return {
211
368
  getTime: () => get("/api/time"),
212
369
  // Projects
@@ -266,14 +423,14 @@ function createApiClient(options) {
266
423
  getIssuePrompt: (issueId) => get(`/api/v1/issues/${issueId}/prompt`),
267
424
  // Issue artifacts (name-addressed under the issue)
268
425
  listArtifacts: (issueId) => get(`/api/v1/issues/${issueId}/artifacts`),
269
- getArtifact: (issueId, name) => get(artifactPath(issueId, name)),
426
+ getArtifact: (issueId, name2) => get(artifactPath(issueId, name2)),
270
427
  /** JSON upsert for text/link/pr: creates the artifact or appends a version. */
271
- putArtifact: (issueId, name, body) => request("PUT", artifactPath(issueId, name), body),
428
+ putArtifact: (issueId, name2, body) => request("PUT", artifactPath(issueId, name2), body),
272
429
  /** Raw-body upload for `file`: creates the artifact or appends a version. */
273
- uploadArtifactFile: async (issueId, name, bytes, opts) => {
430
+ uploadArtifactFile: async (issueId, name2, bytes, opts) => {
274
431
  const res = await raw(
275
432
  "PUT",
276
- artifactPath(issueId, name, `/file?filename=${encodeURIComponent(opts.filename)}`),
433
+ artifactPath(issueId, name2, `/file?filename=${encodeURIComponent(opts.filename)}`),
277
434
  {
278
435
  body: bytes,
279
436
  headers: { "content-type": opts.contentType }
@@ -285,23 +442,23 @@ function createApiClient(options) {
285
442
  * Multipart snapshot upload for `folder`: every file of the new version
286
443
  * in one request (path as the part filename, MIME as the part type).
287
444
  */
288
- uploadArtifactFolder: async (issueId, name, files) => {
445
+ uploadArtifactFolder: async (issueId, name2, files) => {
289
446
  const form = new FormData();
290
447
  for (const file of files) {
291
448
  form.append("file", new Blob([file.bytes], { type: file.contentType }), file.path);
292
449
  }
293
- const res = await raw("PUT", artifactPath(issueId, name, "/folder"), { body: form });
450
+ const res = await raw("PUT", artifactPath(issueId, name2, "/folder"), { body: form });
294
451
  return await res.json();
295
452
  },
296
453
  /** Bless the current content as fresh: appends a reaffirming version. */
297
- reaffirmArtifact: (issueId, name) => request("POST", artifactPath(issueId, name, "/reaffirm")),
454
+ reaffirmArtifact: (issueId, name2) => request("POST", artifactPath(issueId, name2, "/reaffirm")),
298
455
  /** Bytes of a version (default: current; `path` selects a folder entry). */
299
- getArtifactContent: async (issueId, name, opts = {}) => {
456
+ getArtifactContent: async (issueId, name2, opts = {}) => {
300
457
  const params = new URLSearchParams();
301
458
  if (opts.version !== void 0) params.set("version", String(opts.version));
302
459
  if (opts.path !== void 0) params.set("path", opts.path);
303
460
  const query2 = params.toString() ? `?${params.toString()}` : "";
304
- const res = await raw("GET", artifactPath(issueId, name, `/content${query2}`));
461
+ const res = await raw("GET", artifactPath(issueId, name2, `/content${query2}`));
305
462
  const disposition = res.headers.get("content-disposition") ?? "";
306
463
  const filenameMatch = disposition.match(/filename="((?:[^"\\]|\\.)*)"/);
307
464
  return {
@@ -310,7 +467,7 @@ function createApiClient(options) {
310
467
  filename: filenameMatch ? filenameMatch[1].replaceAll('\\"', '"') : null
311
468
  };
312
469
  },
313
- deleteArtifact: (issueId, name) => request("DELETE", artifactPath(issueId, name)),
470
+ deleteArtifact: (issueId, name2) => request("DELETE", artifactPath(issueId, name2)),
314
471
  // Events
315
472
  listEvents: (filters = {}) => get(`/api/v1/events${query(filters)}`),
316
473
  // Runners
@@ -405,30 +562,30 @@ function writeJsonFile(path, value, { secret = false } = {}) {
405
562
  writeFileSync(path, `${JSON.stringify(value, null, 2)}
406
563
  `, secret ? { mode: 384 } : {});
407
564
  }
408
- function credentialsKey(url, name) {
409
- return `${url.replace(/\/+$/, "")}#${name}`;
565
+ function credentialsKey(url, name2) {
566
+ return `${url.replace(/\/+$/, "")}#${name2}`;
410
567
  }
411
568
  function credentialsPath(dir) {
412
569
  return join(dir, "runners.json");
413
570
  }
414
- function loadRunnerCredentials(dir, url, name) {
571
+ function loadRunnerCredentials(dir, url, name2) {
415
572
  const all = readJsonFile(credentialsPath(dir));
416
- const entry = all?.[credentialsKey(url, name)];
573
+ const entry = all?.[credentialsKey(url, name2)];
417
574
  return entry && typeof entry.runner_id === "string" && typeof entry.token === "string" ? entry : null;
418
575
  }
419
- function saveRunnerCredentials(dir, url, name, creds) {
576
+ function saveRunnerCredentials(dir, url, name2, creds) {
420
577
  const path = credentialsPath(dir);
421
578
  const all = readJsonFile(path) ?? {};
422
- all[credentialsKey(url, name)] = creds;
579
+ all[credentialsKey(url, name2)] = creds;
423
580
  writeJsonFile(path, all, { secret: true });
424
581
  }
425
- function hasRunnerCredentials(dir, url, name) {
426
- return loadRunnerCredentials(dir, url, name) !== null;
582
+ function hasRunnerCredentials(dir, url, name2) {
583
+ return loadRunnerCredentials(dir, url, name2) !== null;
427
584
  }
428
- function clearRunnerCredentials(dir, url, name) {
585
+ function clearRunnerCredentials(dir, url, name2) {
429
586
  const path = credentialsPath(dir);
430
587
  const all = readJsonFile(path) ?? {};
431
- delete all[credentialsKey(url, name)];
588
+ delete all[credentialsKey(url, name2)];
432
589
  writeJsonFile(path, all, { secret: true });
433
590
  }
434
591
  function daemonStatePath(dir, runnerId) {
@@ -563,9 +720,9 @@ var LogBatcher = class {
563
720
  buffer = "";
564
721
  timer = null;
565
722
  sending = Promise.resolve();
566
- append(text) {
567
- if (!text) return;
568
- this.buffer += text;
723
+ append(text2) {
724
+ if (!text2) return;
725
+ this.buffer += text2;
569
726
  if (Buffer.byteLength(this.buffer, "utf8") >= (this.opts.maxBytes ?? 8 * 1024)) {
570
727
  void this.flush();
571
728
  } else if (!this.timer) {
@@ -1057,13 +1214,13 @@ function parseScheduleRef(ref) {
1057
1214
  return { project: ref.slice(0, sep), name: ref.slice(sep + 1) };
1058
1215
  }
1059
1216
  async function resolveSchedule(api, ref) {
1060
- const { project, name } = parseScheduleRef(ref);
1217
+ const { project, name: name2 } = parseScheduleRef(ref);
1061
1218
  const proj = await resolveProject(api, project);
1062
1219
  const { items } = await api.listProjectSchedules(proj.id, { limit: 100 });
1063
- const found = items.find((s) => s.name === name) ?? items.find((s) => s.id === name);
1220
+ const found = items.find((s) => s.name === name2) ?? items.find((s) => s.id === name2);
1064
1221
  if (!found) {
1065
1222
  die(
1066
- `no schedule "${name}" in project "${proj.name}" (have: ${items.map((s) => s.name).join(", ") || "none"})`
1223
+ `no schedule "${name2}" in project "${proj.name}" (have: ${items.map((s) => s.name).join(", ") || "none"})`
1067
1224
  );
1068
1225
  }
1069
1226
  return found;
@@ -1307,69 +1464,6 @@ function printWorkflowDetail(wf) {
1307
1464
  for (const w of wf.warnings ?? []) console.log(`
1308
1465
  warning: ${w}`);
1309
1466
  }
1310
- function eventSummary(ev) {
1311
- const p = ev.payload;
1312
- const issue = ev.issue_ref ? `${ev.issue_ref.project_name}/#${ev.issue_ref.number}` : null;
1313
- switch (ev.type) {
1314
- case "issue.created":
1315
- return `created ${issue}: ${p.title}${p.scheduled_task_name ? ` (via schedule "${p.scheduled_task_name}")` : ""}`;
1316
- case "issue.updated":
1317
- return `updated ${issue} (${p.changed?.join(", ")})`;
1318
- case "issue.transitioned":
1319
- return `${p.action ? `"${p.action}" on` : "moved"} ${issue}: ${p.from_state_name} \u2192 ${p.to_state_name}`;
1320
- case "issue.commented":
1321
- return `commented on ${issue}`;
1322
- case "project.created":
1323
- case "project.updated":
1324
- case "project.deleted":
1325
- return `${ev.type.split(".")[1]} project "${p.name ?? ev.project_name}"`;
1326
- case "workflow.created":
1327
- case "workflow.updated":
1328
- case "workflow.deleted":
1329
- return `${ev.type.split(".")[1]} workflow "${p.name}"`;
1330
- case "api_key.created":
1331
- return `created API key "${p.name}"`;
1332
- case "api_key.revoked":
1333
- return `revoked API key "${p.name}"`;
1334
- case "scheduled_task.created":
1335
- case "scheduled_task.updated":
1336
- case "scheduled_task.deleted":
1337
- return `${ev.type.split(".")[1]} schedule "${p.name}"`;
1338
- case "context.created":
1339
- case "context.updated":
1340
- case "context.deleted": {
1341
- const scope = p.scope;
1342
- const verb = ev.type.split(".")[1];
1343
- return `${verb} ${p.kind} "${p.name}"${scope?.label ? ` [${scope.label}]` : ""}`;
1344
- }
1345
- case "scheduled_task.skipped": {
1346
- const blocking = Array.isArray(p.blocking) ? p.blocking.length : 0;
1347
- return `skipped schedule "${p.name}" (${blocking} open instance${blocking === 1 ? "" : "s"})`;
1348
- }
1349
- case "runner.registered":
1350
- case "runner.updated":
1351
- case "runner.removed":
1352
- return `${ev.type.split(".")[1]} runner "${p.name}"`;
1353
- case "runner.errored":
1354
- return `runner "${p.runner_name}" failed to launch (${p.consecutive_failures} consecutive): ${p.error}`;
1355
- case "agent_run.started":
1356
- return `run started on ${issue} via ${p.runner_name} (${p.tier}${p.model ? ` \u2192 ${p.model}` : ""})`;
1357
- case "agent_run.ended":
1358
- return `run ${p.status} on ${issue} via ${p.runner_name}${p.outcome ? ` \u2014 ${p.outcome}` : ""}`;
1359
- case "issue.parked":
1360
- return `parked ${issue} after ${p.attempt_count} strikes \u2014 needs attention`;
1361
- case "issue.resumed":
1362
- return `resumed ${issue} (attempt count reset)`;
1363
- case "routing_rule.created":
1364
- case "routing_rule.updated":
1365
- case "routing_rule.deleted":
1366
- return `${ev.type.split(".")[1]} the ${p.scope_label} routing rule`;
1367
- case "settings.updated":
1368
- return `updated supervisor settings (${p.changed?.join(", ") || "no changes"})`;
1369
- default:
1370
- return ev.type;
1371
- }
1372
- }
1373
1467
  function cliVersion() {
1374
1468
  try {
1375
1469
  const manifest = new URL("../package.json", import.meta.url);
@@ -1401,7 +1495,7 @@ withList(projects.command("list").description("List projects")).action(async (op
1401
1495
  withCommon(
1402
1496
  projects.command("create <name>").description("Create a project (with its initial context prompt)").option("-d, --description <text>", "project description").option("-w, --default-workflow <id-or-name>", "default workflow for new issues").option("--prompt <md>", "initial conventions prompt, stitched into every issue's agent prompt: inline Markdown or @file").option("--no-prompt", "create without an initial prompt")
1403
1497
  ).action(
1404
- async (name, opts) => {
1498
+ async (name2, opts) => {
1405
1499
  if (opts.prompt === void 0 || opts.prompt === true) {
1406
1500
  die(
1407
1501
  'every issue in a project inherits its context \u2014 give the project an initial prompt:\n --prompt "<markdown>" house conventions, inline or @file\n --no-prompt create without one (add later: tines context create -k prompt -n conventions -p <name> --body \u2026)'
@@ -1410,7 +1504,7 @@ withCommon(
1410
1504
  const api = client(opts);
1411
1505
  const workflowId = opts.defaultWorkflow ? (await resolveWorkflow(api, opts.defaultWorkflow)).id : void 0;
1412
1506
  const project = await api.createProject({
1413
- name,
1507
+ name: name2,
1414
1508
  description: opts.description,
1415
1509
  default_workflow_id: workflowId,
1416
1510
  initial_prompt: typeof opts.prompt === "string" ? readBodyValue(opts.prompt) : void 0
@@ -1647,13 +1741,13 @@ withCommon(
1647
1741
  );
1648
1742
  withCommon(
1649
1743
  issues.command("move <ref> <action>").description('Take a transition on an issue by its action name (e.g. "approve")')
1650
- ).action(async (ref, action, opts) => {
1744
+ ).action(async (ref, action2, opts) => {
1651
1745
  const api = client(opts);
1652
1746
  const issue = await resolveIssue(api, ref);
1653
- const moved = await api.transitionIssue(issue.id, { action });
1747
+ const moved = await api.transitionIssue(issue.id, { action: action2 });
1654
1748
  if (opts.json) return printJson(moved);
1655
1749
  console.log(
1656
- `${moved.project_name}/#${moved.number}: ${issue.state.name} \u2192 ${moved.state.name} ("${action}")`
1750
+ `${moved.project_name}/#${moved.number}: ${issue.state.name} \u2192 ${moved.state.name} ("${action2}")`
1657
1751
  );
1658
1752
  });
1659
1753
  withCommon(
@@ -1863,10 +1957,10 @@ withCommon(artifactsCmd.command("list <ref>").description("List the artifacts at
1863
1957
  );
1864
1958
  withCommon(
1865
1959
  artifactsCmd.command("show <ref> <name>").description("Show an artifact with its full version history")
1866
- ).action(async (ref, name, opts) => {
1960
+ ).action(async (ref, name2, opts) => {
1867
1961
  const api = client(opts);
1868
1962
  const issue = await resolveIssue(api, ref);
1869
- const artifact = await api.getArtifact(issue.id, name);
1963
+ const artifact = await api.getArtifact(issue.id, name2);
1870
1964
  if (opts.json) return printJson(artifact);
1871
1965
  console.log(`${artifact.artifact_type} artifact "${artifact.name}" on ${issue.project_name}/${issue.number}`);
1872
1966
  if (artifact.description) console.log(artifact.description);
@@ -1898,7 +1992,7 @@ withCommon(
1898
1992
  // --url is the link payload here; the API base comes from TINES_API_URL.
1899
1993
  { baseUrlFlag: false }
1900
1994
  ).action(
1901
- async (ref, name, opts) => {
1995
+ async (ref, name2, opts) => {
1902
1996
  const api = client({ apiKey: opts.apiKey, json: opts.json });
1903
1997
  const sources = [opts.file, opts.folder, opts.text, opts.url, opts.pr].filter((v) => v !== void 0);
1904
1998
  if (sources.length !== 1) {
@@ -1914,9 +2008,9 @@ withCommon(
1914
2008
  }
1915
2009
  const files = walkFolder(opts.folder);
1916
2010
  if (files.length === 0) die(`${opts.folder} contains no files to snapshot`);
1917
- artifact = await api.uploadArtifactFolder(issue.id, name, files);
2011
+ artifact = await api.uploadArtifactFolder(issue.id, name2, files);
1918
2012
  if (opts.description !== void 0) {
1919
- artifact = await api.putArtifact(issue.id, name, { description: opts.description });
2013
+ artifact = await api.putArtifact(issue.id, name2, { description: opts.description });
1920
2014
  }
1921
2015
  } else if (opts.file !== void 0) {
1922
2016
  let bytes;
@@ -1925,15 +2019,15 @@ withCommon(
1925
2019
  } catch (err) {
1926
2020
  die(`cannot read ${opts.file}: ${err instanceof Error ? err.message : String(err)}`);
1927
2021
  }
1928
- artifact = await api.uploadArtifactFile(issue.id, name, bytes, {
2022
+ artifact = await api.uploadArtifactFile(issue.id, name2, bytes, {
1929
2023
  filename: opts.filename ?? basename(opts.file),
1930
2024
  contentType: opts.contentType ?? sniffContentType(opts.file)
1931
2025
  });
1932
2026
  if (opts.description !== void 0) {
1933
- artifact = await api.putArtifact(issue.id, name, { description: opts.description });
2027
+ artifact = await api.putArtifact(issue.id, name2, { description: opts.description });
1934
2028
  }
1935
2029
  } else if (opts.text !== void 0) {
1936
- artifact = await api.putArtifact(issue.id, name, {
2030
+ artifact = await api.putArtifact(issue.id, name2, {
1937
2031
  type: "text",
1938
2032
  content: readBodyValue(opts.text),
1939
2033
  ...opts.filename !== void 0 ? { filename: opts.filename } : {},
@@ -1941,7 +2035,7 @@ withCommon(
1941
2035
  ...opts.description !== void 0 ? { description: opts.description } : {}
1942
2036
  });
1943
2037
  } else if (opts.url !== void 0) {
1944
- artifact = await api.putArtifact(issue.id, name, {
2038
+ artifact = await api.putArtifact(issue.id, name2, {
1945
2039
  type: "link",
1946
2040
  url: opts.url,
1947
2041
  ...opts.title !== void 0 ? { title: opts.title } : {},
@@ -1952,7 +2046,7 @@ withCommon(
1952
2046
  if (!parsed) {
1953
2047
  die(`--pr takes owner/repo#N or a GitHub PR URL, got "${opts.pr}"`);
1954
2048
  }
1955
- artifact = await api.putArtifact(issue.id, name, {
2049
+ artifact = await api.putArtifact(issue.id, name2, {
1956
2050
  type: "pr",
1957
2051
  pr_repo_url: parsed.repo_url,
1958
2052
  pr_number: parsed.number,
@@ -1967,10 +2061,10 @@ withCommon(
1967
2061
  );
1968
2062
  withCommon(
1969
2063
  artifactsCmd.command("reaffirm <ref> <name>").description("Bless the current content as fresh (appends a version reusing the same payload)")
1970
- ).action(async (ref, name, opts) => {
2064
+ ).action(async (ref, name2, opts) => {
1971
2065
  const api = client(opts);
1972
2066
  const issue = await resolveIssue(api, ref);
1973
- const artifact = await api.reaffirmArtifact(issue.id, name);
2067
+ const artifact = await api.reaffirmArtifact(issue.id, name2);
1974
2068
  if (opts.json) return printJson(artifact);
1975
2069
  console.log(
1976
2070
  `reaffirmed "${artifact.name}" on ${issue.project_name}/${issue.number}: v${artifact.current_version.version} reaffirms v${artifact.current_version.reaffirmed_from} \u2014 fresh as of now`
@@ -1979,14 +2073,14 @@ withCommon(
1979
2073
  withCommon(
1980
2074
  artifactsCmd.command("get <ref> <name>").description("Fetch content (current version by default); a link/pr prints its URL").option("--version <n>", "fetch a specific version from the history", (v) => Number.parseInt(v, 10)).option("--out <path>", "write to this file, or into this directory (keeps the stored filename)")
1981
2075
  ).action(
1982
- async (ref, name, opts) => {
2076
+ async (ref, name2, opts) => {
1983
2077
  const api = client(opts);
1984
2078
  const issue = await resolveIssue(api, ref);
1985
- const artifact = await api.getArtifact(issue.id, name);
2079
+ const artifact = await api.getArtifact(issue.id, name2);
1986
2080
  const version = opts.version === void 0 ? artifact.current_version : artifact.versions.find((v) => v.version === opts.version);
1987
2081
  if (!version) {
1988
2082
  die(
1989
- `artifact "${name}" has no version ${opts.version} (history: v1\u2013v${artifact.current_version.version})`
2083
+ `artifact "${name2}" has no version ${opts.version} (history: v1\u2013v${artifact.current_version.version})`
1990
2084
  );
1991
2085
  }
1992
2086
  if (artifact.artifact_type === "link" || artifact.artifact_type === "pr") {
@@ -1996,7 +2090,7 @@ withCommon(
1996
2090
  }
1997
2091
  if (artifact.artifact_type === "folder") {
1998
2092
  if (opts.out === void 0) {
1999
- die(`artifact "${name}" is a folder \u2014 pass --out <dir> to write its tree`);
2093
+ die(`artifact "${name2}" is a folder \u2014 pass --out <dir> to write its tree`);
2000
2094
  }
2001
2095
  if (existsSync2(opts.out) && !statSync(opts.out).isDirectory()) {
2002
2096
  die(`--out for a folder must be a directory, and "${opts.out}" is a file`);
@@ -2004,7 +2098,7 @@ withCommon(
2004
2098
  const files = version.files ?? [];
2005
2099
  let total = 0;
2006
2100
  for (const file of files) {
2007
- const content2 = await api.getArtifactContent(issue.id, name, {
2101
+ const content2 = await api.getArtifactContent(issue.id, name2, {
2008
2102
  version: opts.version,
2009
2103
  path: file.path
2010
2104
  });
@@ -2014,15 +2108,15 @@ withCommon(
2014
2108
  total += content2.bytes.byteLength;
2015
2109
  }
2016
2110
  return console.log(
2017
- `wrote ${files.length} file${files.length === 1 ? "" : "s"} (${total} bytes) from "${name}" v${version.version} into ${opts.out}/`
2111
+ `wrote ${files.length} file${files.length === 1 ? "" : "s"} (${total} bytes) from "${name2}" v${version.version} into ${opts.out}/`
2018
2112
  );
2019
2113
  }
2020
- const content = await api.getArtifactContent(issue.id, name, { version: opts.version });
2114
+ const content = await api.getArtifactContent(issue.id, name2, { version: opts.version });
2021
2115
  const bytes = Buffer.from(content.bytes);
2022
2116
  if (opts.out !== void 0) {
2023
2117
  let target2 = opts.out;
2024
2118
  if (existsSync2(target2) && statSync(target2).isDirectory()) {
2025
- target2 = join3(target2, version.filename ?? name);
2119
+ target2 = join3(target2, version.filename ?? name2);
2026
2120
  }
2027
2121
  writeFileSync3(target2, bytes);
2028
2122
  return console.log(`wrote ${target2} (${bytes.byteLength} bytes, ${content.content_type})`);
@@ -2031,20 +2125,20 @@ withCommon(
2031
2125
  process.stdout.write(bytes);
2032
2126
  return;
2033
2127
  }
2034
- const target = version.filename ?? name;
2128
+ const target = version.filename ?? name2;
2035
2129
  writeFileSync3(target, bytes);
2036
2130
  console.log(`wrote ${target} (${bytes.byteLength} bytes, ${content.content_type})`);
2037
2131
  }
2038
2132
  );
2039
2133
  withCommon(
2040
2134
  artifactsCmd.command("delete <ref> <name>").description("Delete an artifact \u2014 every version and its stored files (history is not recoverable)")
2041
- ).action(async (ref, name, opts) => {
2135
+ ).action(async (ref, name2, opts) => {
2042
2136
  const api = client(opts);
2043
2137
  const issue = await resolveIssue(api, ref);
2044
- const artifact = await api.getArtifact(issue.id, name);
2045
- await api.deleteArtifact(issue.id, name);
2138
+ const artifact = await api.getArtifact(issue.id, name2);
2139
+ await api.deleteArtifact(issue.id, name2);
2046
2140
  console.log(
2047
- `deleted ${artifact.artifact_type} artifact "${name}" from ${issue.project_name}/${issue.number} (${artifact.version_count} version${artifact.version_count === 1 ? "" : "s"})`
2141
+ `deleted ${artifact.artifact_type} artifact "${name2}" from ${issue.project_name}/${issue.number} (${artifact.version_count} version${artifact.version_count === 1 ? "" : "s"})`
2048
2142
  );
2049
2143
  });
2050
2144
  withCommon(
@@ -2059,8 +2153,8 @@ withCommon(
2059
2153
  return console.log(`unpinned ${updated2.project_name}/#${updated2.number} \u2014 routing rules apply again`);
2060
2154
  }
2061
2155
  if (runnerSpec === void 0) die("pass <runner>[:tier] to pin, or --clear to unpin");
2062
- const { name, tier } = parseTargetSpec(runnerSpec);
2063
- const runner = await resolveRunner(api, name);
2156
+ const { name: name2, tier } = parseTargetSpec(runnerSpec);
2157
+ const runner = await resolveRunner(api, name2);
2064
2158
  const updated = await api.updateIssue(issue.id, {
2065
2159
  pinned_runner_id: runner.id,
2066
2160
  pinned_tier: tier ?? null
@@ -2357,12 +2451,12 @@ withCommon(
2357
2451
  ).action(
2358
2452
  async (ref, markdown, opts, command) => {
2359
2453
  if (helpGuard(command, markdown)) return;
2360
- const text = readBodyValue(markdown);
2454
+ const text2 = readBodyValue(markdown);
2361
2455
  const api = client(opts);
2362
2456
  const { scope, note, item } = await resolveJournal(api, ref, opts.state);
2363
2457
  printNote(note);
2364
2458
  if (item) {
2365
- const updated = await api.appendContextItem(item.id, { text });
2459
+ const updated = await api.appendContextItem(item.id, { text: text2 });
2366
2460
  if (opts.json) return printJson(updated);
2367
2461
  return console.log(`appended to the ${scope.label} journal (now v${updated.version})`);
2368
2462
  }
@@ -2372,7 +2466,7 @@ withCommon(
2372
2466
  name: JOURNAL_NAME,
2373
2467
  project_id: scope.project_id ?? void 0,
2374
2468
  workflow_state_id: scope.workflow_state_id ?? void 0,
2375
- body: text.trim()
2469
+ body: text2.trim()
2376
2470
  });
2377
2471
  if (opts.json) return printJson(created);
2378
2472
  console.log(`started the ${scope.label} journal (${created.id})`);
@@ -2380,7 +2474,7 @@ withCommon(
2380
2474
  if (!(err instanceof ApiError) || err.code !== "duplicate_context_name") throw err;
2381
2475
  const { item: fresh } = await resolveJournal(api, ref, opts.state);
2382
2476
  if (!fresh) throw err;
2383
- const updated = await api.appendContextItem(fresh.id, { text });
2477
+ const updated = await api.appendContextItem(fresh.id, { text: text2 });
2384
2478
  if (opts.json) return printJson(updated);
2385
2479
  console.log(`appended to the ${scope.label} journal (now v${updated.version})`);
2386
2480
  }
@@ -2561,13 +2655,13 @@ async function resolveRunner(api, ref) {
2561
2655
  function parseTargetSpec(spec) {
2562
2656
  const sep = spec.lastIndexOf(":");
2563
2657
  if (sep === -1) return { name: spec };
2564
- const name = spec.slice(0, sep);
2658
+ const name2 = spec.slice(0, sep);
2565
2659
  const tier = spec.slice(sep + 1);
2566
- if (!name) die(`target must look like <runner>[:tier], got "${spec}"`);
2660
+ if (!name2) die(`target must look like <runner>[:tier], got "${spec}"`);
2567
2661
  if (!MODEL_TIERS.includes(tier)) {
2568
2662
  die(`unknown tier "${tier}" in "${spec}" (tiers: ${MODEL_TIERS.join(", ")})`);
2569
2663
  }
2570
- return { name, tier };
2664
+ return { name: name2, tier };
2571
2665
  }
2572
2666
  function runnerStatusLabel(runner) {
2573
2667
  if (runner.status === "paused") return "paused";
@@ -2920,8 +3014,8 @@ withCommon(
2920
3014
  const scope = await resolveRoutingScope(api, opts);
2921
3015
  const targets = [];
2922
3016
  for (const spec of targetSpecs) {
2923
- const { name, tier } = parseTargetSpec(spec);
2924
- const runner = await resolveRunner(api, name);
3017
+ const { name: name2, tier } = parseTargetSpec(spec);
3018
+ const runner = await resolveRunner(api, name2);
2925
3019
  targets.push(tier ? { runner_id: runner.id, tier } : { runner_id: runner.id });
2926
3020
  }
2927
3021
  const { items } = await api.listRoutingRules();
@@ -3063,7 +3157,7 @@ withList(
3063
3157
  if (items.length === 0) return console.log("no events");
3064
3158
  table([
3065
3159
  ["WHEN", "ACTOR", "EVENT"],
3066
- ...items.map((ev) => [timestamp(ev.created_at), actorLabel(ev.actor), eventSummary(ev)])
3160
+ ...items.map((ev) => [timestamp(ev.created_at), displayActor(ev), eventSummary(ev)])
3067
3161
  ]);
3068
3162
  });
3069
3163
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tines",
3
- "version": "0.0.78",
3
+ "version": "0.0.80",
4
4
  "description": "CLI for Tines, an orchestration layer for AI agents",
5
5
  "repository": {
6
6
  "type": "git",