tines 0.0.177 → 0.0.179

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/index.js +516 -149
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -39,7 +39,7 @@ tines issues show <project>/<number>
39
39
  tines issues move <project>/<number> <action> # a workflow transition
40
40
  tines issues transfer <project>/<number> --project <dest> # move to another project (keeps ID, record and old refs)
41
41
  tines issues transfer <ref> --project <dest> --dry-run # review only: no number allocated, nothing written
42
- tines issues transfer <ref> --project <dest> --inspect 0 # print reviewed guidance item [0] in full
42
+ tines issues transfer <ref> --project <dest> --inspect 0 # print any reviewed guidance item, including retained, in full
43
43
  tines issues transfer <ref> --project <dest> --yes # skip the prompt (still commits only the fetched review)
44
44
  tines issues comment <project>/<number> - <<'EOF' # body from stdin; @file also works
45
45
  …
package/dist/index.js CHANGED
@@ -1006,8 +1006,8 @@ var DualOptions = class {
1006
1006
  valueFromOption(value, option) {
1007
1007
  const optionKey = option.attributeName();
1008
1008
  if (!this.dualOptions.has(optionKey)) return true;
1009
- const preset = this.negativeOptions.get(optionKey).presetArg;
1010
- const negativeValue = preset !== void 0 ? preset : false;
1009
+ const preset2 = this.negativeOptions.get(optionKey).presetArg;
1010
+ const negativeValue = preset2 !== void 0 ? preset2 : false;
1011
1011
  return option.negate === (negativeValue === value);
1012
1012
  }
1013
1013
  };
@@ -3130,9 +3130,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3130
3130
  helpWidth: context.helpWidth,
3131
3131
  outputHasColors: context.hasColors
3132
3132
  });
3133
- const text3 = helper.formatHelp(this, helper);
3134
- if (context.hasColors) return text3;
3135
- return this._outputConfiguration.stripColor(text3);
3133
+ const text4 = helper.formatHelp(this, helper);
3134
+ if (context.hasColors) return text4;
3135
+ return this._outputConfiguration.stripColor(text4);
3136
3136
  }
3137
3137
  /**
3138
3138
  * @typedef HelpContext
@@ -3292,7 +3292,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3292
3292
  * @param {(string | Function)} text - string to add, or a function returning a string
3293
3293
  * @return {Command} `this` command for chaining
3294
3294
  */
3295
- addHelpText(position, text3) {
3295
+ addHelpText(position, text4) {
3296
3296
  const allowedValues = ["beforeAll", "before", "after", "afterAll"];
3297
3297
  if (!allowedValues.includes(position)) {
3298
3298
  throw new Error(`Unexpected value for position to addHelpText.
@@ -3301,10 +3301,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
3301
3301
  const helpEvent = `${position}Help`;
3302
3302
  this.on(helpEvent, (context) => {
3303
3303
  let helpStr;
3304
- if (typeof text3 === "function") {
3305
- helpStr = text3({ error: context.error, command: context.command });
3304
+ if (typeof text4 === "function") {
3305
+ helpStr = text4({ error: context.error, command: context.command });
3306
3306
  } else {
3307
- helpStr = text3;
3307
+ helpStr = text4;
3308
3308
  }
3309
3309
  if (helpStr) {
3310
3310
  context.write(`${helpStr}
@@ -3534,7 +3534,7 @@ function runCostLabel(run) {
3534
3534
  const tokens = (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0) + (usage.cache_read_tokens ?? 0) + (usage.cache_write_tokens ?? 0);
3535
3535
  return tokens > 0 ? `${tokens.toLocaleString()} tok` : null;
3536
3536
  }
3537
- function utilizationLabel(quota, activeRuns, stateName = (id) => id) {
3537
+ function utilizationLabel(quota, activeRuns, stateName = (id2) => id2) {
3538
3538
  if (quota.type === "global_cap") {
3539
3539
  return `${activeRuns.length}/${quota.limit} global slot${quota.limit === 1 ? "" : "s"} in use`;
3540
3540
  }
@@ -3978,17 +3978,17 @@ function createApiClient(options) {
3978
3978
  listProjects: (params = {}) => get(`/api/v1/projects${query(params)}`),
3979
3979
  createProject: (body) => request("POST", "/api/v1/projects", body),
3980
3980
  listStarters: () => get("/api/v1/projects/starters"),
3981
- getProject: (id) => get(`/api/v1/projects/${id}`),
3982
- updateProject: (id, body) => request("PATCH", `/api/v1/projects/${id}`, body),
3983
- deleteProject: (id, body) => request("DELETE", `/api/v1/projects/${id}`, body),
3984
- archiveProject: (id) => request("POST", `/api/v1/projects/${id}/archive`),
3985
- unarchiveProject: (id) => request("POST", `/api/v1/projects/${id}/unarchive`),
3981
+ getProject: (id2) => get(`/api/v1/projects/${id2}`),
3982
+ updateProject: (id2, body) => request("PATCH", `/api/v1/projects/${id2}`, body),
3983
+ deleteProject: (id2, body) => request("DELETE", `/api/v1/projects/${id2}`, body),
3984
+ archiveProject: (id2) => request("POST", `/api/v1/projects/${id2}/archive`),
3985
+ unarchiveProject: (id2) => request("POST", `/api/v1/projects/${id2}/unarchive`),
3986
3986
  // Workflows
3987
3987
  listWorkflows: (page = {}) => get(`/api/v1/workflows${query(page)}`),
3988
3988
  createWorkflow: (body) => request("POST", "/api/v1/workflows", body),
3989
- getWorkflow: (id) => get(`/api/v1/workflows/${id}`),
3990
- updateWorkflow: (id, body) => request("PATCH", `/api/v1/workflows/${id}`, body),
3991
- deleteWorkflow: (id, body) => request("DELETE", `/api/v1/workflows/${id}`, body),
3989
+ getWorkflow: (id2) => get(`/api/v1/workflows/${id2}`),
3990
+ updateWorkflow: (id2, body) => request("PATCH", `/api/v1/workflows/${id2}`, body),
3991
+ deleteWorkflow: (id2, body) => request("DELETE", `/api/v1/workflows/${id2}`, body),
3992
3992
  // Issues
3993
3993
  listIssues: (filters = {}) => get(`/api/v1/issues${query(filters)}`),
3994
3994
  listLabels: () => get("/api/v1/labels"),
@@ -4003,14 +4003,14 @@ function createApiClient(options) {
4003
4003
  removeIssueLabel: (issueId, labelRef) => request("DELETE", `/api/v1/issues/${issueId}/labels/${encodeURIComponent(labelRef)}`),
4004
4004
  listProjectIssues: (projectId, filters = {}) => get(`/api/v1/projects/${projectId}/issues${query(filters)}`),
4005
4005
  createIssue: (projectId, body) => request("POST", `/api/v1/projects/${projectId}/issues`, body),
4006
- getIssue: (id) => get(`/api/v1/issues/${id}`),
4006
+ getIssue: (id2) => get(`/api/v1/issues/${id2}`),
4007
4007
  getIssueByNumber: (projectId, number) => get(`/api/v1/projects/${projectId}/issues/${number}`),
4008
- updateIssue: (id, body) => request("PATCH", `/api/v1/issues/${id}`, body),
4009
- transitionIssue: (id, body) => request("POST", `/api/v1/issues/${id}/transition`, body),
4008
+ updateIssue: (id2, body) => request("PATCH", `/api/v1/issues/${id2}`, body),
4009
+ transitionIssue: (id2, body) => request("POST", `/api/v1/issues/${id2}/transition`, body),
4010
4010
  /** Un-park: clears needs_attention, resets the attempt count. */
4011
- resumeIssue: (id) => request("POST", `/api/v1/issues/${id}/resume`),
4011
+ resumeIssue: (id2) => request("POST", `/api/v1/issues/${id2}/resume`),
4012
4012
  /** The dispatch explainer: "why isn't this running?". */
4013
- getIssueDispatch: (id) => get(`/api/v1/issues/${id}/dispatch`),
4013
+ getIssueDispatch: (id2) => get(`/api/v1/issues/${id2}/dispatch`),
4014
4014
  // Issue links (dependencies & duplicates)
4015
4015
  addIssueLink: (issueId, body) => request("POST", `/api/v1/issues/${issueId}/links`, body),
4016
4016
  removeIssueLink: (issueId, linkId) => request("DELETE", `/api/v1/issues/${issueId}/links/${linkId}`),
@@ -4022,19 +4022,19 @@ function createApiClient(options) {
4022
4022
  // Scheduled tasks
4023
4023
  listSchedules: (filters = {}) => get(`/api/v1/schedules${query(filters)}`),
4024
4024
  listProjectSchedules: (projectId, page = {}) => get(`/api/v1/projects/${projectId}/schedules${query(page)}`),
4025
- getSchedule: (id) => get(`/api/v1/schedules/${id}`),
4026
- updateSchedule: (id, body) => request("PATCH", `/api/v1/schedules/${id}`, body),
4027
- deleteSchedule: (id) => request("DELETE", `/api/v1/schedules/${id}`),
4025
+ getSchedule: (id2) => get(`/api/v1/schedules/${id2}`),
4026
+ updateSchedule: (id2, body) => request("PATCH", `/api/v1/schedules/${id2}`, body),
4027
+ deleteSchedule: (id2) => request("DELETE", `/api/v1/schedules/${id2}`),
4028
4028
  /** Run now: creates an instance immediately (gate-respecting; 422 when blocked). */
4029
- runSchedule: (id) => request("POST", `/api/v1/schedules/${id}/run`),
4029
+ runSchedule: (id2) => request("POST", `/api/v1/schedules/${id2}/run`),
4030
4030
  // Context items
4031
4031
  listContext: (filters = {}) => get(`/api/v1/context${query(filters)}`),
4032
4032
  createContextItem: (body) => request("POST", "/api/v1/context", body),
4033
- getContextItem: (id) => get(`/api/v1/context/${id}`),
4034
- updateContextItem: (id, body) => request("PATCH", `/api/v1/context/${id}`, body),
4035
- deleteContextItem: (id) => request("DELETE", `/api/v1/context/${id}`),
4033
+ getContextItem: (id2) => get(`/api/v1/context/${id2}`),
4034
+ updateContextItem: (id2, body) => request("PATCH", `/api/v1/context/${id2}`, body),
4035
+ deleteContextItem: (id2) => request("DELETE", `/api/v1/context/${id2}`),
4036
4036
  /** Atomic append to a prompt item's body (blank-line separated). */
4037
- appendContextItem: (id, body) => request("POST", `/api/v1/context/${id}/append`, body),
4037
+ appendContextItem: (id2, body) => request("POST", `/api/v1/context/${id2}/append`, body),
4038
4038
  /** Effective context for an issue: the assembled bundle. */
4039
4039
  getIssueContext: (issueId) => get(`/api/v1/issues/${issueId}/context`),
4040
4040
  /**
@@ -4114,44 +4114,44 @@ function createApiClient(options) {
4114
4114
  // Runners
4115
4115
  listRunners: () => get("/api/v1/runners"),
4116
4116
  createRunner: (body) => request("POST", "/api/v1/runners", body),
4117
- getRunner: (id) => get(`/api/v1/runners/${id}`),
4118
- updateRunner: (id, body) => request("PATCH", `/api/v1/runners/${id}`, body),
4117
+ getRunner: (id2) => get(`/api/v1/runners/${id2}`),
4118
+ updateRunner: (id2, body) => request("PATCH", `/api/v1/runners/${id2}`, body),
4119
4119
  /** Reject-by-default: 422 names referencing rules/pins unless `force`. */
4120
- deleteRunner: (id, body) => request("DELETE", `/api/v1/runners/${id}`, body),
4120
+ deleteRunner: (id2, body) => request("DELETE", `/api/v1/runners/${id2}`, body),
4121
4121
  /** Create/reconnect a local runner; the response's token is shown once. */
4122
4122
  registerRunner: (body) => request("POST", "/api/v1/runners/register", body),
4123
4123
  /** Invalidate the runner token and mint a fresh one (shown once). */
4124
- rotateRunnerToken: (id) => request("POST", `/api/v1/runners/${id}/rotate-token`),
4124
+ rotateRunnerToken: (id2) => request("POST", `/api/v1/runners/${id2}/rotate-token`),
4125
4125
  // Local runner protocol (runner-token auth: construct the client with
4126
4126
  // the runner token as `apiKey`)
4127
- pollRunner: (id, body) => request("POST", `/api/v1/runners/${id}/poll`, body),
4127
+ pollRunner: (id2, body) => request("POST", `/api/v1/runners/${id2}/poll`, body),
4128
4128
  appendRunLog: (runId, body) => request("POST", `/api/v1/runs/${runId}/logs`, body),
4129
4129
  finishRun: (runId, body) => request("POST", `/api/v1/runs/${runId}/finish`, body),
4130
4130
  // Agent runs
4131
4131
  listRuns: (filters = {}) => get(`/api/v1/runs${query(filters)}`),
4132
- getRun: (id) => get(`/api/v1/runs/${id}`),
4132
+ getRun: (id2) => get(`/api/v1/runs/${id2}`),
4133
4133
  /**
4134
4134
  * The run's complete log (not the 256 KB tail `getRun` returns) as a
4135
4135
  * streamed Response, so a multi-megabyte log never has to be held in
4136
4136
  * memory. `raw` asks for the unrendered harness stream instead.
4137
4137
  */
4138
- getRunLogFull: (id, opts = {}) => raw("GET", `/api/v1/runs/${id}/log${opts.raw ? "?raw=1" : ""}`, {
4138
+ getRunLogFull: (id2, opts = {}) => raw("GET", `/api/v1/runs/${id2}/log${opts.raw ? "?raw=1" : ""}`, {
4139
4139
  headers: { accept: "text/plain" }
4140
4140
  }),
4141
4141
  /** Daemon-only: uploads the raw harness stream for a settled run. */
4142
- putRunLogRaw: (id, body) => raw("PUT", `/api/v1/runs/${id}/log/raw`, {
4142
+ putRunLogRaw: (id2, body) => raw("PUT", `/api/v1/runs/${id2}/log/raw`, {
4143
4143
  body,
4144
4144
  headers: {
4145
4145
  "content-type": "application/x-ndjson",
4146
4146
  "content-length": String(body.byteLength)
4147
4147
  }
4148
4148
  }),
4149
- cancelRun: (id) => request("POST", `/api/v1/runs/${id}/cancel`),
4149
+ cancelRun: (id2) => request("POST", `/api/v1/runs/${id2}/cancel`),
4150
4150
  // Routing rules (one per exact scope; responses carry shadow hints)
4151
4151
  listRoutingRules: () => get("/api/v1/routing-rules"),
4152
4152
  createRoutingRule: (body) => request("POST", "/api/v1/routing-rules", body),
4153
- updateRoutingRule: (id, body) => request("PATCH", `/api/v1/routing-rules/${id}`, body),
4154
- deleteRoutingRule: (id) => request("DELETE", `/api/v1/routing-rules/${id}`),
4153
+ updateRoutingRule: (id2, body) => request("PATCH", `/api/v1/routing-rules/${id2}`, body),
4154
+ deleteRoutingRule: (id2) => request("DELETE", `/api/v1/routing-rules/${id2}`),
4155
4155
  // Supervisor settings
4156
4156
  getPreferences: () => get("/api/v1/preferences"),
4157
4157
  updatePreferences: (body) => request("PATCH", "/api/v1/preferences", body),
@@ -4161,15 +4161,109 @@ function createApiClient(options) {
4161
4161
  // API keys (create/revoke require a browser session, not a key)
4162
4162
  listApiKeys: (filters = {}) => get(`/api/v1/api-keys${query(filters)}`),
4163
4163
  createApiKey: (body) => request("POST", "/api/v1/api-keys", body),
4164
- revokeApiKey: (id) => request("DELETE", `/api/v1/api-keys/${id}`),
4164
+ revokeApiKey: (id2) => request("DELETE", `/api/v1/api-keys/${id2}`),
4165
+ exportWorkflowPackage: (id2, opts = {}) => {
4166
+ const params = new URLSearchParams();
4167
+ if (opts.source_project_id) params.set("source_project_id", opts.source_project_id);
4168
+ for (const id3 of opts.schedule_ids ?? []) params.append("schedule_id", id3);
4169
+ for (const tier of opts.tiers ?? []) params.append("tier", JSON.stringify(tier));
4170
+ if (opts.authoring) params.set("authoring", JSON.stringify(opts.authoring));
4171
+ return get(
4172
+ `/api/v1/workflows/${encodeURIComponent(id2)}/export${params.size ? "?" + params : ""}`
4173
+ );
4174
+ },
4175
+ prepareWorkflowPackage: (body) => request(
4176
+ "POST",
4177
+ "/api/v1/library/prepare",
4178
+ body
4179
+ ),
4180
+ validateLibrary: (body) => request(
4181
+ "POST",
4182
+ "/api/v1/library/validate",
4183
+ body
4184
+ ),
4165
4185
  // Library export / import (workflows + context; no tracker data, no secrets)
4166
- exportLibrary: (opts = {}) => get(`/api/v1/export${opts.journals === false ? "?journals=false" : ""}`),
4186
+ exportLibrary: (opts = {}) => get(
4187
+ `/api/v1/export${query(opts)}`
4188
+ ),
4167
4189
  /** Plan-then-apply; `dry_run: true` returns the preview the apply follows. */
4168
4190
  importLibrary: (body) => request("POST", "/api/v1/import", body)
4169
4191
  };
4170
4192
  }
4171
4193
 
4172
4194
  // ../shared/src/schedule.ts
4195
+ var ScheduleInputError = class extends Error {
4196
+ constructor(message3) {
4197
+ super(message3);
4198
+ this.name = "ScheduleInputError";
4199
+ }
4200
+ };
4201
+ function parseField(spec, fieldName, min, max, normalize = (n) => n) {
4202
+ const values = /* @__PURE__ */ new Set();
4203
+ let restricted = false;
4204
+ const fail = (why) => {
4205
+ throw new ScheduleInputError(`Invalid cron ${fieldName} field "${spec}": ${why}`);
4206
+ };
4207
+ for (const item of spec.split(",")) {
4208
+ const match = item.match(/^(\*|\d+|\d+-\d+)(?:\/(\d+))?$/);
4209
+ if (!match) fail(`"${item}" is not a number, range, "*", or step`);
4210
+ const [, base, stepRaw] = match;
4211
+ const step = stepRaw === void 0 ? 1 : Number.parseInt(stepRaw, 10);
4212
+ if (step < 1) fail("step must be at least 1");
4213
+ let lo;
4214
+ let hi;
4215
+ if (base === "*") {
4216
+ lo = min;
4217
+ hi = max;
4218
+ if (stepRaw !== void 0) restricted = true;
4219
+ } else if (base.includes("-")) {
4220
+ const [a, b] = base.split("-").map((n) => Number.parseInt(n, 10));
4221
+ lo = a;
4222
+ hi = b;
4223
+ restricted = true;
4224
+ } else {
4225
+ lo = hi = Number.parseInt(base, 10);
4226
+ restricted = true;
4227
+ if (stepRaw !== void 0) fail('a step needs a range or "*" before the "/"');
4228
+ }
4229
+ if (lo < min || hi > max) fail(`values must be between ${min} and ${max}`);
4230
+ if (lo > hi) fail(`range ${lo}-${hi} is backwards`);
4231
+ for (let v = lo; v <= hi; v += step) values.add(normalize(v));
4232
+ }
4233
+ return { values, restricted };
4234
+ }
4235
+ function parseCron(expr) {
4236
+ const fields = expr.trim().split(/\s+/);
4237
+ if (fields.length !== 5) {
4238
+ throw new ScheduleInputError(
4239
+ `Cron expression "${expr.trim()}" must have 5 fields (minute hour day-of-month month day-of-week), got ${fields.length}`
4240
+ );
4241
+ }
4242
+ const [m, h, dom, mon, dow] = fields;
4243
+ const minutes = parseField(m, "minute", 0, 59);
4244
+ const hours = parseField(h, "hour", 0, 23);
4245
+ const days = parseField(dom, "day-of-month", 1, 31);
4246
+ const months = parseField(mon, "month", 1, 12);
4247
+ const weekdays = parseField(dow, "day-of-week", 0, 7, (n) => n % 7);
4248
+ return {
4249
+ minutes: minutes.values,
4250
+ hours: hours.values,
4251
+ days: days.values,
4252
+ months: months.values,
4253
+ weekdays: weekdays.values,
4254
+ dayRestricted: days.restricted,
4255
+ weekdayRestricted: weekdays.restricted
4256
+ };
4257
+ }
4258
+ function validateScheduleCron(expr) {
4259
+ const parsed = parseCron(expr);
4260
+ if (parsed.minutes.size > 1) {
4261
+ throw new ScheduleInputError(
4262
+ `Cron expression "${expr.trim()}" would fire more often than once per hour; the minute field must be a single value`
4263
+ );
4264
+ }
4265
+ return parsed;
4266
+ }
4173
4267
  var WEEKDAY_NAMES = [
4174
4268
  "Sunday",
4175
4269
  "Monday",
@@ -4179,24 +4273,79 @@ var WEEKDAY_NAMES = [
4179
4273
  "Friday",
4180
4274
  "Saturday"
4181
4275
  ];
4182
- function describeRecurrence(preset, cron) {
4183
- if (preset) {
4184
- switch (preset.kind) {
4276
+ function parseTimeOfDay(time) {
4277
+ const match = typeof time === "string" ? time.match(/^(\d{1,2}):(\d{2})$/) : null;
4278
+ if (match) {
4279
+ const hour = Number.parseInt(match[1], 10);
4280
+ const minute = Number.parseInt(match[2], 10);
4281
+ if (hour <= 23 && minute <= 59) return { hour, minute };
4282
+ }
4283
+ throw new ScheduleInputError(`Preset time must be "HH:MM" (24-hour), got "${String(time)}"`);
4284
+ }
4285
+ function compilePreset(preset2) {
4286
+ if (preset2.kind === "hourly") {
4287
+ const every = preset2.every_hours;
4288
+ if (typeof every !== "number" || !Number.isInteger(every) || every < 1 || every > 23) {
4289
+ throw new ScheduleInputError("Hourly preset needs an every_hours between 1 and 23");
4290
+ }
4291
+ const minute2 = preset2.minute ?? 0;
4292
+ if (typeof minute2 !== "number" || !Number.isInteger(minute2) || minute2 < 0 || minute2 > 59) {
4293
+ throw new ScheduleInputError("Hourly preset minute must be between 0 and 59");
4294
+ }
4295
+ return every === 1 ? `${minute2} * * * *` : `${minute2} */${every} * * *`;
4296
+ }
4297
+ const { hour, minute } = parseTimeOfDay(preset2.time);
4298
+ switch (preset2.kind) {
4299
+ case "daily":
4300
+ return `${minute} ${hour} * * *`;
4301
+ case "weekly": {
4302
+ const weekday = preset2.weekday;
4303
+ if (typeof weekday !== "number" || !Number.isInteger(weekday) || weekday < 0 || weekday > 6) {
4304
+ throw new ScheduleInputError(
4305
+ "Weekly preset needs a weekday between 0 (Sunday) and 6 (Saturday)"
4306
+ );
4307
+ }
4308
+ return `${minute} ${hour} * * ${weekday}`;
4309
+ }
4310
+ case "monthly": {
4311
+ const day = preset2.day_of_month;
4312
+ if (typeof day !== "number" || !Number.isInteger(day) || day < 1 || day > 31) {
4313
+ throw new ScheduleInputError("Monthly preset needs a day_of_month between 1 and 31");
4314
+ }
4315
+ return `${minute} ${hour} ${day} * *`;
4316
+ }
4317
+ default:
4318
+ throw new ScheduleInputError(
4319
+ `Unknown preset kind "${String(preset2.kind)}"; expected hourly, daily, weekly, or monthly`
4320
+ );
4321
+ }
4322
+ }
4323
+ function describeRecurrence(preset2, cron) {
4324
+ if (preset2) {
4325
+ switch (preset2.kind) {
4185
4326
  case "hourly": {
4186
- const every = preset.every_hours ?? 1;
4187
- const at = preset.minute ? ` at :${String(preset.minute).padStart(2, "0")}` : "";
4327
+ const every = preset2.every_hours ?? 1;
4328
+ const at = preset2.minute ? ` at :${String(preset2.minute).padStart(2, "0")}` : "";
4188
4329
  return every === 1 ? `Every hour${at}` : `Every ${every} hours${at}`;
4189
4330
  }
4190
4331
  case "daily":
4191
- return `Every day at ${preset.time}`;
4332
+ return `Every day at ${preset2.time}`;
4192
4333
  case "weekly":
4193
- return `Every ${WEEKDAY_NAMES[preset.weekday ?? 0]} at ${preset.time}`;
4334
+ return `Every ${WEEKDAY_NAMES[preset2.weekday ?? 0]} at ${preset2.time}`;
4194
4335
  case "monthly":
4195
- return `Monthly on day ${preset.day_of_month} at ${preset.time}`;
4336
+ return `Monthly on day ${preset2.day_of_month} at ${preset2.time}`;
4196
4337
  }
4197
4338
  }
4198
4339
  return `Cron \u201C${cron}\u201D`;
4199
4340
  }
4341
+ function validateTimezone(tz) {
4342
+ try {
4343
+ new Intl.DateTimeFormat("en-US", { timeZone: tz });
4344
+ return tz;
4345
+ } catch {
4346
+ throw new ScheduleInputError(`Unknown timezone "${tz}"; use an IANA name like "Europe/London"`);
4347
+ }
4348
+ }
4200
4349
  var PLACEHOLDER_DESCRIPTIONS = {
4201
4350
  date: "run date, e.g. 2026-08-23",
4202
4351
  time: "run time, e.g. 09:30",
@@ -4242,6 +4391,136 @@ async function listAll(fetchPage, opts = {}) {
4242
4391
  // ../shared/src/routing.ts
4243
4392
  var INHERIT_RUNNER_ID = "*";
4244
4393
 
4394
+ // ../shared/src/library/types.ts
4395
+ var LibraryValidationError = class extends Error {
4396
+ constructor(diagnostics) {
4397
+ super(diagnostics[0]?.message ?? "Invalid library document");
4398
+ this.diagnostics = diagnostics;
4399
+ this.name = "LibraryValidationError";
4400
+ }
4401
+ diagnostics;
4402
+ };
4403
+
4404
+ // ../shared/src/library/schema.ts
4405
+ var pointer = (path2, key) => `${path2}/${String(key).replaceAll("~", "~0").replaceAll("/", "~1")}`;
4406
+ function invalid(path2, code, message3) {
4407
+ throw new LibraryValidationError([{ path: path2, code, message: message3 }]);
4408
+ }
4409
+ function validateUnicode(value, path2) {
4410
+ for (let i = 0; i < value.length; i++) {
4411
+ const unit = value.charCodeAt(i);
4412
+ if (unit >= 55296 && unit <= 56319) {
4413
+ const next = value.charCodeAt(++i);
4414
+ if (!(next >= 56320 && next <= 57343))
4415
+ invalid(path2, "invalid_unicode", "Lone UTF-16 surrogate is not allowed");
4416
+ } else if (unit >= 56320 && unit <= 57343)
4417
+ invalid(path2, "invalid_unicode", "Lone UTF-16 surrogate is not allowed");
4418
+ }
4419
+ }
4420
+ var text2 = (max, nonempty = false) => (v, p) => {
4421
+ if (typeof v !== "string") invalid(p, "invalid_type", "Expected a string");
4422
+ validateUnicode(v, p);
4423
+ if (v.length > max || nonempty && !v.trim())
4424
+ invalid(
4425
+ p,
4426
+ "invalid_field",
4427
+ `Expected ${nonempty ? "non-empty " : ""}text of at most ${max} characters`
4428
+ );
4429
+ };
4430
+ var bool = (v, p) => {
4431
+ if (typeof v !== "boolean") invalid(p, "invalid_type", "Expected a boolean");
4432
+ };
4433
+ var integer = (v, p) => {
4434
+ if (!Number.isSafeInteger(v) || v < 0)
4435
+ invalid(p, "invalid_integer", "Expected a non-negative safe integer");
4436
+ };
4437
+ var oneOf = (values) => (v, p) => {
4438
+ if (!values.includes(v)) invalid(p, "invalid_value", `Expected one of ${values.join(", ")}`);
4439
+ };
4440
+ var nullable = (check) => (v, p) => {
4441
+ if (v !== null) check(v, p);
4442
+ };
4443
+ function object(v, p) {
4444
+ if (!v || typeof v !== "object" || Array.isArray(v) || ![null, Object.prototype].includes(Object.getPrototypeOf(v)))
4445
+ invalid(p, "invalid_type", "Expected a plain object");
4446
+ return v;
4447
+ }
4448
+ var shape = (required, optional = {}) => (v, p) => {
4449
+ const o = object(v, p);
4450
+ for (const key of Object.keys(o)) {
4451
+ validateUnicode(key, pointer(p, key));
4452
+ if (!Object.hasOwn(required, key) && !Object.hasOwn(optional, key))
4453
+ invalid(pointer(p, key), "unknown_field", `Unknown field ${key}`);
4454
+ }
4455
+ for (const [key, check] of Object.entries(required)) {
4456
+ if (!Object.hasOwn(o, key))
4457
+ invalid(pointer(p, key), "missing_field", `Missing required field ${key}`);
4458
+ check(o[key], pointer(p, key));
4459
+ }
4460
+ for (const [key, check] of Object.entries(optional))
4461
+ if (Object.hasOwn(o, key)) check(o[key], pointer(p, key));
4462
+ };
4463
+ var discriminated = (key, variants) => (v, p) => {
4464
+ const o = object(v, p);
4465
+ if (typeof o[key] !== "string" || !Object.hasOwn(variants, o[key]))
4466
+ invalid(pointer(p, key), "invalid_discriminator", `Unknown ${key}`);
4467
+ variants[o[key]](v, p);
4468
+ };
4469
+ var id = (v, p) => {
4470
+ text2(80, true)(v, p);
4471
+ if (!/^[A-Za-z0-9:_-]{1,80}$/.test(v))
4472
+ invalid(p, "invalid_local_id", "Invalid document-local ID");
4473
+ };
4474
+ var bundledState = shape({ kind: oneOf(["bundled_state"]), state_id: id });
4475
+ var systemState = shape({
4476
+ kind: oneOf(["system_state"]),
4477
+ workflow: oneOf(["Standard"]),
4478
+ state_name: text2(100, true)
4479
+ });
4480
+ var bundledWorkflow = shape({ kind: oneOf(["bundled_workflow"]), workflow_id: id });
4481
+ var projectRef = shape({ kind: oneOf(["input_project"]), input_id: id });
4482
+ var preset = discriminated("kind", {
4483
+ hourly: shape({ kind: oneOf(["hourly"]), every_hours: integer }, { minute: integer }),
4484
+ daily: shape({ kind: oneOf(["daily"]), time: text2(5, true) }),
4485
+ weekly: shape({ kind: oneOf(["weekly"]), time: text2(5, true), weekday: integer }),
4486
+ monthly: shape({ kind: oneOf(["monthly"]), time: text2(5, true), day_of_month: integer })
4487
+ });
4488
+ var recurrence = (v, p) => {
4489
+ discriminated("kind", {
4490
+ preset: shape({ kind: oneOf(["preset"]), preset }),
4491
+ cron: shape({ kind: oneOf(["cron"]), cron: text2(100, true) })
4492
+ })(v, p);
4493
+ const o = v;
4494
+ try {
4495
+ validateScheduleCron(o.kind === "preset" ? compilePreset(o.preset) : o.cron);
4496
+ } catch (e) {
4497
+ invalid(p, "invalid_recurrence", e.message);
4498
+ }
4499
+ };
4500
+ var timezone = (v, p) => {
4501
+ text2(100, true)(v, p);
4502
+ try {
4503
+ validateTimezone(v);
4504
+ } catch (e) {
4505
+ invalid(p, "invalid_timezone", e.message);
4506
+ }
4507
+ };
4508
+ var schedule = shape({
4509
+ id,
4510
+ workflow: bundledWorkflow,
4511
+ project: projectRef,
4512
+ name: text2(200, true),
4513
+ title_template: text2(500, true),
4514
+ description_template: text2(1e5),
4515
+ recurrence,
4516
+ timezone,
4517
+ require_all_closed: bool,
4518
+ start_state: nullable(bundledState)
4519
+ });
4520
+
4521
+ // ../shared/src/library/choices.ts
4522
+ var PACKAGE_CHOICES_MAX_BYTES = 512 * 1024;
4523
+
4245
4524
  // src/format.ts
4246
4525
  function timestamp(ms) {
4247
4526
  return new Date(ms).toISOString().replace("T", " ").slice(0, 19);
@@ -4258,8 +4537,8 @@ function contextItemSummary(item) {
4258
4537
  return item.artifact_type ?? "artifact";
4259
4538
  }
4260
4539
  }
4261
- function recurrenceLabel(schedule) {
4262
- return `${describeRecurrence(schedule.preset, schedule.cron)}, ${schedule.timezone}`;
4540
+ function recurrenceLabel(schedule2) {
4541
+ return `${describeRecurrence(schedule2.preset, schedule2.cron)}, ${schedule2.timezone}`;
4263
4542
  }
4264
4543
  function issueRef(ref) {
4265
4544
  return `${ref.project_name}/${ref.number}`;
@@ -4365,7 +4644,7 @@ function ruleTargetsLabel(rule) {
4365
4644
  function quotaLabel(quota, stateName) {
4366
4645
  if (quota.type === "global_cap") return `global cap: at most ${quota.limit} concurrent runs`;
4367
4646
  const overrides = Object.entries(quota.overrides).map(
4368
- ([id, limit]) => `${stateName ? stateName(id) : id}=${limit}`
4647
+ ([id2, limit]) => `${stateName ? stateName(id2) : id2}=${limit}`
4369
4648
  );
4370
4649
  return `state roster: default ${quota.default_limit} per state${overrides.length > 0 ? `, overrides: ${overrides.join(", ")}` : ""}`;
4371
4650
  }
@@ -4899,8 +5178,8 @@ function register(program3) {
4899
5178
  );
4900
5179
  withCommon(
4901
5180
  context.command("show <id>").description("Show a context item (skills include their files)")
4902
- ).action(async (id, opts) => {
4903
- const item = await client(opts).getContextItem(id);
5181
+ ).action(async (id2, opts) => {
5182
+ const item = await client(opts).getContextItem(id2);
4904
5183
  if (opts.json) return printJson(item);
4905
5184
  printContextItem(item);
4906
5185
  });
@@ -4954,7 +5233,7 @@ function register(program3) {
4954
5233
  )
4955
5234
  )
4956
5235
  ).action(
4957
- async (id, opts) => {
5236
+ async (id2, opts) => {
4958
5237
  const api = client(opts);
4959
5238
  const body = {};
4960
5239
  if (opts.expectVersion !== void 0) body.expected_version = opts.expectVersion;
@@ -4971,7 +5250,7 @@ function register(program3) {
4971
5250
  }
4972
5251
  if (opts.body !== void 0) body.body = readBodyValue(opts.body);
4973
5252
  if (opts.file.length > 0 || opts.removeFile.length > 0) {
4974
- const current = await api.getContextItem(id);
5253
+ const current = await api.getContextItem(id2);
4975
5254
  if (current.kind !== "skill")
4976
5255
  die(`--file/--remove-file only apply to skills (this is a ${current.kind})`);
4977
5256
  if (body.expected_version === void 0) body.expected_version = current.version;
@@ -4997,16 +5276,16 @@ function register(program3) {
4997
5276
  "nothing to update: pass payload flags, --name/--description, scope flags, and/or --unset"
4998
5277
  );
4999
5278
  }
5000
- const item = await api.updateContextItem(id, body);
5279
+ const item = await api.updateContextItem(id2, body);
5001
5280
  if (opts.json) return printJson(item);
5002
5281
  console.log(`updated ${item.kind} "${item.name}" (${item.id}) \u2014 scope: ${item.scope.label}`);
5003
5282
  }
5004
5283
  );
5005
5284
  withCommon(context.command("delete <id>").description("Delete a context item")).action(
5006
- async (id, opts) => {
5285
+ async (id2, opts) => {
5007
5286
  const api = client(opts);
5008
- const item = await api.getContextItem(id);
5009
- await api.deleteContextItem(id);
5287
+ const item = await api.getContextItem(id2);
5288
+ await api.deleteContextItem(id2);
5010
5289
  console.log(`deleted ${item.kind} "${item.name}" (${item.id}) \u2014 scope: ${item.scope.label}`);
5011
5290
  }
5012
5291
  );
@@ -5048,11 +5327,12 @@ var CHANGE_LABEL = {
5048
5327
  removed: "removed with source",
5049
5328
  retained: "retained",
5050
5329
  rescoped: "moves with the issue",
5051
- replaced: "overridden at destination"
5330
+ replaced: "effective selection changes"
5052
5331
  };
5053
5332
  function inspectableChanges(preview) {
5054
- return preview.context.changes.filter((c) => c.change !== "retained");
5333
+ return preview.context.changes;
5055
5334
  }
5335
+ var effectiveness = (present, effective) => !present ? "not present" : effective ? "effective" : "overridden candidate";
5056
5336
  function repoLine(change) {
5057
5337
  if (change.kind !== "repo") return null;
5058
5338
  const before = change.repo_before;
@@ -5074,16 +5354,85 @@ function routingLines(preview) {
5074
5354
  lines.push(`${label}: ${explainer.verdict}`);
5075
5355
  if (explainer.pin) {
5076
5356
  lines.push(
5077
- ` pinned runner ${explainer.pin.runner_name ?? explainer.pin.runner_id}${explainer.pin.tier ? ` (${explainer.pin.tier})` : ""} \u2014 retained by the move`
5357
+ ` pin: runner ${explainer.pin.runner_name ?? explainer.pin.runner_id}, tier ${explainer.pin.tier ?? "default"}`
5358
+ );
5359
+ }
5360
+ for (const check of explainer.checks) {
5361
+ lines.push(
5362
+ ` ${check.ok ? "pass" : "FAIL"} ${check.name}: ${check.detail}${check.action?.label ? ` (${check.action.label})` : ""}`
5078
5363
  );
5079
5364
  }
5365
+ if (explainer.matched_rule)
5366
+ lines.push(` matched rule ${explainer.matched_rule.scope_label}`);
5080
5367
  for (const tie of explainer.ambiguous_rules) {
5081
5368
  lines.push(` tied rule ${tie.scope_label}`);
5082
5369
  }
5370
+ if (explainer.runner_rule)
5371
+ lines.push(` runner source rule ${explainer.runner_rule.scope_label}`);
5372
+ if (explainer.tier_override) lines.push(` tier override ${explainer.tier_override}`);
5373
+ for (const target of explainer.targets) {
5374
+ lines.push(
5375
+ ` target ${target.runner_name} \u2014 ${target.tier}${target.model ? ` / ${target.model}` : ""}: ${target.verdict} \u2014 ${target.detail}`
5376
+ );
5377
+ }
5378
+ if (explainer.active_run)
5379
+ lines.push(
5380
+ ` active run ${explainer.active_run.id} (${explainer.active_run.status})`
5381
+ );
5382
+ if (explainer.queue_position !== null)
5383
+ lines.push(` queue position ${explainer.queue_position}`);
5384
+ lines.push(
5385
+ ` attempts ${explainer.attempt_count}/${explainer.attempt_limit}; parked ${explainer.parked ? "yes" : "no"}`
5386
+ );
5083
5387
  }
5084
5388
  lines.push(" Capacity, heartbeats and spending are advisory and may change at any moment.");
5085
5389
  return lines;
5086
5390
  }
5391
+ function repoDetail(repo) {
5392
+ return `${repo.url}; branch ${repo.branch ?? "repository default branch"}; directory ${repo.dir}`;
5393
+ }
5394
+ function effectiveRepositoryLines(preview) {
5395
+ const lines = ["", "Effective repositories:"];
5396
+ for (const [label, context] of [
5397
+ [" before", preview.context.before],
5398
+ [" after ", preview.context.after]
5399
+ ]) {
5400
+ lines.push(`${label}:`);
5401
+ if (!context.repos.length) lines.push(" none");
5402
+ for (const repo of context.repos) {
5403
+ lines.push(` ${repo.name} \u2014 effective (${repo.scope.label})`);
5404
+ lines.push(` ${repoDetail(repo)}`);
5405
+ for (const loser of context.overridden.filter(
5406
+ (item) => item.kind === "repo" && item.name === repo.name
5407
+ )) {
5408
+ lines.push(
5409
+ ` overridden candidate ${loser.name} (${loser.scope.label}) \u2014 overridden by ${loser.overridden_by}`
5410
+ );
5411
+ lines.push(
5412
+ ` ${loser.repo ? repoDetail(loser.repo) : "checkout details unavailable from this server"}`
5413
+ );
5414
+ }
5415
+ }
5416
+ }
5417
+ return lines;
5418
+ }
5419
+ function conflictLines(preview) {
5420
+ const lines = ["", "Repository checkout conflicts:"];
5421
+ for (const [label, context] of [
5422
+ [" before", preview.context.before],
5423
+ [" after ", preview.context.after]
5424
+ ]) {
5425
+ if (!context.conflicts.length) lines.push(`${label}: none`);
5426
+ for (const conflict of context.conflicts) {
5427
+ const participants = conflict.item_ids.map((id2) => {
5428
+ const repo = context.repos.find((item) => item.item_id === id2);
5429
+ return repo ? `${repo.name} (${repo.scope.label})` : id2;
5430
+ }).join(", ");
5431
+ lines.push(`${label}: ${conflict.dir} \u2014 ${participants}`);
5432
+ }
5433
+ }
5434
+ return lines;
5435
+ }
5087
5436
  function formatTransferPreview(preview) {
5088
5437
  const p = preview.preserved;
5089
5438
  const lines = [
@@ -5097,20 +5446,19 @@ function formatTransferPreview(preview) {
5097
5446
  ` pins: ${p.pinned_runner_id ?? "none"}${p.pinned_tier ? ` (${p.pinned_tier})` : ""}; attempts ${p.attempt_count}${p.parked ? "; parked" : ""}`
5098
5447
  ];
5099
5448
  const changes = inspectableChanges(preview);
5100
- lines.push("", changes.length ? "Guidance changes:" : "Guidance: unchanged by this move.");
5449
+ lines.push("", changes.length ? "Guidance:" : "Guidance: none.");
5101
5450
  changes.forEach((change, index) => {
5102
5451
  lines.push(` [${index}] ${change.kind} "${change.name}" \u2014 ${CHANGE_LABEL[change.change]}`);
5103
5452
  const scopeBefore = change.scope_before?.label ?? "\u2014";
5104
5453
  const scopeAfter = change.scope_after?.label ?? "\u2014";
5105
5454
  lines.push(` scope: ${scopeBefore} => ${scopeAfter}`);
5455
+ lines.push(
5456
+ ` before: ${effectiveness(Boolean(change.scope_before), change.effective_before)}; after: ${effectiveness(Boolean(change.scope_after), change.effective_after)}`
5457
+ );
5106
5458
  const repo = repoLine(change);
5107
5459
  if (repo) lines.push(repo);
5108
5460
  });
5109
- for (const conflict of preview.context.after.conflicts) {
5110
- lines.push(
5111
- ` ! ${conflict.item_ids.length} repositories still want the "${conflict.dir}" directory at the destination`
5112
- );
5113
- }
5461
+ lines.push(...effectiveRepositoryLines(preview), ...conflictLines(preview));
5114
5462
  lines.push(...routingLines(preview));
5115
5463
  if (preview.schedule) {
5116
5464
  lines.push(
@@ -5133,11 +5481,24 @@ function formatTransferPreview(preview) {
5133
5481
  function formatTransferItem(preview, index) {
5134
5482
  const change = inspectableChanges(preview)[index];
5135
5483
  if (!change) return `no item [${index}] in this review`;
5136
- const side = change.change === "removed" ? preview.context.before : preview.context.after;
5137
- const prompt = side.prompt.parts.find((part) => part.item_id === change.item_id);
5138
- if (prompt) return `${change.name} (prompt, ${prompt.scope.label})
5139
- ${prompt.body}`;
5140
- const skill = side.skills.find((s) => s.item_id === change.item_id);
5484
+ const beforePrompt = preview.context.before.prompt.parts.find(
5485
+ (part) => part.item_id === change.item_id
5486
+ );
5487
+ const afterPrompt = preview.context.after.prompt.parts.find(
5488
+ (part) => part.item_id === change.item_id
5489
+ );
5490
+ if (beforePrompt || afterPrompt) {
5491
+ if (beforePrompt?.body === afterPrompt?.body)
5492
+ return `${change.name} (prompt, Before and after)
5493
+ ${beforePrompt?.body ?? afterPrompt?.body}`;
5494
+ return [
5495
+ beforePrompt ? `${change.name} (prompt, Before \u2014 ${beforePrompt.scope.label})
5496
+ ${beforePrompt.body}` : "",
5497
+ afterPrompt ? `${change.name} (prompt, After \u2014 ${afterPrompt.scope.label})
5498
+ ${afterPrompt.body}` : ""
5499
+ ].filter(Boolean).join("\n\n");
5500
+ }
5501
+ const skill = preview.context.after.skills.find((s) => s.item_id === change.item_id) ?? preview.context.before.skills.find((s) => s.item_id === change.item_id);
5141
5502
  if (skill) {
5142
5503
  return [
5143
5504
  `${change.name} (skill, ${skill.scope.label})`,
@@ -5145,11 +5506,17 @@ ${prompt.body}`;
5145
5506
  ${f.content}`)
5146
5507
  ].join("\n");
5147
5508
  }
5148
- const repo = side.repos.find((r) => r.item_id === change.item_id);
5149
- if (repo)
5150
- return `${change.name} (repo, ${repo.scope.label})
5151
- ${repo.url} ${repo.branch ?? ""} \u2192 ${repo.dir}`;
5152
- return `${change.name} (${change.kind}) is not effective on either side; nothing to show.`;
5509
+ const repo = preview.context.after.repos.find((r) => r.item_id === change.item_id) ?? preview.context.before.repos.find((r) => r.item_id === change.item_id);
5510
+ if (repo) return `${change.name} (repo, ${repo.scope.label})
5511
+ ${repoDetail(repo)}`;
5512
+ const candidate = [
5513
+ ...preview.context.after.overridden,
5514
+ ...preview.context.before.overridden
5515
+ ].find((item) => item.item_id === change.item_id);
5516
+ if (candidate?.repo)
5517
+ return `${change.name} (overridden repo candidate, ${candidate.scope.label})
5518
+ ${repoDetail(candidate.repo)}`;
5519
+ return `${change.name} (${change.kind}) is an overridden candidate; content details are unavailable from this server.`;
5153
5520
  }
5154
5521
  function formatTransferResult(result) {
5155
5522
  if (result.status === "noop") {
@@ -5832,17 +6199,17 @@ function register2(program3) {
5832
6199
  []
5833
6200
  )
5834
6201
  ).action(
5835
- async (projectRef, opts) => {
6202
+ async (projectRef2, opts) => {
5836
6203
  const description = opts.description !== void 0 ? readBodyValue(opts.description) : void 0;
5837
6204
  const api = client(opts);
5838
- const project = await resolveProject(api, projectRef);
6205
+ const project = await resolveProject(api, projectRef2);
5839
6206
  const workflowId = opts.workflow ? (await resolveWorkflow(api, opts.workflow)).id : void 0;
5840
- const recurrence = buildRecurrence(opts);
5841
- if (!recurrence && (opts.ifClosed !== void 0 || opts.scheduleName !== void 0)) {
6207
+ const recurrence2 = buildRecurrence(opts);
6208
+ if (!recurrence2 && (opts.ifClosed !== void 0 || opts.scheduleName !== void 0)) {
5842
6209
  die('--if-closed/--schedule-name need a recurrence: add --every \u2026 or --cron "<expr>"');
5843
6210
  }
5844
- const schedule = recurrence ? {
5845
- ...recurrence,
6211
+ const schedule2 = recurrence2 ? {
6212
+ ...recurrence2,
5846
6213
  name: opts.scheduleName,
5847
6214
  timezone: opts.tz ?? systemTimezone(),
5848
6215
  require_all_closed: opts.ifClosed ?? false
@@ -5852,7 +6219,7 @@ function register2(program3) {
5852
6219
  description,
5853
6220
  workflow_id: workflowId,
5854
6221
  state: opts.state,
5855
- schedule,
6222
+ schedule: schedule2,
5856
6223
  labels: opts.label
5857
6224
  });
5858
6225
  if (opts.json) return printJson(issue);
@@ -5926,9 +6293,9 @@ function register2(program3) {
5926
6293
  const destination = await resolveProject(api, opts.project);
5927
6294
  let preview = await api.previewIssueTransfer(issue.id, destination.id);
5928
6295
  if (opts.inspect !== void 0) {
5929
- const text3 = formatTransferItem(preview, Number(opts.inspect));
5930
- if (opts.json) return printJson({ ...preview, inspected: text3 });
5931
- return console.log(text3);
6296
+ const text4 = formatTransferItem(preview, Number(opts.inspect));
6297
+ if (opts.json) return printJson({ ...preview, inspected: text4 });
6298
+ return console.log(text4);
5932
6299
  }
5933
6300
  if (opts.dryRun) {
5934
6301
  if (opts.json) return printJson(preview);
@@ -5959,7 +6326,7 @@ function register2(program3) {
5959
6326
  }
5960
6327
  const rl = interactive ? createInterface({ input: process.stdin, output: process.stderr }) : null;
5961
6328
  const terminal = {
5962
- write: (text3) => process.stderr.write(text3),
6329
+ write: (text4) => process.stderr.write(text4),
5963
6330
  ask: (question) => rl.question(question).catch(() => null)
5964
6331
  };
5965
6332
  try {
@@ -6631,12 +6998,12 @@ start one: tines journal append ${issue.project_name}/${issue.number} "- <date>:
6631
6998
  ).action(
6632
6999
  async (ref, markdown, opts, command) => {
6633
7000
  if (helpGuard(command, markdown)) return;
6634
- const text3 = readBodyValue(markdown);
7001
+ const text4 = readBodyValue(markdown);
6635
7002
  const api = client(opts);
6636
7003
  const { scope, note, item } = await resolveJournal(api, ref, opts.state);
6637
7004
  printNote(note);
6638
7005
  if (item) {
6639
- const updated = await api.appendContextItem(item.id, { text: text3 });
7006
+ const updated = await api.appendContextItem(item.id, { text: text4 });
6640
7007
  if (opts.json) return printJson(updated);
6641
7008
  return console.log(`appended to the ${scope.label} journal (now v${updated.version})`);
6642
7009
  }
@@ -6646,7 +7013,7 @@ start one: tines journal append ${issue.project_name}/${issue.number} "- <date>:
6646
7013
  name: JOURNAL_NAME,
6647
7014
  project_id: scope.project_id ?? void 0,
6648
7015
  workflow_state_id: scope.workflow_state_id ?? void 0,
6649
- body: text3.trim()
7016
+ body: text4.trim()
6650
7017
  });
6651
7018
  if (opts.json) return printJson(created);
6652
7019
  console.log(`started the ${scope.label} journal (${created.id})`);
@@ -6654,7 +7021,7 @@ start one: tines journal append ${issue.project_name}/${issue.number} "- <date>:
6654
7021
  if (!(err instanceof ApiError) || err.code !== "duplicate_context_name") throw err;
6655
7022
  const { item: fresh } = await resolveJournal(api, ref, opts.state);
6656
7023
  if (!fresh) throw err;
6657
- const updated = await api.appendContextItem(fresh.id, { text: text3 });
7024
+ const updated = await api.appendContextItem(fresh.id, { text: text4 });
6658
7025
  if (opts.json) return printJson(updated);
6659
7026
  console.log(`appended to the ${scope.label} journal (now v${updated.version})`);
6660
7027
  }
@@ -7374,10 +7741,10 @@ var ClaudeStreamRenderer = class {
7374
7741
  };
7375
7742
 
7376
7743
  // src/daemon/codex-stream.ts
7377
- function object(value) {
7744
+ function object2(value) {
7378
7745
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
7379
7746
  }
7380
- function text2(value) {
7747
+ function text3(value) {
7381
7748
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
7382
7749
  }
7383
7750
  function renderCodexEvent(event) {
@@ -7386,35 +7753,35 @@ function renderCodexEvent(event) {
7386
7753
  if (type === "turn.started") return ["[session] turn started"];
7387
7754
  if (type === "turn.completed") return ["[session] turn completed"];
7388
7755
  if (type === "turn.failed") {
7389
- const error = object(event.error);
7390
- return [`[error] ${clip(text2(error?.message) ?? text2(event.message) ?? "turn failed", 2e3)}`];
7756
+ const error = object2(event.error);
7757
+ return [`[error] ${clip(text3(error?.message) ?? text3(event.message) ?? "turn failed", 2e3)}`];
7391
7758
  }
7392
- if (type === "error") return [`[error] ${clip(text2(event.message) ?? "unknown error", 2e3)}`];
7759
+ if (type === "error") return [`[error] ${clip(text3(event.message) ?? "unknown error", 2e3)}`];
7393
7760
  if (type !== "item.completed") return [];
7394
- const item = object(event.item);
7761
+ const item = object2(event.item);
7395
7762
  if (!item) return [];
7396
7763
  switch (item.type) {
7397
7764
  case "agent_message":
7398
- return text2(item.text) ? [`[agent] ${clip(text2(item.text), 2e3)}`] : [];
7765
+ return text3(item.text) ? [`[agent] ${clip(text3(item.text), 2e3)}`] : [];
7399
7766
  case "command_execution": {
7400
- const command = text2(item.command) ?? "command";
7767
+ const command = text3(item.command) ?? "command";
7401
7768
  const failed = validMetric(item.exit_code) && item.exit_code !== 0;
7402
- const output = failed ? text2(item.aggregated_output) : void 0;
7769
+ const output = failed ? text3(item.aggregated_output) : void 0;
7403
7770
  return [
7404
7771
  `[tool] ${clip(command, 300)}${failed ? ` (exit ${item.exit_code}${output ? `: ${clip(output, 300)}` : ""})` : ""}`
7405
7772
  ];
7406
7773
  }
7407
7774
  case "file_change": {
7408
7775
  const changes = Array.isArray(item.changes) ? item.changes : [];
7409
- const paths = changes.map((change) => text2(object(change)?.path)).filter((path2) => Boolean(path2));
7776
+ const paths = changes.map((change) => text3(object2(change)?.path)).filter((path2) => Boolean(path2));
7410
7777
  return [`[tool] file change${paths.length ? `: ${clip(paths.join(", "), 300)}` : ""}`];
7411
7778
  }
7412
7779
  case "mcp_tool_call":
7413
7780
  return [
7414
- `[tool] ${clip([text2(item.server), text2(item.tool)].filter(Boolean).join("/") || "MCP call", 300)}`
7781
+ `[tool] ${clip([text3(item.server), text3(item.tool)].filter(Boolean).join("/") || "MCP call", 300)}`
7415
7782
  ];
7416
7783
  case "web_search":
7417
- return [`[tool] web search${text2(item.query) ? `: ${clip(text2(item.query), 300)}` : ""}`];
7784
+ return [`[tool] web search${text3(item.query) ? `: ${clip(text3(item.query), 300)}` : ""}`];
7418
7785
  default:
7419
7786
  return [];
7420
7787
  }
@@ -7451,7 +7818,7 @@ var CodexStreamRenderer = class {
7451
7818
  let event;
7452
7819
  try {
7453
7820
  const parsed = JSON.parse(trimmed);
7454
- const parsedObject = object(parsed);
7821
+ const parsedObject = object2(parsed);
7455
7822
  if (!parsedObject) return;
7456
7823
  event = parsedObject;
7457
7824
  } catch {
@@ -7468,7 +7835,7 @@ var CodexStreamRenderer = class {
7468
7835
  this.collected.providerSessionId = event.thread_id;
7469
7836
  }
7470
7837
  if (event.type !== "turn.completed") return;
7471
- const raw = object(event.usage);
7838
+ const raw = object2(event.usage);
7472
7839
  if (!raw) return;
7473
7840
  const totalInput = validMetric(raw.input_tokens) ? raw.input_tokens : void 0;
7474
7841
  const rawCached = validMetric(raw.cached_input_tokens) ? raw.cached_input_tokens : void 0;
@@ -7585,8 +7952,8 @@ function zonedDate(zone, at) {
7585
7952
  return { y: get("year"), m: get("month") - 1, d: get("day") };
7586
7953
  }
7587
7954
  var DURATION = /(\d+)\s*([dhms])/g;
7588
- function parseResetTime(text3, now) {
7589
- const raw = text3.trim();
7955
+ function parseResetTime(text4, now) {
7956
+ const raw = text4.trim();
7590
7957
  if (!raw) return null;
7591
7958
  const relative = raw.match(/^in\s+(.+)$/i);
7592
7959
  if (relative) {
@@ -7866,9 +8233,9 @@ var LogBatcher = class {
7866
8233
  seq = 0;
7867
8234
  /** Chunks awaiting a successful send, oldest first. */
7868
8235
  pending = [];
7869
- append(text3) {
7870
- if (!text3) return;
7871
- this.buffer += text3;
8236
+ append(text4) {
8237
+ if (!text4) return;
8238
+ this.buffer += text4;
7872
8239
  if (Buffer.byteLength(this.buffer, "utf8") >= (this.opts.maxBytes ?? 32 * 1024)) {
7873
8240
  void this.flush();
7874
8241
  } else if (!this.timer) {
@@ -8600,9 +8967,9 @@ async function runDaemon(opts) {
8600
8967
  child.stdout?.on("data", (data) => run.batcher.append(data.toString("utf8")));
8601
8968
  }
8602
8969
  child.stderr?.on("data", (data) => {
8603
- const text3 = data.toString("utf8");
8604
- run.batcher.append(text3);
8605
- run.limiter?.noteStderr(text3);
8970
+ const text4 = data.toString("utf8");
8971
+ run.batcher.append(text4);
8972
+ run.limiter?.noteStderr(text4);
8606
8973
  });
8607
8974
  run.timeout = setTimeout(() => {
8608
8975
  if (run.settled) return;
@@ -9192,9 +9559,9 @@ function register8(program3) {
9192
9559
  withCommon(
9193
9560
  runsCmd.command("show <id>").description("Show a run; --logs prints the captured log tail, --logs --full the whole log").option("--logs", "print the log tail").option("--full", "with --logs: print the complete log, not the 256 KB tail").option("--raw", "with --logs --full: print the unrendered harness stream instead")
9194
9561
  ).action(
9195
- async (id, opts) => {
9562
+ async (id2, opts) => {
9196
9563
  const api = client(opts);
9197
- const run = await api.getRun(id);
9564
+ const run = await api.getRun(id2);
9198
9565
  if (opts.json) return printJson(run);
9199
9566
  console.log(
9200
9567
  `${run.id} ${run.status} on ${run.runner_name}${run.resumed_from_run_id ? ` \xB7 resumed run ${run.resumed_from_run_id}` : ""}`
@@ -9226,7 +9593,7 @@ function register8(program3) {
9226
9593
  if (opts.logs) {
9227
9594
  console.log("");
9228
9595
  if (opts.full || opts.raw) {
9229
- const res = await api.getRunLogFull(id, { raw: opts.raw });
9596
+ const res = await api.getRunLogFull(id2, { raw: opts.raw });
9230
9597
  const body = res.body;
9231
9598
  if (!body) return;
9232
9599
  const reader = body.getReader();
@@ -9250,9 +9617,9 @@ function register8(program3) {
9250
9617
  );
9251
9618
  withCommon(
9252
9619
  runsCmd.command("cancel <id>").description("Cancel a run (judged like any other end: usually a strike)")
9253
- ).action(async (id, opts) => {
9620
+ ).action(async (id2, opts) => {
9254
9621
  const api = client(opts);
9255
- const run = await api.cancelRun(id);
9622
+ const run = await api.cancelRun(id2);
9256
9623
  if (opts.json) return printJson(run);
9257
9624
  console.log(
9258
9625
  `canceled ${run.id}${run.issue_ref ? ` on ${issueRef(run.issue_ref)}` : ""} (was on ${run.runner_name})`
@@ -9323,10 +9690,10 @@ function register9(program3) {
9323
9690
  schedules.command("show <ref>").description("Show a schedule (<project>/<name>): config, next/last run, recent instances")
9324
9691
  ).action(async (ref, opts) => {
9325
9692
  const api = client(opts);
9326
- const schedule = await resolveSchedule(api, ref);
9327
- if (opts.json) return printJson(schedule);
9328
- printScheduleDetail(schedule);
9329
- const { items } = await api.listIssues({ schedule: schedule.id, limit: 10 });
9693
+ const schedule2 = await resolveSchedule(api, ref);
9694
+ if (opts.json) return printJson(schedule2);
9695
+ printScheduleDetail(schedule2);
9696
+ const { items } = await api.listIssues({ schedule: schedule2.id, limit: 10 });
9330
9697
  if (items.length > 0) {
9331
9698
  console.log(`
9332
9699
  recent instances:`);
@@ -9363,16 +9730,16 @@ recent instances:`);
9363
9730
  async (ref, opts) => {
9364
9731
  const descriptionTemplate = opts.description !== void 0 ? readBodyValue(opts.description) : void 0;
9365
9732
  const api = client(opts);
9366
- const schedule = await resolveSchedule(api, ref);
9733
+ const schedule2 = await resolveSchedule(api, ref);
9367
9734
  const body = {};
9368
9735
  if (opts.title !== void 0) body.title_template = opts.title;
9369
9736
  if (descriptionTemplate !== void 0) body.description_template = descriptionTemplate;
9370
9737
  if (opts.workflow !== void 0)
9371
9738
  body.workflow_id = (await resolveWorkflow(api, opts.workflow)).id;
9372
9739
  if (opts.state !== void 0) body.state = opts.state;
9373
- const recurrence = buildRecurrence(opts);
9374
- if (recurrence?.preset) body.preset = recurrence.preset;
9375
- if (recurrence?.cron !== void 0) body.cron = recurrence.cron;
9740
+ const recurrence2 = buildRecurrence(opts);
9741
+ if (recurrence2?.preset) body.preset = recurrence2.preset;
9742
+ if (recurrence2?.cron !== void 0) body.cron = recurrence2.cron;
9376
9743
  if (opts.tz !== void 0) body.timezone = opts.tz;
9377
9744
  if (opts.ifClosed !== void 0) body.require_all_closed = opts.ifClosed;
9378
9745
  if (opts.name !== void 0) body.name = opts.name;
@@ -9381,7 +9748,7 @@ recent instances:`);
9381
9748
  "nothing to update: pass --title, --description, --workflow, --state, --every/--at/--on, --cron, --tz, --[no-]if-closed, and/or --name"
9382
9749
  );
9383
9750
  }
9384
- const updated = await api.updateSchedule(schedule.id, body);
9751
+ const updated = await api.updateSchedule(schedule2.id, body);
9385
9752
  if (opts.json) return printJson(updated);
9386
9753
  console.log(`updated schedule "${scheduleRef(updated)}"
9387
9754
  `);
@@ -9392,8 +9759,8 @@ recent instances:`);
9392
9759
  schedules.command("pause <ref>").description("Pause a schedule (keeps config and history)")
9393
9760
  ).action(async (ref, opts) => {
9394
9761
  const api = client(opts);
9395
- const schedule = await resolveSchedule(api, ref);
9396
- const updated = await api.updateSchedule(schedule.id, { enabled: false });
9762
+ const schedule2 = await resolveSchedule(api, ref);
9763
+ const updated = await api.updateSchedule(schedule2.id, { enabled: false });
9397
9764
  if (opts.json) return printJson(updated);
9398
9765
  console.log(`paused schedule "${scheduleRef(updated)}"`);
9399
9766
  });
@@ -9401,8 +9768,8 @@ recent instances:`);
9401
9768
  schedules.command("resume <ref>").description("Resume a paused schedule (recomputes the next occurrence from now)")
9402
9769
  ).action(async (ref, opts) => {
9403
9770
  const api = client(opts);
9404
- const schedule = await resolveSchedule(api, ref);
9405
- const updated = await api.updateSchedule(schedule.id, { enabled: true });
9771
+ const schedule2 = await resolveSchedule(api, ref);
9772
+ const updated = await api.updateSchedule(schedule2.id, { enabled: true });
9406
9773
  if (opts.json) return printJson(updated);
9407
9774
  console.log(
9408
9775
  `resumed schedule "${scheduleRef(updated)}" \u2014 next run ${timestamp(updated.next_run_at)}`
@@ -9412,8 +9779,8 @@ recent instances:`);
9412
9779
  schedules.command("run <ref>").description("Create an instance now (respects the only-when-closed gate)")
9413
9780
  ).action(async (ref, opts) => {
9414
9781
  const api = client(opts);
9415
- const schedule = await resolveSchedule(api, ref);
9416
- const issue = await api.runSchedule(schedule.id);
9782
+ const schedule2 = await resolveSchedule(api, ref);
9783
+ const issue = await api.runSchedule(schedule2.id);
9417
9784
  if (opts.json) return printJson(issue);
9418
9785
  console.log(
9419
9786
  `created ${issue.project_name}/#${issue.number} "${issue.title}" in state "${issue.state.name}"`
@@ -9423,17 +9790,17 @@ recent instances:`);
9423
9790
  schedules.command("delete <ref>").description("Delete a schedule (existing issues are kept)").option("-y, --yes", "skip the confirmation prompt")
9424
9791
  ).action(async (ref, opts) => {
9425
9792
  const api = client(opts);
9426
- const schedule = await resolveSchedule(api, ref);
9793
+ const schedule2 = await resolveSchedule(api, ref);
9427
9794
  if (!opts.yes) {
9428
9795
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
9429
9796
  const answer = await rl.question(
9430
- `Delete schedule "${scheduleRef(schedule)}"? Its ${schedule.run_count} existing issue${schedule.run_count === 1 ? "" : "s"} will be kept. [y/N] `
9797
+ `Delete schedule "${scheduleRef(schedule2)}"? Its ${schedule2.run_count} existing issue${schedule2.run_count === 1 ? "" : "s"} will be kept. [y/N] `
9431
9798
  );
9432
9799
  rl.close();
9433
9800
  if (!/^y(es)?$/i.test(answer.trim())) die("aborted");
9434
9801
  }
9435
- await api.deleteSchedule(schedule.id);
9436
- console.log(`deleted schedule "${scheduleRef(schedule)}" (issues kept)`);
9802
+ await api.deleteSchedule(schedule2.id);
9803
+ console.log(`deleted schedule "${scheduleRef(schedule2)}" (issues kept)`);
9437
9804
  });
9438
9805
  }
9439
9806
 
@@ -9552,9 +9919,9 @@ function register10(program3) {
9552
9919
  console.log(
9553
9920
  `automation: ${settings.enabled ? "ON" : "OFF (kill switch \u2014 nothing dispatches)"}`
9554
9921
  );
9555
- console.log(quotaLabel(settings.quota, (id) => stateNames.get(id) ?? id));
9922
+ console.log(quotaLabel(settings.quota, (id2) => stateNames.get(id2) ?? id2));
9556
9923
  console.log(
9557
- `utilization: ${utilizationLabel(settings.quota, activeRunItems, (id) => stateNames.get(id) ?? id)}`
9924
+ `utilization: ${utilizationLabel(settings.quota, activeRunItems, (id2) => stateNames.get(id2) ?? id2)}`
9558
9925
  );
9559
9926
  console.log(`attempt limit: ${settings.attempt_limit} strikes, then the issue parks`);
9560
9927
  if (queue.waiting === 0) {
@@ -9649,7 +10016,7 @@ function register10(program3) {
9649
10016
  for (const wf of workflows.items) {
9650
10017
  for (const s of wf.states) stateNames.set(s.id, `${wf.name}/${s.name}`);
9651
10018
  }
9652
- console.log(quotaLabel(settings.quota, (id) => stateNames.get(id) ?? id));
10019
+ console.log(quotaLabel(settings.quota, (id2) => stateNames.get(id2) ?? id2));
9653
10020
  });
9654
10021
  }
9655
10022
 
@@ -9750,9 +10117,9 @@ async function loadLibrary(api) {
9750
10117
  return { workflows, states, children };
9751
10118
  }
9752
10119
  var qualify = (entry) => `${entry.workflow.name} / ${entry.state.name}`;
9753
- function stateLabel(lib, id) {
9754
- const entry = lib.states.get(id);
9755
- return entry ? qualify(entry) : id;
10120
+ function stateLabel(lib, id2) {
10121
+ const entry = lib.states.get(id2);
10122
+ return entry ? qualify(entry) : id2;
9756
10123
  }
9757
10124
  function inheritanceLines(lib, state) {
9758
10125
  const lines = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tines",
3
- "version": "0.0.177",
3
+ "version": "0.0.179",
4
4
  "description": "CLI for Tines, an orchestration layer for AI agents",
5
5
  "repository": {
6
6
  "type": "git",