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.
- package/README.md +1 -1
- package/dist/index.js +516 -149
- 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
|
|
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
|
|
1010
|
-
const negativeValue =
|
|
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
|
|
3134
|
-
if (context.hasColors) return
|
|
3135
|
-
return this._outputConfiguration.stripColor(
|
|
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,
|
|
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
|
|
3305
|
-
helpStr =
|
|
3304
|
+
if (typeof text4 === "function") {
|
|
3305
|
+
helpStr = text4({ error: context.error, command: context.command });
|
|
3306
3306
|
} else {
|
|
3307
|
-
helpStr =
|
|
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 = (
|
|
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: (
|
|
3982
|
-
updateProject: (
|
|
3983
|
-
deleteProject: (
|
|
3984
|
-
archiveProject: (
|
|
3985
|
-
unarchiveProject: (
|
|
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: (
|
|
3990
|
-
updateWorkflow: (
|
|
3991
|
-
deleteWorkflow: (
|
|
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: (
|
|
4006
|
+
getIssue: (id2) => get(`/api/v1/issues/${id2}`),
|
|
4007
4007
|
getIssueByNumber: (projectId, number) => get(`/api/v1/projects/${projectId}/issues/${number}`),
|
|
4008
|
-
updateIssue: (
|
|
4009
|
-
transitionIssue: (
|
|
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: (
|
|
4011
|
+
resumeIssue: (id2) => request("POST", `/api/v1/issues/${id2}/resume`),
|
|
4012
4012
|
/** The dispatch explainer: "why isn't this running?". */
|
|
4013
|
-
getIssueDispatch: (
|
|
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: (
|
|
4026
|
-
updateSchedule: (
|
|
4027
|
-
deleteSchedule: (
|
|
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: (
|
|
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: (
|
|
4034
|
-
updateContextItem: (
|
|
4035
|
-
deleteContextItem: (
|
|
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: (
|
|
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: (
|
|
4118
|
-
updateRunner: (
|
|
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: (
|
|
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: (
|
|
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: (
|
|
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: (
|
|
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: (
|
|
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: (
|
|
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: (
|
|
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: (
|
|
4154
|
-
deleteRoutingRule: (
|
|
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: (
|
|
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(
|
|
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
|
|
4183
|
-
|
|
4184
|
-
|
|
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 =
|
|
4187
|
-
const at =
|
|
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 ${
|
|
4332
|
+
return `Every day at ${preset2.time}`;
|
|
4192
4333
|
case "weekly":
|
|
4193
|
-
return `Every ${WEEKDAY_NAMES[
|
|
4334
|
+
return `Every ${WEEKDAY_NAMES[preset2.weekday ?? 0]} at ${preset2.time}`;
|
|
4194
4335
|
case "monthly":
|
|
4195
|
-
return `Monthly on day ${
|
|
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(
|
|
4262
|
-
return `${describeRecurrence(
|
|
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
|
-
([
|
|
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 (
|
|
4903
|
-
const item = await client(opts).getContextItem(
|
|
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 (
|
|
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(
|
|
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(
|
|
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 (
|
|
5285
|
+
async (id2, opts) => {
|
|
5007
5286
|
const api = client(opts);
|
|
5008
|
-
const item = await api.getContextItem(
|
|
5009
|
-
await api.deleteContextItem(
|
|
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: "
|
|
5330
|
+
replaced: "effective selection changes"
|
|
5052
5331
|
};
|
|
5053
5332
|
function inspectableChanges(preview) {
|
|
5054
|
-
return preview.context.changes
|
|
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
|
-
`
|
|
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
|
|
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
|
-
|
|
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
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
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 =
|
|
5149
|
-
if (repo)
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
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 (
|
|
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,
|
|
6205
|
+
const project = await resolveProject(api, projectRef2);
|
|
5839
6206
|
const workflowId = opts.workflow ? (await resolveWorkflow(api, opts.workflow)).id : void 0;
|
|
5840
|
-
const
|
|
5841
|
-
if (!
|
|
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
|
|
5845
|
-
...
|
|
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
|
|
5930
|
-
if (opts.json) return printJson({ ...preview, inspected:
|
|
5931
|
-
return console.log(
|
|
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: (
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
7744
|
+
function object2(value) {
|
|
7378
7745
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
7379
7746
|
}
|
|
7380
|
-
function
|
|
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 =
|
|
7390
|
-
return [`[error] ${clip(
|
|
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(
|
|
7759
|
+
if (type === "error") return [`[error] ${clip(text3(event.message) ?? "unknown error", 2e3)}`];
|
|
7393
7760
|
if (type !== "item.completed") return [];
|
|
7394
|
-
const item =
|
|
7761
|
+
const item = object2(event.item);
|
|
7395
7762
|
if (!item) return [];
|
|
7396
7763
|
switch (item.type) {
|
|
7397
7764
|
case "agent_message":
|
|
7398
|
-
return
|
|
7765
|
+
return text3(item.text) ? [`[agent] ${clip(text3(item.text), 2e3)}`] : [];
|
|
7399
7766
|
case "command_execution": {
|
|
7400
|
-
const command =
|
|
7767
|
+
const command = text3(item.command) ?? "command";
|
|
7401
7768
|
const failed = validMetric(item.exit_code) && item.exit_code !== 0;
|
|
7402
|
-
const output = failed ?
|
|
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) =>
|
|
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([
|
|
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${
|
|
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 =
|
|
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 =
|
|
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(
|
|
7589
|
-
const raw =
|
|
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(
|
|
7870
|
-
if (!
|
|
7871
|
-
this.buffer +=
|
|
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
|
|
8604
|
-
run.batcher.append(
|
|
8605
|
-
run.limiter?.noteStderr(
|
|
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 (
|
|
9562
|
+
async (id2, opts) => {
|
|
9196
9563
|
const api = client(opts);
|
|
9197
|
-
const run = await api.getRun(
|
|
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(
|
|
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 (
|
|
9620
|
+
).action(async (id2, opts) => {
|
|
9254
9621
|
const api = client(opts);
|
|
9255
|
-
const run = await api.cancelRun(
|
|
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
|
|
9327
|
-
if (opts.json) return printJson(
|
|
9328
|
-
printScheduleDetail(
|
|
9329
|
-
const { items } = await api.listIssues({ schedule:
|
|
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
|
|
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
|
|
9374
|
-
if (
|
|
9375
|
-
if (
|
|
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(
|
|
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
|
|
9396
|
-
const updated = await api.updateSchedule(
|
|
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
|
|
9405
|
-
const updated = await api.updateSchedule(
|
|
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
|
|
9416
|
-
const issue = await api.runSchedule(
|
|
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
|
|
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(
|
|
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(
|
|
9436
|
-
console.log(`deleted schedule "${scheduleRef(
|
|
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, (
|
|
9922
|
+
console.log(quotaLabel(settings.quota, (id2) => stateNames.get(id2) ?? id2));
|
|
9556
9923
|
console.log(
|
|
9557
|
-
`utilization: ${utilizationLabel(settings.quota, activeRunItems, (
|
|
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, (
|
|
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,
|
|
9754
|
-
const entry = lib.states.get(
|
|
9755
|
-
return entry ? qualify(entry) :
|
|
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 = [];
|