brnch-cli 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/brnch.mjs +1250 -695
- package/package.json +1 -1
package/brnch.mjs
CHANGED
|
@@ -718,9 +718,9 @@ var require_Alias = __commonJS({
|
|
|
718
718
|
} else if (identity.isCollection(node2)) {
|
|
719
719
|
let count = 0;
|
|
720
720
|
for (const item of node2.items) {
|
|
721
|
-
const
|
|
722
|
-
if (
|
|
723
|
-
count =
|
|
721
|
+
const c5 = getAliasCount(doc, item, anchors2);
|
|
722
|
+
if (c5 > count)
|
|
723
|
+
count = c5;
|
|
724
724
|
}
|
|
725
725
|
return count;
|
|
726
726
|
} else if (identity.isPair(node2)) {
|
|
@@ -5829,11 +5829,11 @@ var require_lexer = __commonJS({
|
|
|
5829
5829
|
hasChars(n) {
|
|
5830
5830
|
return this.pos + n <= this.buffer.length;
|
|
5831
5831
|
}
|
|
5832
|
-
setNext(
|
|
5832
|
+
setNext(state2) {
|
|
5833
5833
|
this.buffer = this.buffer.substring(this.pos);
|
|
5834
5834
|
this.pos = 0;
|
|
5835
5835
|
this.lineEndPos = null;
|
|
5836
|
-
this.next =
|
|
5836
|
+
this.next = state2;
|
|
5837
5837
|
return null;
|
|
5838
5838
|
}
|
|
5839
5839
|
peek(n) {
|
|
@@ -13766,7 +13766,7 @@ var base64urlCharset = /^[A-Za-z0-9_-]*$/;
|
|
|
13766
13766
|
function isValidBase64URL(data) {
|
|
13767
13767
|
if (!base64urlCharset.test(data))
|
|
13768
13768
|
return false;
|
|
13769
|
-
const base643 = data.replace(/[-_]/g, (
|
|
13769
|
+
const base643 = data.replace(/[-_]/g, (c5) => c5 === "-" ? "+" : "/");
|
|
13770
13770
|
const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
|
|
13771
13771
|
return isValidBase64(padded);
|
|
13772
13772
|
}
|
|
@@ -15903,11 +15903,11 @@ function settle(inst, answer) {
|
|
|
15903
15903
|
function isRecursiveSchema(inst) {
|
|
15904
15904
|
return isRecursive(inst, /* @__PURE__ */ new Set(), true) !== NONE;
|
|
15905
15905
|
}
|
|
15906
|
-
function bucketFor(
|
|
15907
|
-
let bucket =
|
|
15906
|
+
function bucketFor(state2, inst) {
|
|
15907
|
+
let bucket = state2.buckets.get(inst);
|
|
15908
15908
|
if (!bucket) {
|
|
15909
15909
|
bucket = /* @__PURE__ */ new WeakMap();
|
|
15910
|
-
|
|
15910
|
+
state2.buckets.set(inst, bucket);
|
|
15911
15911
|
}
|
|
15912
15912
|
return bucket;
|
|
15913
15913
|
}
|
|
@@ -15965,16 +15965,16 @@ var memo = {
|
|
|
15965
15965
|
const input2 = payload.value;
|
|
15966
15966
|
if (!isRef(input2))
|
|
15967
15967
|
return base2(payload, ctx);
|
|
15968
|
-
let
|
|
15969
|
-
if (!
|
|
15970
|
-
|
|
15971
|
-
ctx[STATE] =
|
|
15968
|
+
let state2 = ctx[STATE];
|
|
15969
|
+
if (!state2) {
|
|
15970
|
+
state2 = { buckets: /* @__PURE__ */ new WeakMap(), backEdges: void 0 };
|
|
15971
|
+
ctx[STATE] = state2;
|
|
15972
15972
|
}
|
|
15973
15973
|
let bucket;
|
|
15974
15974
|
if (lastCtx === ctx) {
|
|
15975
15975
|
bucket = lastBucket;
|
|
15976
15976
|
} else {
|
|
15977
|
-
bucket = bucketFor(
|
|
15977
|
+
bucket = bucketFor(state2, inst);
|
|
15978
15978
|
lastCtx = ctx;
|
|
15979
15979
|
lastBucket = bucket;
|
|
15980
15980
|
}
|
|
@@ -15986,8 +15986,8 @@ var memo = {
|
|
|
15986
15986
|
payload.issues.push(...cloneIssues(hit.issues));
|
|
15987
15987
|
} else {
|
|
15988
15988
|
payload.memo = true;
|
|
15989
|
-
|
|
15990
|
-
|
|
15989
|
+
state2.backEdges ?? (state2.backEdges = /* @__PURE__ */ new WeakSet());
|
|
15990
|
+
state2.backEdges.add(hit.value);
|
|
15991
15991
|
}
|
|
15992
15992
|
return payload;
|
|
15993
15993
|
}
|
|
@@ -30642,7 +30642,7 @@ var ReactionRequest = external_exports.object({
|
|
|
30642
30642
|
content: external_exports.enum(REACTION_CONTENTS)
|
|
30643
30643
|
});
|
|
30644
30644
|
var LabelName = external_exports.string().trim().min(1).max(50).regex(/^[^\u0000-\u001f\u007f]+$/, "control characters are not allowed");
|
|
30645
|
-
var LabelColor = external_exports.string().trim().regex(/^#?[0-9a-fA-F]{6}$/, "six-digit hex color").transform((
|
|
30645
|
+
var LabelColor = external_exports.string().trim().regex(/^#?[0-9a-fA-F]{6}$/, "six-digit hex color").transform((c5) => `#${c5.replace(/^#/, "").toLowerCase()}`);
|
|
30646
30646
|
var CreateLabelRequest = external_exports.object({ name: LabelName, color: LabelColor, description: external_exports.string().max(100).default("") });
|
|
30647
30647
|
var UpdateLabelRequest = external_exports.object({ name: LabelName.optional(), color: LabelColor.optional(), description: external_exports.string().max(100).optional(), version: external_exports.number().int() });
|
|
30648
30648
|
var INTERACTION_LIMIT_LEVELS = ["none", "prior_contributors", "collaborators"];
|
|
@@ -30946,12 +30946,6 @@ var CreateReleaseRequest = external_exports.object({
|
|
|
30946
30946
|
draft: external_exports.boolean().default(false)
|
|
30947
30947
|
});
|
|
30948
30948
|
var CreateTagRequest = external_exports.object({ name: external_exports.string().min(1).max(200).regex(/^[A-Za-z0-9._\/-]+$/), target: external_exports.string().max(255) });
|
|
30949
|
-
var NotificationSettingsSchema = external_exports.object({
|
|
30950
|
-
email_immediate: external_exports.array(external_exports.enum(["review_requested", "response_required", "check_failed", "permission_request", "merge_conflict", "promotion_blocked", "session_blocked", "watching", "secret_alert"])).default([]),
|
|
30951
|
-
email_digest: external_exports.enum(["off", "daily"]).default("off"),
|
|
30952
|
-
muted: external_exports.array(external_exports.string().max(200)).max(500).default([])
|
|
30953
|
-
});
|
|
30954
|
-
var MuteRequest = external_exports.object({ group_key: external_exports.string().max(200).optional(), change_id: external_exports.string().optional(), session_id: external_exports.string().optional() });
|
|
30955
30949
|
|
|
30956
30950
|
// packages/protocol/src/auth-unified.ts
|
|
30957
30951
|
var DeliverableEmail = external_exports.email().max(254).refine((e) => !/\.invalid$/i.test(e), "this address cannot receive email");
|
|
@@ -31239,11 +31233,11 @@ var ConnectorVariants = external_exports.discriminatedUnion("kind", [
|
|
|
31239
31233
|
credentials: external_exports.object({ api_key: Secret })
|
|
31240
31234
|
})
|
|
31241
31235
|
]);
|
|
31242
|
-
var CreateConnectorRequest = ConnectorVariants.superRefine((v,
|
|
31236
|
+
var CreateConnectorRequest = ConnectorVariants.superRefine((v, c5) => {
|
|
31243
31237
|
const withConnection = "connection_id" in v && !!v.connection_id;
|
|
31244
31238
|
const withCredentials = "credentials" in v && v.credentials !== void 0 && Object.keys(v.credentials).length > 0;
|
|
31245
31239
|
if (v.kind === "cloudflare" || v.kind === "planetscale" || v.kind === "sentry") {
|
|
31246
|
-
if (withConnection === withCredentials)
|
|
31240
|
+
if (withConnection === withCredentials) c5.addIssue({ code: "custom", path: ["credentials"], message: "give either credentials or connection_id (a connected account), not both" });
|
|
31247
31241
|
}
|
|
31248
31242
|
});
|
|
31249
31243
|
var FactRequestSchema = external_exports.object({
|
|
@@ -32254,11 +32248,11 @@ var UpsertWorkerEnvRequest = external_exports.object({
|
|
|
32254
32248
|
store_id: external_exports.string().regex(/^[A-Za-z0-9]{1,64}$/).optional(),
|
|
32255
32249
|
store_secret_name: external_exports.string().regex(/^[A-Za-z0-9_-]{1,255}$/).optional(),
|
|
32256
32250
|
expected_version: external_exports.number().int().positive().optional()
|
|
32257
|
-
}).superRefine((v,
|
|
32258
|
-
if (v.source === "value" && v.value === void 0)
|
|
32259
|
-
if (v.source === "actions_secret" && !v.secret_name)
|
|
32260
|
-
if (v.source === "secrets_store" && (!v.store_id || !v.store_secret_name))
|
|
32261
|
-
if (v.kind === "var" && v.source !== "value")
|
|
32251
|
+
}).superRefine((v, c5) => {
|
|
32252
|
+
if (v.source === "value" && v.value === void 0) c5.addIssue({ code: "custom", message: "value is required for source=value", path: ["value"] });
|
|
32253
|
+
if (v.source === "actions_secret" && !v.secret_name) c5.addIssue({ code: "custom", message: "secret_name is required for source=actions_secret", path: ["secret_name"] });
|
|
32254
|
+
if (v.source === "secrets_store" && (!v.store_id || !v.store_secret_name)) c5.addIssue({ code: "custom", message: "store_id and store_secret_name are required for source=secrets_store", path: ["store_id"] });
|
|
32255
|
+
if (v.kind === "var" && v.source !== "value") c5.addIssue({ code: "custom", message: "plain vars take a value", path: ["source"] });
|
|
32262
32256
|
});
|
|
32263
32257
|
|
|
32264
32258
|
// packages/protocol/src/buildkite.ts
|
|
@@ -32495,19 +32489,19 @@ function parseGreptileJson(stdout, stderr, exitCode) {
|
|
|
32495
32489
|
return done({ status: "failed", summary: null, findings: [], error: { code: "output_invalid", message: "greptile did not print its JSON result" } });
|
|
32496
32490
|
}
|
|
32497
32491
|
const findings2 = [];
|
|
32498
|
-
for (const
|
|
32499
|
-
const body = str2(
|
|
32492
|
+
for (const c5 of Array.isArray(out.comments) ? out.comments.map(rec) : []) {
|
|
32493
|
+
const body = str2(c5.body);
|
|
32500
32494
|
if (!body) continue;
|
|
32501
32495
|
findings2.push(
|
|
32502
32496
|
finding({
|
|
32503
|
-
path: relPath(
|
|
32504
|
-
start: line(
|
|
32505
|
-
end: line(
|
|
32506
|
-
side:
|
|
32507
|
-
severity: GREPTILE_SEVERITY[String(
|
|
32497
|
+
path: relPath(c5.path),
|
|
32498
|
+
start: line(c5.startLine),
|
|
32499
|
+
end: line(c5.endLine),
|
|
32500
|
+
side: c5.side === "old" ? "old" : "new",
|
|
32501
|
+
severity: GREPTILE_SEVERITY[String(c5.severity ?? "")] ?? "info",
|
|
32508
32502
|
body,
|
|
32509
|
-
suggestion: str2(
|
|
32510
|
-
security:
|
|
32503
|
+
suggestion: str2(c5.suggestion),
|
|
32504
|
+
security: c5.securityIssue === true
|
|
32511
32505
|
})
|
|
32512
32506
|
);
|
|
32513
32507
|
}
|
|
@@ -32766,6 +32760,53 @@ var StaffRiskQuery = external_exports.object({
|
|
|
32766
32760
|
cursor: external_exports.string().max(200).optional()
|
|
32767
32761
|
});
|
|
32768
32762
|
|
|
32763
|
+
// packages/protocol/src/notifications.ts
|
|
32764
|
+
var NOTIFICATION_REASONS = [
|
|
32765
|
+
"review_requested",
|
|
32766
|
+
"review_available",
|
|
32767
|
+
"response_required",
|
|
32768
|
+
"check_failed",
|
|
32769
|
+
"permission_request",
|
|
32770
|
+
"merge_conflict",
|
|
32771
|
+
"promotion_blocked",
|
|
32772
|
+
"session_blocked",
|
|
32773
|
+
"watching",
|
|
32774
|
+
"secret_alert",
|
|
32775
|
+
"mentioned",
|
|
32776
|
+
"assigned",
|
|
32777
|
+
"comment",
|
|
32778
|
+
"approved",
|
|
32779
|
+
"merged"
|
|
32780
|
+
];
|
|
32781
|
+
var NotificationReasonSchema = external_exports.enum(NOTIFICATION_REASONS);
|
|
32782
|
+
var NOTIFICATION_CHANNELS = ["in_app", "email", "push"];
|
|
32783
|
+
var NotificationModeSchema = external_exports.enum(["off", "on", "immediate", "digest"]);
|
|
32784
|
+
var ChannelModesSchema = external_exports.object({ in_app: external_exports.enum(["on", "off"]).optional(), email: external_exports.enum(["off", "immediate", "digest"]).optional(), push: external_exports.enum(["on", "off"]).optional() }).strict();
|
|
32785
|
+
var HHMM = external_exports.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "HH:MM, 24-hour");
|
|
32786
|
+
var ReasonModes = external_exports.partialRecord(NotificationReasonSchema, ChannelModesSchema);
|
|
32787
|
+
var NotificationSettingsSchema = external_exports.object({
|
|
32788
|
+
reasons: ReasonModes.optional(),
|
|
32789
|
+
orgs: external_exports.record(external_exports.string().max(64), ReasonModes).refine((o) => Object.keys(o).length <= 100, "at most 100 organizations").optional(),
|
|
32790
|
+
digest: external_exports.object({ frequency: external_exports.enum(["off", "daily", "weekly"]), hour: external_exports.number().int().min(0).max(23).default(8), time_zone: external_exports.string().max(64).default("UTC") }).optional(),
|
|
32791
|
+
quiet_hours: external_exports.object({ start: HHMM, end: HHMM }).nullable().optional(),
|
|
32792
|
+
push_previews: external_exports.boolean().optional(),
|
|
32793
|
+
muted: external_exports.array(external_exports.string().max(200)).max(500).optional(),
|
|
32794
|
+
email_immediate: external_exports.array(NotificationReasonSchema).optional(),
|
|
32795
|
+
email_digest: external_exports.enum(["off", "daily"]).optional()
|
|
32796
|
+
});
|
|
32797
|
+
var MuteRequest = external_exports.object({ group_key: external_exports.string().max(200).optional(), change_id: external_exports.string().optional(), session_id: external_exports.string().optional() });
|
|
32798
|
+
var SnoozeRequest = external_exports.object({ until: external_exports.iso.datetime() });
|
|
32799
|
+
var InboxBulkRequest = external_exports.object({ action: external_exports.enum(["read", "unread", "done"]), ids: external_exports.array(external_exports.string().max(64)).max(100).optional(), all: external_exports.boolean().optional() });
|
|
32800
|
+
var RegisterPushDeviceRequest = external_exports.object({
|
|
32801
|
+
platform: external_exports.literal("ios"),
|
|
32802
|
+
/** The APNs device token, hex. */
|
|
32803
|
+
token: external_exports.string().regex(/^[0-9a-fA-F]{32,200}$/),
|
|
32804
|
+
environment: external_exports.enum(["sandbox", "production"]),
|
|
32805
|
+
app_version: external_exports.string().max(40).optional(),
|
|
32806
|
+
name: external_exports.string().max(80).optional()
|
|
32807
|
+
});
|
|
32808
|
+
var PushTestRequest = external_exports.object({ message: external_exports.string().trim().min(1).max(120).optional() });
|
|
32809
|
+
|
|
32769
32810
|
// packages/sdk/src/sse.ts
|
|
32770
32811
|
async function* parseSse(body) {
|
|
32771
32812
|
const reader2 = body.getReader();
|
|
@@ -32803,11 +32844,11 @@ async function* parseSse(body) {
|
|
|
32803
32844
|
}
|
|
32804
32845
|
let start = 0;
|
|
32805
32846
|
for (let i = 0; i < buf.length; i++) {
|
|
32806
|
-
const
|
|
32807
|
-
if (
|
|
32808
|
-
if (
|
|
32847
|
+
const c5 = buf[i];
|
|
32848
|
+
if (c5 !== "\n" && c5 !== "\r") continue;
|
|
32849
|
+
if (c5 === "\r" && i === buf.length - 1) break;
|
|
32809
32850
|
const line2 = buf.slice(start, i);
|
|
32810
|
-
if (
|
|
32851
|
+
if (c5 === "\r" && buf[i + 1] === "\n") i++;
|
|
32811
32852
|
start = i + 1;
|
|
32812
32853
|
const msg = onLine(line2);
|
|
32813
32854
|
if (msg) yield msg;
|
|
@@ -33934,19 +33975,49 @@ function integrationsGroup(t) {
|
|
|
33934
33975
|
};
|
|
33935
33976
|
}
|
|
33936
33977
|
function eventsGroup(t) {
|
|
33978
|
+
const list2 = (org, q = {}, o) => t.json({ method: "GET", path: path2`/v1/orgs/${org}/events`, query: { ...q }, options: o });
|
|
33937
33979
|
return {
|
|
33938
|
-
/** Permission-filtered replay; pass the previous `next_cursor`
|
|
33939
|
-
list:
|
|
33980
|
+
/** Permission-filtered replay, oldest first; pass the previous `next_cursor` as `after`. */
|
|
33981
|
+
list: list2,
|
|
33982
|
+
/**
|
|
33983
|
+
* Follow an organization's events by polling the replay (there is no push stream for them): each event once, in
|
|
33984
|
+
* order. `after` is a cursor from `list` or an event id; without it the replay starts at the oldest event, or at
|
|
33985
|
+
* the end with `fromNow` (which pages through the history once to find it). Ends when `signal` aborts.
|
|
33986
|
+
*/
|
|
33940
33987
|
async *stream(org, q = {}) {
|
|
33941
|
-
|
|
33942
|
-
|
|
33943
|
-
|
|
33944
|
-
|
|
33945
|
-
|
|
33946
|
-
|
|
33988
|
+
const o = q.signal ? { signal: q.signal } : void 0;
|
|
33989
|
+
let after = q.after && isEventId(q.after) ? eventCursor(q.after) : q.after;
|
|
33990
|
+
let skipping = !after && !!q.fromNow;
|
|
33991
|
+
try {
|
|
33992
|
+
while (!q.signal?.aborted) {
|
|
33993
|
+
const page = await list2(org, { ...after ? { after } : {}, limit: 100 }, o);
|
|
33994
|
+
if (!skipping) for (const e of page.items) yield e;
|
|
33995
|
+
const last = page.items.at(-1);
|
|
33996
|
+
after = page.next_cursor ?? (last ? eventCursor(last.id) : after);
|
|
33997
|
+
if (page.next_cursor) continue;
|
|
33998
|
+
skipping = false;
|
|
33999
|
+
await pause(q.pollMs ?? 5e3, q.signal);
|
|
34000
|
+
}
|
|
34001
|
+
} catch (e) {
|
|
34002
|
+
if (!q.signal?.aborted) throw e;
|
|
34003
|
+
}
|
|
33947
34004
|
}
|
|
33948
34005
|
};
|
|
33949
34006
|
}
|
|
34007
|
+
var isEventId = (s) => /^[a-z]+_[0-9a-z]+$/.test(s);
|
|
34008
|
+
var eventCursor = (id2) => btoa(id2).replace(/=+$/, "");
|
|
34009
|
+
function pause(ms, signal) {
|
|
34010
|
+
return new Promise((resolve13) => {
|
|
34011
|
+
if (signal?.aborted) return resolve13();
|
|
34012
|
+
const timer = setTimeout(done2, ms);
|
|
34013
|
+
function done2() {
|
|
34014
|
+
clearTimeout(timer);
|
|
34015
|
+
signal?.removeEventListener("abort", done2);
|
|
34016
|
+
resolve13();
|
|
34017
|
+
}
|
|
34018
|
+
signal?.addEventListener("abort", done2, { once: true });
|
|
34019
|
+
});
|
|
34020
|
+
}
|
|
33950
34021
|
function webhooksGroup(t) {
|
|
33951
34022
|
return {
|
|
33952
34023
|
/** The signing `secret` is returned only here. */
|
|
@@ -33960,8 +34031,104 @@ function webhooksGroup(t) {
|
|
|
33960
34031
|
};
|
|
33961
34032
|
}
|
|
33962
34033
|
function inboxGroup(t) {
|
|
34034
|
+
const act2 = (action) => (id2, o) => t.void({ method: "POST", path: path2`/v1/inbox/${id2}/${action}`, options: o });
|
|
34035
|
+
const count = (o) => t.json({ method: "GET", path: "/v1/inbox/count", options: o });
|
|
34036
|
+
return {
|
|
34037
|
+
list: (q = {}, o) => t.json({ method: "GET", path: "/v1/inbox", query: { ...q }, options: o }),
|
|
34038
|
+
count,
|
|
34039
|
+
read: act2("read"),
|
|
34040
|
+
unread: act2("unread"),
|
|
34041
|
+
done: act2("done"),
|
|
34042
|
+
undone: act2("undone"),
|
|
34043
|
+
snooze: (id2, until, o) => t.void({ method: "POST", path: path2`/v1/inbox/${id2}/snooze`, json: validate2(SnoozeRequest, { until }, "SnoozeRequest"), options: o }),
|
|
34044
|
+
bulk: (body, o) => t.json({ method: "POST", path: "/v1/inbox/bulk", json: validate2(InboxBulkRequest, body, "InboxBulkRequest"), options: o }),
|
|
34045
|
+
mute: (body, o) => t.json({ method: "POST", path: "/v1/inbox/mute", json: validate2(MuteRequest, body, "MuteRequest"), options: o }),
|
|
34046
|
+
/**
|
|
34047
|
+
* Live inbox changes. Uses the WebSocket at `/v1/me/inbox/events` when the runtime's WebSocket can send an
|
|
34048
|
+
* Authorization header (Node's), and otherwise polls the unread count every `pollMs`; either way each yield means
|
|
34049
|
+
* "the inbox changed: re-read it". Ends when `signal` aborts.
|
|
34050
|
+
*/
|
|
34051
|
+
async *watch(q = {}) {
|
|
34052
|
+
const getToken = async () => t.options.tokenProvider ? await t.options.tokenProvider.getToken() : t.options.token;
|
|
34053
|
+
const WS = globalThis.WebSocket;
|
|
34054
|
+
if (WS && await getToken() && typeof process !== "undefined") {
|
|
34055
|
+
try {
|
|
34056
|
+
while (!q.signal?.aborted) {
|
|
34057
|
+
for await (const e of liveEvents(WS, `${t.baseUrl.replace(/^http/, "ws")}/v1/me/inbox/events`, await getToken(), q.signal)) yield e;
|
|
34058
|
+
await pause(1e3, q.signal);
|
|
34059
|
+
}
|
|
34060
|
+
return;
|
|
34061
|
+
} catch {
|
|
34062
|
+
}
|
|
34063
|
+
}
|
|
34064
|
+
let last = -1;
|
|
34065
|
+
while (!q.signal?.aborted) {
|
|
34066
|
+
const { unread } = await count(q.signal ? { signal: q.signal } : void 0);
|
|
34067
|
+
if (unread !== last) {
|
|
34068
|
+
if (last !== -1) yield { type: "state", ids: [], unread, at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
34069
|
+
last = unread;
|
|
34070
|
+
}
|
|
34071
|
+
await pause(q.pollMs ?? 15e3, q.signal);
|
|
34072
|
+
}
|
|
34073
|
+
}
|
|
34074
|
+
};
|
|
34075
|
+
}
|
|
34076
|
+
async function* liveEvents(WS, url2, token, signal) {
|
|
34077
|
+
const ws = new WS(url2, { headers: { authorization: `Bearer ${token}` } });
|
|
34078
|
+
const queue = [];
|
|
34079
|
+
let wake = null;
|
|
34080
|
+
const end2 = { closed: null };
|
|
34081
|
+
const notify = () => {
|
|
34082
|
+
wake?.();
|
|
34083
|
+
wake = null;
|
|
34084
|
+
};
|
|
34085
|
+
const ping = setInterval(() => ws.readyState === 1 && ws.send("ping"), 3e4);
|
|
34086
|
+
ws.addEventListener("message", (m) => {
|
|
34087
|
+
if (m.data === "pong") return;
|
|
34088
|
+
try {
|
|
34089
|
+
queue.push(JSON.parse(String(m.data)));
|
|
34090
|
+
} catch {
|
|
34091
|
+
return;
|
|
34092
|
+
}
|
|
34093
|
+
notify();
|
|
34094
|
+
});
|
|
34095
|
+
ws.addEventListener("error", () => {
|
|
34096
|
+
end2.closed ??= { error: true };
|
|
34097
|
+
notify();
|
|
34098
|
+
});
|
|
34099
|
+
ws.addEventListener("close", () => {
|
|
34100
|
+
end2.closed ??= { error: false };
|
|
34101
|
+
notify();
|
|
34102
|
+
});
|
|
34103
|
+
signal?.addEventListener("abort", () => ws.close(1e3), { once: true });
|
|
34104
|
+
try {
|
|
34105
|
+
for (; ; ) {
|
|
34106
|
+
while (queue.length) yield queue.shift();
|
|
34107
|
+
if (end2.closed) {
|
|
34108
|
+
if (end2.closed.error) throw new Error("inbox socket failed");
|
|
34109
|
+
return;
|
|
34110
|
+
}
|
|
34111
|
+
await new Promise((r) => wake = r);
|
|
34112
|
+
}
|
|
34113
|
+
} finally {
|
|
34114
|
+
clearInterval(ping);
|
|
34115
|
+
if (ws.readyState <= 1) ws.close(1e3);
|
|
34116
|
+
}
|
|
34117
|
+
}
|
|
34118
|
+
function notificationsGroup(t) {
|
|
33963
34119
|
return {
|
|
33964
|
-
|
|
34120
|
+
get: (o) => t.json({ method: "GET", path: "/v1/me/notifications", options: o }),
|
|
34121
|
+
/** Changes only what is given; per reason, only the channels given. */
|
|
34122
|
+
update: (body, o) => t.json({ method: "PATCH", path: "/v1/me/notifications", json: validate2(NotificationSettingsSchema, body, "NotificationSettings"), options: o }),
|
|
34123
|
+
/** Turns email off for a reason (or all) from an unsubscribe link's token; needs no sign-in. */
|
|
34124
|
+
unsubscribe: (token, o) => t.json({ method: "POST", path: "/v1/notifications/unsubscribe", query: { token }, anonymous: true, options: o }),
|
|
34125
|
+
devices: {
|
|
34126
|
+
list: (o) => t.json({ method: "GET", path: "/v1/me/push-devices", options: o }),
|
|
34127
|
+
register: (body, o) => t.json({ method: "POST", path: "/v1/me/push-devices", json: validate2(RegisterPushDeviceRequest, body, "RegisterPushDeviceRequest"), options: o }),
|
|
34128
|
+
remove: (id2, o) => t.void({ method: "DELETE", path: path2`/v1/me/push-devices/${id2}`, options: o }),
|
|
34129
|
+
/** A test notification to your own devices; `message` replaces the default text. */
|
|
34130
|
+
test: (body = {}, o) => t.json({ method: "POST", path: "/v1/me/push-devices/test", json: validate2(PushTestRequest, body, "PushTestRequest"), options: o })
|
|
34131
|
+
}
|
|
33965
34132
|
};
|
|
33966
34133
|
}
|
|
33967
34134
|
function auditGroup(t) {
|
|
@@ -34378,6 +34545,7 @@ function createClient(options) {
|
|
|
34378
34545
|
events: eventsGroup(t),
|
|
34379
34546
|
webhooks: webhooksGroup(t),
|
|
34380
34547
|
inbox: inboxGroup(t),
|
|
34548
|
+
notifications: notificationsGroup(t),
|
|
34381
34549
|
audit: auditGroup(t),
|
|
34382
34550
|
exports: exportsGroup(t),
|
|
34383
34551
|
migrations: migrationsGroup(t),
|
|
@@ -34631,7 +34799,7 @@ async function verifyReceipt(envelope, keys, opts = {}) {
|
|
|
34631
34799
|
}
|
|
34632
34800
|
|
|
34633
34801
|
// packages/cli/package.json
|
|
34634
|
-
var version2 = "0.
|
|
34802
|
+
var version2 = "0.15.0";
|
|
34635
34803
|
|
|
34636
34804
|
// packages/cli/src/brand.ts
|
|
34637
34805
|
var BRAND = {
|
|
@@ -35403,7 +35571,7 @@ function createStoredTokenProvider(opts) {
|
|
|
35403
35571
|
const skew = opts.skewMs ?? 12e4;
|
|
35404
35572
|
let cached3;
|
|
35405
35573
|
let inflight = null;
|
|
35406
|
-
const expiring = (
|
|
35574
|
+
const expiring = (c5) => !!c5.expires_at && Date.parse(c5.expires_at) - skew <= now();
|
|
35407
35575
|
const load = async () => cached3 !== void 0 ? cached3 : cached3 = await lookupCredential(opts.file, opts.baseUrl, opts.account);
|
|
35408
35576
|
async function doRefresh(stale, force) {
|
|
35409
35577
|
return withCredentialsLock(
|
|
@@ -35438,14 +35606,14 @@ function createStoredTokenProvider(opts) {
|
|
|
35438
35606
|
return {
|
|
35439
35607
|
current: load,
|
|
35440
35608
|
async getToken() {
|
|
35441
|
-
const
|
|
35442
|
-
if (!
|
|
35443
|
-
if (!
|
|
35444
|
-
return refreshOnce(
|
|
35609
|
+
const c5 = await load();
|
|
35610
|
+
if (!c5) return void 0;
|
|
35611
|
+
if (!c5.refresh_token || !expiring(c5)) return c5.token;
|
|
35612
|
+
return refreshOnce(c5.token, false);
|
|
35445
35613
|
},
|
|
35446
35614
|
async onUnauthorized(token) {
|
|
35447
|
-
const
|
|
35448
|
-
if (!
|
|
35615
|
+
const c5 = await load();
|
|
35616
|
+
if (!c5?.refresh_token) return void 0;
|
|
35449
35617
|
return refreshOnce(token, true);
|
|
35450
35618
|
}
|
|
35451
35619
|
};
|
|
@@ -35698,8 +35866,8 @@ async function autoWireHooks(deps, agent) {
|
|
|
35698
35866
|
const names = SKILL_NAMES.join(" and ");
|
|
35699
35867
|
if (await hooksWired(deps, agent.tool) !== false)
|
|
35700
35868
|
return skill ? `Added the ${names} skills for ${agent.label}: how to coordinate with other agents here and hand changes to people for merge.` : null;
|
|
35701
|
-
const
|
|
35702
|
-
return `Wired ${
|
|
35869
|
+
const state2 = await installAgentHooks(tool, "user", home2, null, BRAND.cli);
|
|
35870
|
+
return `Wired ${state2.label}'s hooks (${state2.file})${skill ? ` and the ${names} skills` : ""} so its sessions report to Brnch by themselves from its next session on. Undo: ${BRAND.cli} hooks uninstall --agent ${tool}`;
|
|
35703
35871
|
}
|
|
35704
35872
|
async function wireInstalledTools(deps, tools) {
|
|
35705
35873
|
if (autoWireOff(deps.env) || deps.env[envName("CAPTURE")] === "0") return [];
|
|
@@ -35711,8 +35879,8 @@ async function wireInstalledTools(deps, tools) {
|
|
|
35711
35879
|
try {
|
|
35712
35880
|
await installSkills([tool], home2).catch(() => []);
|
|
35713
35881
|
if ((await agentHookState(tool, "user", home2, null)).installed.length) continue;
|
|
35714
|
-
const
|
|
35715
|
-
out.push(`${
|
|
35882
|
+
const state2 = await installAgentHooks(tool, "user", home2, null, BRAND.cli);
|
|
35883
|
+
out.push(`${state2.label} \u2192 ${state2.file}`);
|
|
35716
35884
|
} catch {
|
|
35717
35885
|
}
|
|
35718
35886
|
}
|
|
@@ -35758,16 +35926,16 @@ async function loadBookmark(deps, baseUrl) {
|
|
|
35758
35926
|
if (!entry || !isBookmark(entry.bookmark) || !(deps.sys.now() - entry.at < TTL_MS)) return void 0;
|
|
35759
35927
|
return entry.bookmark;
|
|
35760
35928
|
}
|
|
35761
|
-
async function saveBookmark(deps,
|
|
35929
|
+
async function saveBookmark(deps, state2) {
|
|
35762
35930
|
try {
|
|
35763
|
-
if (!
|
|
35931
|
+
if (!state2.bookmarkChanged || !state2.bookmark || !state2.baseUrl) return;
|
|
35764
35932
|
const file2 = bookmarkFile(deps.env);
|
|
35765
35933
|
const data = await readFileSafe(deps, file2);
|
|
35766
35934
|
const now = deps.sys.now();
|
|
35767
35935
|
for (const [k, v] of Object.entries(data.hosts)) if (!(now - v.at < TTL_MS)) delete data.hosts[k];
|
|
35768
|
-
const key = hostKey(
|
|
35936
|
+
const key = hostKey(state2.baseUrl);
|
|
35769
35937
|
const prev = data.hosts[key];
|
|
35770
|
-
if (!prev || !isBookmark(prev.bookmark) ||
|
|
35938
|
+
if (!prev || !isBookmark(prev.bookmark) || state2.bookmark > prev.bookmark) data.hosts[key] = { bookmark: state2.bookmark, at: now };
|
|
35771
35939
|
else data.hosts[key] = { ...prev, at: now };
|
|
35772
35940
|
await deps.sys.mkdir(dirname6(file2), 448);
|
|
35773
35941
|
await deps.writeFile(file2, `${JSON.stringify(data)}
|
|
@@ -36239,7 +36407,7 @@ function selectAccount(list2, o) {
|
|
|
36239
36407
|
return { account: active, source: active ? "active" : "none" };
|
|
36240
36408
|
}
|
|
36241
36409
|
var isPersonToken = (t) => !/^f(ses|int|job|wsg)_/.test(t);
|
|
36242
|
-
async function createContext(deps, globals,
|
|
36410
|
+
async function createContext(deps, globals, state2) {
|
|
36243
36411
|
const env = deps.env;
|
|
36244
36412
|
const credFile = credentialsPath({ XDG_CONFIG_HOME: env.XDG_CONFIG_HOME, HOME: env.HOME }, BRAND.configDir);
|
|
36245
36413
|
let creds;
|
|
@@ -36255,7 +36423,7 @@ async function createContext(deps, globals, state) {
|
|
|
36255
36423
|
} catch {
|
|
36256
36424
|
throw usage(`invalid server URL: ${baseUrl}`);
|
|
36257
36425
|
}
|
|
36258
|
-
|
|
36426
|
+
state2.baseUrl = baseUrl;
|
|
36259
36427
|
if (!project.repo && !globals.repo && !env[envName("REPO")]) {
|
|
36260
36428
|
const inferred = await repoFromGitRemotes(deps, baseUrl);
|
|
36261
36429
|
if (inferred) project.repo = inferred;
|
|
@@ -36268,14 +36436,14 @@ async function createContext(deps, globals, state) {
|
|
|
36268
36436
|
const storedCred = selected?.cred;
|
|
36269
36437
|
const stored = storedCred?.token;
|
|
36270
36438
|
const accountId = storedCred?.account?.user_id ?? null;
|
|
36271
|
-
if (signedIn2.length > 1 && selected)
|
|
36272
|
-
const interactive = !
|
|
36439
|
+
if (signedIn2.length > 1 && selected) state2.accounts = { using: accountLabel(selected.cred.account), others: signedIn2.filter((a) => a !== selected).map((a) => accountLabel(a.cred.account)) };
|
|
36440
|
+
const interactive = !state2.json && !env.CI && deps.stdinIsTTY && deps.stderrIsTTY;
|
|
36273
36441
|
const userAgent2 = `${BRAND.cli}-cli/${BRAND.version}`;
|
|
36274
36442
|
if (invalidAgentToolFlag(globals.agentTool)) throw usage(`unknown --agent-tool "${globals.agentTool}"; e.g. claude-code, codex, cursor, gemini-cli, opencode, aider, copilot, grok, other`);
|
|
36275
36443
|
const agent = detectAgent(env, globals.agentTool);
|
|
36276
36444
|
const headers = agent ? { [CLIENT_RUNTIME_HEADER]: formatClientRuntime({ agent: agent.tool, version: agent.version }) } : void 0;
|
|
36277
|
-
for (const s of [globals.token, env[envName("TOKEN")], env[envName("SESSION_TOKEN")], stored, storedCred?.refresh_token]) if (s)
|
|
36278
|
-
for (const a of signedIn2) for (const s of [a.cred.token, a.cred.refresh_token]) if (s)
|
|
36445
|
+
for (const s of [globals.token, env[envName("TOKEN")], env[envName("SESSION_TOKEN")], stored, storedCred?.refresh_token]) if (s) state2.secrets.push(s);
|
|
36446
|
+
for (const a of signedIn2) for (const s of [a.cred.token, a.cred.refresh_token]) if (s) state2.secrets.push(s);
|
|
36279
36447
|
const providers = /* @__PURE__ */ new Map();
|
|
36280
36448
|
function storedProvider(url2) {
|
|
36281
36449
|
const key = hostKey(url2);
|
|
@@ -36287,7 +36455,7 @@ async function createContext(deps, globals, state) {
|
|
|
36287
36455
|
...key === hostKey(baseUrl) ? { account: accountId } : {},
|
|
36288
36456
|
refresh: async (input3) => {
|
|
36289
36457
|
const r = await deps.createClient({ baseUrl: url2, userAgent: userAgent2, headers }).oauth.refresh(input3);
|
|
36290
|
-
|
|
36458
|
+
state2.secrets.push(r.access_token, ...r.refresh_token ? [r.refresh_token] : []);
|
|
36291
36459
|
return r;
|
|
36292
36460
|
}
|
|
36293
36461
|
});
|
|
@@ -36306,14 +36474,14 @@ async function createContext(deps, globals, state) {
|
|
|
36306
36474
|
}
|
|
36307
36475
|
const seedBookmark = await loadBookmark(deps, baseUrl);
|
|
36308
36476
|
const noteBookmark = (b) => {
|
|
36309
|
-
if (
|
|
36310
|
-
|
|
36311
|
-
|
|
36477
|
+
if (state2.bookmark && b <= state2.bookmark) return;
|
|
36478
|
+
state2.bookmark = b;
|
|
36479
|
+
state2.bookmarkChanged = true;
|
|
36312
36480
|
};
|
|
36313
36481
|
const clients = /* @__PURE__ */ new Map();
|
|
36314
36482
|
function makeClient(t, routed) {
|
|
36315
36483
|
const dynamic = !!t && t === stored && !!storedCred?.refresh_token;
|
|
36316
|
-
const consistency = { bookmark:
|
|
36484
|
+
const consistency = { bookmark: state2.bookmark ?? seedBookmark, onBookmark: noteBookmark, ...headers ? { headers } : {}, ...routed ? { routeCredential } : {} };
|
|
36317
36485
|
return dynamic ? deps.createClient({ baseUrl, tokenProvider: storedProvider(baseUrl), userAgent: userAgent2, ...consistency }) : deps.createClient({ baseUrl, token: t, userAgent: userAgent2, ...consistency });
|
|
36318
36486
|
}
|
|
36319
36487
|
function client(pref = "agent", opts = {}) {
|
|
@@ -36327,32 +36495,32 @@ async function createContext(deps, globals, state) {
|
|
|
36327
36495
|
}
|
|
36328
36496
|
const routed = !!agent && !!t && isPersonToken(t);
|
|
36329
36497
|
const key = `${routed ? "r:" : ""}${t ?? ""}`;
|
|
36330
|
-
let
|
|
36331
|
-
if (!
|
|
36332
|
-
|
|
36333
|
-
clients.set(key,
|
|
36498
|
+
let c5 = clients.get(key);
|
|
36499
|
+
if (!c5) {
|
|
36500
|
+
c5 = makeClient(t, routed);
|
|
36501
|
+
clients.set(key, c5);
|
|
36334
36502
|
}
|
|
36335
|
-
return
|
|
36503
|
+
return c5;
|
|
36336
36504
|
}
|
|
36337
36505
|
function humanClient() {
|
|
36338
36506
|
const { token: t } = token("user");
|
|
36339
36507
|
if (!t) return client("user");
|
|
36340
36508
|
const key = `h:${t}`;
|
|
36341
|
-
let
|
|
36342
|
-
if (!
|
|
36343
|
-
|
|
36344
|
-
clients.set(key,
|
|
36509
|
+
let c5 = clients.get(key);
|
|
36510
|
+
if (!c5) {
|
|
36511
|
+
c5 = makeClient(t, false);
|
|
36512
|
+
clients.set(key, c5);
|
|
36345
36513
|
}
|
|
36346
|
-
return
|
|
36514
|
+
return c5;
|
|
36347
36515
|
}
|
|
36348
36516
|
function sessionClient(t) {
|
|
36349
36517
|
const key = `s:${t}`;
|
|
36350
|
-
let
|
|
36351
|
-
if (!
|
|
36352
|
-
|
|
36353
|
-
clients.set(key,
|
|
36518
|
+
let c5 = clients.get(key);
|
|
36519
|
+
if (!c5) {
|
|
36520
|
+
c5 = deps.createClient({ baseUrl, token: t, userAgent: userAgent2, bookmark: state2.bookmark ?? seedBookmark, onBookmark: noteBookmark, ...headers ? { headers } : {} });
|
|
36521
|
+
clients.set(key, c5);
|
|
36354
36522
|
}
|
|
36355
|
-
return
|
|
36523
|
+
return c5;
|
|
36356
36524
|
}
|
|
36357
36525
|
const sessions = /* @__PURE__ */ new Map();
|
|
36358
36526
|
let announced = false;
|
|
@@ -36388,8 +36556,8 @@ async function createContext(deps, globals, state) {
|
|
|
36388
36556
|
const r = await repoTarget(spec);
|
|
36389
36557
|
const target = { baseUrl, repoId: r.id, repo: r.name, tool: agent.tool, toolSession: toolSessionFromEnv(), toolVersion: agent.version, title: env[envName("SESSION_TITLE")]?.trim() || null, accountId };
|
|
36390
36558
|
const { session, started } = await ensureAgentSession({ file: credFile, human: humanClient, asSession: sessionClient }, target);
|
|
36391
|
-
|
|
36392
|
-
|
|
36559
|
+
state2.secrets.push(session.token);
|
|
36560
|
+
state2.actingAs = session;
|
|
36393
36561
|
if (!announced) {
|
|
36394
36562
|
announced = true;
|
|
36395
36563
|
info(`${started ? "Started agent session. " : ""}${actingLine(session)}`);
|
|
@@ -36430,7 +36598,7 @@ async function createContext(deps, globals, state) {
|
|
|
36430
36598
|
account: userId,
|
|
36431
36599
|
refresh: async (input3) => {
|
|
36432
36600
|
const r = await deps.createClient({ baseUrl, userAgent: userAgent2, headers }).oauth.refresh(input3);
|
|
36433
|
-
|
|
36601
|
+
state2.secrets.push(r.access_token, ...r.refresh_token ? [r.refresh_token] : []);
|
|
36434
36602
|
return r;
|
|
36435
36603
|
}
|
|
36436
36604
|
});
|
|
@@ -36480,13 +36648,13 @@ async function createContext(deps, globals, state) {
|
|
|
36480
36648
|
throw usage(`no agent session selected: pass --session <id>, set ${envName("SESSION_ID")}, or authenticate with ${envName("SESSION_TOKEN")}`);
|
|
36481
36649
|
}
|
|
36482
36650
|
function info(message) {
|
|
36483
|
-
deps.stderr.write(`${redact(message,
|
|
36651
|
+
deps.stderr.write(`${redact(message, state2.secrets)}
|
|
36484
36652
|
`);
|
|
36485
36653
|
}
|
|
36486
36654
|
function result(value, human) {
|
|
36487
|
-
if (
|
|
36488
|
-
|
|
36489
|
-
if (
|
|
36655
|
+
if (state2.wroteResult) throw new Error("internal: result written twice");
|
|
36656
|
+
state2.wroteResult = true;
|
|
36657
|
+
if (state2.json) {
|
|
36490
36658
|
deps.stdout.write(`${JSON.stringify(value ?? null, null, 2)}
|
|
36491
36659
|
`);
|
|
36492
36660
|
return;
|
|
@@ -36505,7 +36673,7 @@ async function createContext(deps, globals, state) {
|
|
|
36505
36673
|
return {
|
|
36506
36674
|
deps,
|
|
36507
36675
|
globals,
|
|
36508
|
-
json:
|
|
36676
|
+
json: state2.json,
|
|
36509
36677
|
interactive,
|
|
36510
36678
|
baseUrl,
|
|
36511
36679
|
credentialsFile: credFile,
|
|
@@ -36537,9 +36705,9 @@ async function createContext(deps, globals, state) {
|
|
|
36537
36705
|
confirm,
|
|
36538
36706
|
input: input2,
|
|
36539
36707
|
setExit: (code) => {
|
|
36540
|
-
|
|
36708
|
+
state2.exitCode = code;
|
|
36541
36709
|
},
|
|
36542
|
-
addSecret: (s) =>
|
|
36710
|
+
addSecret: (s) => state2.secrets.push(s)
|
|
36543
36711
|
};
|
|
36544
36712
|
}
|
|
36545
36713
|
|
|
@@ -36562,7 +36730,7 @@ function act(rt, handler) {
|
|
|
36562
36730
|
}
|
|
36563
36731
|
function commandPath(cmd) {
|
|
36564
36732
|
const names = [];
|
|
36565
|
-
for (let
|
|
36733
|
+
for (let c5 = cmd; c5?.parent; c5 = c5.parent) names.unshift(c5.name());
|
|
36566
36734
|
return names.join(" ");
|
|
36567
36735
|
}
|
|
36568
36736
|
async function wireHooks(ctx) {
|
|
@@ -36651,10 +36819,10 @@ function pick2(o, key) {
|
|
|
36651
36819
|
}
|
|
36652
36820
|
function table(rows2, columns) {
|
|
36653
36821
|
if (!rows2.length) return "(none)";
|
|
36654
|
-
const data = rows2.map((r) => columns.map((
|
|
36655
|
-
const widths = columns.map((
|
|
36822
|
+
const data = rows2.map((r) => columns.map((c5) => cell(pick2(r ?? {}, c5))));
|
|
36823
|
+
const widths = columns.map((c5, i) => Math.max(c5.length, ...data.map((d) => (d[i] ?? "").length)));
|
|
36656
36824
|
const line2 = (cells2) => cells2.map((s, i) => i === cells2.length - 1 ? s : s.padEnd(widths[i] ?? 0)).join(" ");
|
|
36657
|
-
return [line2(columns.map((
|
|
36825
|
+
return [line2(columns.map((c5) => c5.toUpperCase())), ...data.map(line2)].join("\n");
|
|
36658
36826
|
}
|
|
36659
36827
|
function listWithCursor(page, columns) {
|
|
36660
36828
|
const body = table(page.items, columns);
|
|
@@ -36754,15 +36922,15 @@ function registerAgent(program2, rt) {
|
|
|
36754
36922
|
agent.command("update <agent>").description("Edit an agent's name, description or capability ceiling (requires agent:manage). You can only add capabilities you hold; removing one narrows its running sessions at once").option("--name <name>", "new name").option("--description <text>", "new description").option("--capability <cap>", "replace the ceiling with these, repeatable or comma-separated", list).option("--add-capability <cap>", "add to the ceiling, repeatable or comma-separated", list).option("--remove-capability <cap>", "remove from the ceiling, repeatable or comma-separated", list).action(
|
|
36755
36923
|
act(rt, async (ctx, o, [id2]) => {
|
|
36756
36924
|
if (o.capability && (o.addCapability || o.removeCapability)) throw usage("pass --capability (replace) or --add-capability/--remove-capability, not both");
|
|
36757
|
-
const
|
|
36925
|
+
const c5 = ctx.client("user");
|
|
36758
36926
|
let capabilities = o.capability;
|
|
36759
36927
|
if (o.addCapability || o.removeCapability) {
|
|
36760
|
-
const current = (await
|
|
36928
|
+
const current = (await c5.agents.get(id2)).capabilities;
|
|
36761
36929
|
const remove = new Set(o.removeCapability ?? []);
|
|
36762
36930
|
capabilities = [.../* @__PURE__ */ new Set([...current, ...o.addCapability ?? []])].filter((x) => !remove.has(x));
|
|
36763
36931
|
}
|
|
36764
36932
|
if (o.name === void 0 && o.description === void 0 && capabilities === void 0) throw usage("nothing to update: pass --name, --description or a capability option");
|
|
36765
|
-
const a = await
|
|
36933
|
+
const a = await c5.agents.update(id2, { name: o.name, description: o.description, capabilities });
|
|
36766
36934
|
ctx.result(a, (v) => kv(v, ["id", "name", "integration_type", "state", "capabilities", "repository_ids"]));
|
|
36767
36935
|
})
|
|
36768
36936
|
);
|
|
@@ -36959,17 +37127,17 @@ function registerActivity(program2, rt) {
|
|
|
36959
37127
|
})
|
|
36960
37128
|
);
|
|
36961
37129
|
}
|
|
36962
|
-
var renderCheckpoint = (
|
|
37130
|
+
var renderCheckpoint = (c5) => kv(c5, ["id", "session_id", "repository_id", "workspace_id", "source_oid", "manifest_digest", "predecessor_checkpoint_id", "export_state", "created_at"]) + `
|
|
36963
37131
|
|
|
36964
|
-
intent: ${
|
|
37132
|
+
intent: ${c5.manifest.intent}`;
|
|
36965
37133
|
function registerCheckpoint(program2, rt) {
|
|
36966
37134
|
const ckp = program2.command("checkpoint").description("Checkpoints and handoff (PRD \xA79.3)");
|
|
36967
37135
|
ckp.command("create").description("Record a checkpoint from a manifest (validated locally against the protocol schema)").requiredOption("--manifest <file>", "manifest JSON file, @file, or - for stdin").option("--session <id>", "session (default: manifest.session_id, then the current session)").action(
|
|
36968
37136
|
act(rt, async (ctx, o) => {
|
|
36969
37137
|
const manifest = await readJsonObject(fileSpec(o.manifest), ctx.input, "--manifest");
|
|
36970
37138
|
const session = await ctx.sessionId(o.session ?? (typeof manifest.session_id === "string" ? manifest.session_id : void 0));
|
|
36971
|
-
const
|
|
36972
|
-
ctx.result(
|
|
37139
|
+
const c5 = await ctx.client("agent").checkpoints.create(session, { manifest });
|
|
37140
|
+
ctx.result(c5, renderCheckpoint);
|
|
36973
37141
|
})
|
|
36974
37142
|
);
|
|
36975
37143
|
ckp.command("list").description("List checkpoints of a session").option("--session <id>", "session (default: current)").option("--limit <n>", "page size", (v) => parseIntOption(v, "--limit")).option("--cursor <cursor>", "page cursor").action(
|
|
@@ -37732,7 +37900,7 @@ function isReference(v) {
|
|
|
37732
37900
|
}
|
|
37733
37901
|
function entropy(s) {
|
|
37734
37902
|
const counts2 = /* @__PURE__ */ new Map();
|
|
37735
|
-
for (const
|
|
37903
|
+
for (const c5 of s) counts2.set(c5, (counts2.get(c5) ?? 0) + 1);
|
|
37736
37904
|
let h = 0;
|
|
37737
37905
|
for (const n of counts2.values()) {
|
|
37738
37906
|
const p = n / s.length;
|
|
@@ -38086,6 +38254,26 @@ var DISPOSABLE_DOMAINS = new Set(LIST.split(/\s+/).filter(Boolean));
|
|
|
38086
38254
|
// packages/domain/src/risk-score.ts
|
|
38087
38255
|
var NO_VELOCITY = Object.freeze({ sameNetwork24h: 0, sameMailbox: 0, reposFirstDay: 0, invitationsFirstDay: 0, forkChangesFirstDay: 0, starsFirstDay: 0 });
|
|
38088
38256
|
|
|
38257
|
+
// packages/domain/src/notifications.ts
|
|
38258
|
+
var on = (email3, push) => ({ in_app: "on", email: email3, push });
|
|
38259
|
+
var DEFAULT_MODES = {
|
|
38260
|
+
review_requested: on("immediate", "on"),
|
|
38261
|
+
review_available: on("off", "off"),
|
|
38262
|
+
response_required: on("off", "on"),
|
|
38263
|
+
check_failed: on("off", "on"),
|
|
38264
|
+
permission_request: on("off", "on"),
|
|
38265
|
+
merge_conflict: on("off", "on"),
|
|
38266
|
+
promotion_blocked: on("off", "on"),
|
|
38267
|
+
session_blocked: on("off", "on"),
|
|
38268
|
+
watching: on("off", "off"),
|
|
38269
|
+
secret_alert: on("immediate", "on"),
|
|
38270
|
+
mentioned: on("immediate", "on"),
|
|
38271
|
+
assigned: on("immediate", "on"),
|
|
38272
|
+
comment: on("off", "off"),
|
|
38273
|
+
approved: on("off", "on"),
|
|
38274
|
+
merged: on("off", "off")
|
|
38275
|
+
};
|
|
38276
|
+
|
|
38089
38277
|
// packages/cli/src/capture/normalize.ts
|
|
38090
38278
|
import { realpathSync } from "node:fs";
|
|
38091
38279
|
import { basename, dirname as dirname10, isAbsolute as isAbsolute4, relative, resolve as resolve3, sep } from "node:path";
|
|
@@ -38119,10 +38307,10 @@ function extractDecisions(text2, max = 3) {
|
|
|
38119
38307
|
return out;
|
|
38120
38308
|
}
|
|
38121
38309
|
function classifyCommand(command2) {
|
|
38122
|
-
const
|
|
38123
|
-
if (/\b(vitest|jest|pytest|mocha|rspec|phpunit|ctest|go test|cargo test|mvn test|gradle(w)? test|deno test|bun test|playwright test|(npm|pnpm|yarn)( run)? test(:\w+)?)\b/.test(
|
|
38124
|
-
if (/\b(eslint|prettier --check|ruff|flake8|clippy|golangci-lint|biome (check|lint)|(npm|pnpm|yarn)( run)? lint)\b/.test(
|
|
38125
|
-
if (/\b(tsc|make|cargo build|go build|webpack|vite build|esbuild|gradle(w)? build|mvn (package|compile)|(npm|pnpm|yarn)( run)? (build|typecheck|check))\b/.test(
|
|
38310
|
+
const c5 = command2.toLowerCase();
|
|
38311
|
+
if (/\b(vitest|jest|pytest|mocha|rspec|phpunit|ctest|go test|cargo test|mvn test|gradle(w)? test|deno test|bun test|playwright test|(npm|pnpm|yarn)( run)? test(:\w+)?)\b/.test(c5) || /\bnpm t\b/.test(c5)) return "test";
|
|
38312
|
+
if (/\b(eslint|prettier --check|ruff|flake8|clippy|golangci-lint|biome (check|lint)|(npm|pnpm|yarn)( run)? lint)\b/.test(c5)) return "lint";
|
|
38313
|
+
if (/\b(tsc|make|cargo build|go build|webpack|vite build|esbuild|gradle(w)? build|mvn (package|compile)|(npm|pnpm|yarn)( run)? (build|typecheck|check))\b/.test(c5)) return "build";
|
|
38126
38314
|
return "other";
|
|
38127
38315
|
}
|
|
38128
38316
|
|
|
@@ -38841,19 +39029,19 @@ async function flushSpool(env, baseUrl, client, now = Date.now(), agentFor, opts
|
|
|
38841
39029
|
for (const b of batches) await rm4(join11(dir, b), { force: true });
|
|
38842
39030
|
};
|
|
38843
39031
|
try {
|
|
38844
|
-
const
|
|
39032
|
+
const c5 = link?.client ?? client();
|
|
38845
39033
|
if (!meta3.repo_id) {
|
|
38846
39034
|
const [org, name] = meta3.repo.split("/");
|
|
38847
39035
|
meta3.repo_id = (await client().repos.getByName(org, name)).id;
|
|
38848
39036
|
}
|
|
38849
39037
|
const key = link ? `${meta3.client_key}@${link.sessionId}`.slice(0, 200) : meta3.client_key;
|
|
38850
|
-
const cap = await
|
|
39038
|
+
const cap = await c5.captures.upsert(meta3.repo_id, { client_key: key, tool: meta3.tool, model: meta3.model, started_at: meta3.started_at });
|
|
38851
39039
|
meta3.capture_id = cap.id;
|
|
38852
39040
|
await writeMeta(env, id2, meta3);
|
|
38853
39041
|
for (let i = 0; i < events.length; i += MAX_CAPTURE_EVENTS_PER_BATCH) {
|
|
38854
39042
|
const batch = events.slice(i, i + MAX_CAPTURE_EVENTS_PER_BATCH);
|
|
38855
39043
|
const along = i === 0 ? ride : [];
|
|
38856
|
-
const submit = (withSession) =>
|
|
39044
|
+
const submit = (withSession) => c5.captures.submit(cap.id, batch, withSession.length ? { sessionEvents: withSession.map(toSubmission) } : void 0);
|
|
38857
39045
|
try {
|
|
38858
39046
|
let res;
|
|
38859
39047
|
try {
|
|
@@ -39173,7 +39361,7 @@ function sessionLines(s, now, you) {
|
|
|
39173
39361
|
...s.paths.length ? [` touching: ${pathList(s.paths)}`] : []
|
|
39174
39362
|
];
|
|
39175
39363
|
}
|
|
39176
|
-
var claimLine = (
|
|
39364
|
+
var claimLine = (c5) => ` ${c5.key} ${c5.holder.display_name ?? c5.holder.id}${c5.session_id ? ` (${c5.session_id})` : ""}${c5.change ? ` \xB7 change #${c5.change.number}` : ""}${c5.note ? ` \xB7 ${c5.note}` : ""}`;
|
|
39177
39365
|
function renderStatus(st, now = Date.now()) {
|
|
39178
39366
|
const others = st.sessions.filter((s) => s.id !== st.you);
|
|
39179
39367
|
const out = [others.length ? `${others.length} other agent session${others.length === 1 ? "" : "s"} working in this repository.` : "No other agent sessions are working in this repository."];
|
|
@@ -39396,7 +39584,7 @@ function agentUploads(ctx) {
|
|
|
39396
39584
|
const t = ctx.token("user").token;
|
|
39397
39585
|
if (!t || !isPersonToken(t) || !agentSessionsEnabled(ctx.deps.env)) return void 0;
|
|
39398
39586
|
return async (meta3) => {
|
|
39399
|
-
const tool = Object.entries(AGENT_RUNTIME_CAPTURE_TOOL).find(([,
|
|
39587
|
+
const tool = Object.entries(AGENT_RUNTIME_CAPTURE_TOOL).find(([, c5]) => c5 === meta3.tool)?.[0];
|
|
39400
39588
|
if (!tool) return null;
|
|
39401
39589
|
if (!meta3.repo_id) {
|
|
39402
39590
|
const [org, name] = meta3.repo.split("/");
|
|
@@ -39428,8 +39616,8 @@ async function readStdinCapped(deps) {
|
|
|
39428
39616
|
function startFlush(deps) {
|
|
39429
39617
|
if (deps.env.BRNCH_CAPTURE_NO_FLUSH !== "1") deps.spawnBackground(["capture", "flush", "--quiet"]);
|
|
39430
39618
|
}
|
|
39431
|
-
async function runHook(deps,
|
|
39432
|
-
|
|
39619
|
+
async function runHook(deps, state2, tool, eventArg) {
|
|
39620
|
+
state2.noUpdateHint = true;
|
|
39433
39621
|
let out = "";
|
|
39434
39622
|
try {
|
|
39435
39623
|
if (eventArg === "git-post-commit") return await postCommit(deps);
|
|
@@ -39493,7 +39681,7 @@ async function runHook(deps, state, tool, eventArg) {
|
|
|
39493
39681
|
await logError(deps.env, `hook ${tool ?? "?"} ${eventArg ?? "?"}: ${e instanceof Error ? e.message : String(e)}`);
|
|
39494
39682
|
} finally {
|
|
39495
39683
|
if (out) deps.stdout.write(out);
|
|
39496
|
-
|
|
39684
|
+
state2.exitCode = EXIT.OK;
|
|
39497
39685
|
}
|
|
39498
39686
|
}
|
|
39499
39687
|
async function postCommit(deps) {
|
|
@@ -39752,8 +39940,8 @@ ${report3.errors.join("\n")}` : ""}`);
|
|
|
39752
39940
|
);
|
|
39753
39941
|
capture.command("show <capture>").description("Show a captured session and its events").option("--limit <n>", "events to show", (v) => parseIntOption(v, "--limit"), 100).action(
|
|
39754
39942
|
act(rt, async (ctx, o, [id2]) => {
|
|
39755
|
-
const
|
|
39756
|
-
const [cap, events] = await Promise.all([
|
|
39943
|
+
const c5 = ctx.client("user");
|
|
39944
|
+
const [cap, events] = await Promise.all([c5.captures.get(id2), c5.captures.events(id2, { limit: o.limit })]);
|
|
39757
39945
|
ctx.result(
|
|
39758
39946
|
{ capture: cap, events: events.items },
|
|
39759
39947
|
(v) => `${kv(v.capture, ["id", "tool", "model", "provenance", "captured_by.name", "state", "started_at", "edit_count", "linked_commits"])}
|
|
@@ -39783,13 +39971,13 @@ ${table(
|
|
|
39783
39971
|
);
|
|
39784
39972
|
capture.command("policy").description("Show or change the organization's capture policy (changes need org admin)").option("--allow <on|off>", "accept capture uploads at all").option("--prompts <on|off>", "accept prompt text").option("--reasoning <on|off>", "accept reasoning summaries and extracted decisions").option("--retention-days <n>", "keep capture data this many days after its last event", (v) => parseIntOption(v, "--retention-days")).action(
|
|
39785
39973
|
act(rt, async (ctx, o) => {
|
|
39786
|
-
const
|
|
39974
|
+
const c5 = ctx.client("user");
|
|
39787
39975
|
const patch = {};
|
|
39788
39976
|
if (o.allow !== void 0) patch.allowed = onOff(o.allow, "--allow");
|
|
39789
39977
|
if (o.prompts !== void 0) patch.prompts_allowed = onOff(o.prompts, "--prompts");
|
|
39790
39978
|
if (o.reasoning !== void 0) patch.reasoning_allowed = onOff(o.reasoning, "--reasoning");
|
|
39791
39979
|
if (o.retentionDays !== void 0) patch.retention_days = o.retentionDays;
|
|
39792
|
-
const p = Object.keys(patch).length ? await
|
|
39980
|
+
const p = Object.keys(patch).length ? await c5.captures.policy.update(ctx.org(), patch) : await c5.captures.policy.get(ctx.org());
|
|
39793
39981
|
ctx.result(p, (v) => kv(v, ["org_id", "allowed", "prompts_allowed", "reasoning_allowed", "retention_days", "me.opted_out", "updated_at"]));
|
|
39794
39982
|
})
|
|
39795
39983
|
);
|
|
@@ -39917,7 +40105,7 @@ async function storeVerified(ctx, cred) {
|
|
|
39917
40105
|
expires_at: cred.expires_at,
|
|
39918
40106
|
agent_sign_in: cred.agent_runtime ?? null,
|
|
39919
40107
|
...cred.kind === "oauth" ? { scopes: cred.scopes ?? null } : {},
|
|
39920
|
-
other_accounts: Object.values(others).map((
|
|
40108
|
+
other_accounts: Object.values(others).map((c5) => accountLabel(c5.account))
|
|
39921
40109
|
};
|
|
39922
40110
|
}
|
|
39923
40111
|
async function revokeStored(ctx, cred) {
|
|
@@ -40193,12 +40381,12 @@ Warning: ${v.remaining === 0 ? "no unused backup codes left" : `only ${v.remaini
|
|
|
40193
40381
|
if (!code) throw usage("pass --code <code>: a current authenticator code or an unused backup code (--code - reads it from stdin)");
|
|
40194
40382
|
ctx.addSecret(code);
|
|
40195
40383
|
const r = await ctx.client("user").auth.backupCodes.regenerate({ code });
|
|
40196
|
-
for (const
|
|
40384
|
+
for (const c5 of r.backup_codes) ctx.addSecret(c5);
|
|
40197
40385
|
ctx.result(
|
|
40198
40386
|
r,
|
|
40199
40387
|
(v) => `New backup codes. They are shown only now; each works once, and your previous codes no longer work:
|
|
40200
40388
|
|
|
40201
|
-
${v.backup_codes.map((
|
|
40389
|
+
${v.backup_codes.map((c5) => ` ${c5}`).join("\n")}
|
|
40202
40390
|
|
|
40203
40391
|
Store them somewhere safe and offline (a password manager or on paper).`
|
|
40204
40392
|
);
|
|
@@ -40916,10 +41104,10 @@ async function localKeyRegistered(w, alias) {
|
|
|
40916
41104
|
return keys.some((k) => registered.has(k.fingerprint));
|
|
40917
41105
|
}
|
|
40918
41106
|
async function stepSsh(w, signedIn2) {
|
|
40919
|
-
const
|
|
41107
|
+
const state2 = { alias: null, keyRegistered: false };
|
|
40920
41108
|
if (!w.o.ssh) {
|
|
40921
41109
|
w.record("ssh", "skipped", "--no-ssh");
|
|
40922
|
-
return
|
|
41110
|
+
return state2;
|
|
40923
41111
|
}
|
|
40924
41112
|
let doc;
|
|
40925
41113
|
try {
|
|
@@ -40929,7 +41117,7 @@ async function stepSsh(w, signedIn2) {
|
|
|
40929
41117
|
}
|
|
40930
41118
|
if (!doc?.enabled || !doc.keys.length) {
|
|
40931
41119
|
w.record("ssh", "skipped", `SSH is not enabled on ${w.ctx.baseUrl}; HTTPS will be used`);
|
|
40932
|
-
return
|
|
41120
|
+
return state2;
|
|
40933
41121
|
}
|
|
40934
41122
|
const alias = defaultSshAlias(w.ctx, doc.host);
|
|
40935
41123
|
const configPath = join18(sshDir(w.ctx), "config");
|
|
@@ -40939,14 +41127,14 @@ async function stepSsh(w, signedIn2) {
|
|
|
40939
41127
|
const ok = w.ctx.interactive && !w.o.dryRun && await w.confirm(`${configPath} already has a "Host ${alias}" entry. Add the ${BRAND.cli} block anyway (yours stays, but the first match wins)?`, false);
|
|
40940
41128
|
if (!ok) {
|
|
40941
41129
|
w.record("ssh", "skipped", `${configPath} already has "Host ${alias}" (left untouched)`);
|
|
40942
|
-
return
|
|
41130
|
+
return state2;
|
|
40943
41131
|
}
|
|
40944
41132
|
}
|
|
40945
41133
|
const ready = ours2 && signedIn2 && await localKeyRegistered(w, alias);
|
|
40946
41134
|
const what = signedIn2 ? "adds a block to ~/.ssh/config, pins the host key, registers a key and tests it" : "adds a block to ~/.ssh/config and pins the host key; keys need sign-in";
|
|
40947
41135
|
if (!w.apply || !ready && !await w.confirm(`Set up git over SSH for ${alias} (${what})?`)) {
|
|
40948
41136
|
w.record("ssh", w.o.dryRun || w.pendingConsent ? "planned" : "skipped", `\`${BRAND.cli} ssh setup\` (${alias})`);
|
|
40949
|
-
return
|
|
41137
|
+
return state2;
|
|
40950
41138
|
}
|
|
40951
41139
|
const args = [
|
|
40952
41140
|
...w.ctx.globals.yes ? ["--yes"] : [],
|
|
@@ -40958,8 +41146,8 @@ async function stepSsh(w, signedIn2) {
|
|
|
40958
41146
|
];
|
|
40959
41147
|
const r = await w.run(args);
|
|
40960
41148
|
if (r.code === 0) {
|
|
40961
|
-
|
|
40962
|
-
|
|
41149
|
+
state2.alias = alias;
|
|
41150
|
+
state2.keyRegistered = signedIn2;
|
|
40963
41151
|
}
|
|
40964
41152
|
const untested = r.code === 0 && signedIn2 ? await unattendedApproval(w.ctx, alias) : null;
|
|
40965
41153
|
w.record(
|
|
@@ -40967,7 +41155,7 @@ async function stepSsh(w, signedIn2) {
|
|
|
40967
41155
|
r.code !== 0 ? "failed" : ready ? "already" : "done",
|
|
40968
41156
|
r.code !== 0 ? `\`${BRAND.cli} ssh setup\` exited ${r.code} (see above; \`${BRAND.cli} ssh test\` explains)` : untested ? `${alias}: key registered, not tested: ${untested} asks to approve each use and nobody is at this terminal (\`${BRAND.cli} ssh test\`)` : signedIn2 ? `${alias}: key registered and verified with ssh -T` : `${alias} configured; sign in, then \`${BRAND.cli} ssh setup\` registers a key`
|
|
40969
41157
|
);
|
|
40970
|
-
return
|
|
41158
|
+
return state2;
|
|
40971
41159
|
}
|
|
40972
41160
|
async function stepGit(w) {
|
|
40973
41161
|
const origin = new URL(w.ctx.baseUrl).origin;
|
|
@@ -41025,7 +41213,7 @@ async function stepInstructions(w, root) {
|
|
|
41025
41213
|
w.record("instructions", "skipped", "not in a git repository");
|
|
41026
41214
|
return;
|
|
41027
41215
|
}
|
|
41028
|
-
const detected = (await detectTools(w.ctx.deps)).map((
|
|
41216
|
+
const detected = (await detectTools(w.ctx.deps)).map((c5) => Object.entries(AGENT_RUNTIME_CAPTURE_TOOL).find(([, x]) => x === c5)?.[0] ?? null);
|
|
41029
41217
|
const tools = [...new Set([w.ctx.agent?.tool ?? null, ...detected].filter((t) => !!t))];
|
|
41030
41218
|
if (!tools.length) {
|
|
41031
41219
|
w.record("instructions", "skipped", "no coding agent found");
|
|
@@ -41129,8 +41317,8 @@ async function stepRepo(w, me, ns, ssh) {
|
|
|
41129
41317
|
if (!files) await w.ctx.deps.writeFile(join18(dir, "README.md"), `# ${name}
|
|
41130
41318
|
`);
|
|
41131
41319
|
await git(w, dir, ["add", "-A"]);
|
|
41132
|
-
const
|
|
41133
|
-
if (
|
|
41320
|
+
const c5 = await git(w, dir, ["commit", "-q", "-m", "Initial commit"]);
|
|
41321
|
+
if (c5.code !== 0) throw new Error(`initial commit failed (is git user.name/user.email configured?): ${c5.stderr.trim().slice(0, 200)}`);
|
|
41134
41322
|
}
|
|
41135
41323
|
await initialPush(w, repo, remote);
|
|
41136
41324
|
w.record("repo", "done", `created ${ns}/${name}, remote ${remote} \u2192 ${url2}, pushed ${repo.default_branch}`);
|
|
@@ -41148,20 +41336,20 @@ function registerSetup(program2, rt) {
|
|
|
41148
41336
|
rt.state.noUpdateHint = true;
|
|
41149
41337
|
const bad = [...o.skip ?? [], ...o.only ?? []].filter((s) => !SETUP_STEPS.includes(s));
|
|
41150
41338
|
if (bad.length) throw usage(`unknown step(s) ${bad.join(", ")}; steps: ${SETUP_STEPS.join(", ")}`);
|
|
41151
|
-
const
|
|
41339
|
+
const on2 = (s) => (!o.only?.length || o.only.includes(s)) && !o.skip?.includes(s);
|
|
41152
41340
|
const w = new Wizard(ctx, rt, o);
|
|
41153
41341
|
if (!ctx.json) ctx.info(`${BRAND.cli} setup for ${ctx.baseUrl}${o.dryRun ? " (dry run: nothing will change)" : !w.apply ? " (non-interactive: showing the plan; pass --yes to apply)" : ""}`);
|
|
41154
|
-
const me =
|
|
41342
|
+
const me = on2("signin") ? await stepSignin(w) : await w.me();
|
|
41155
41343
|
const signedIn2 = !!me?.user;
|
|
41156
|
-
const ssh =
|
|
41344
|
+
const ssh = on2("ssh") ? await stepSsh(w, signedIn2) : { alias: null, keyRegistered: false };
|
|
41157
41345
|
if (o.hooksScope !== "user" && o.hooksScope !== "project") throw usage("--hooks-scope must be user or project");
|
|
41158
|
-
const ns =
|
|
41159
|
-
if (
|
|
41160
|
-
if (
|
|
41161
|
-
if (
|
|
41162
|
-
if (
|
|
41163
|
-
if (
|
|
41164
|
-
if (
|
|
41346
|
+
const ns = on2("integrations") || on2("repo") ? signedIn2 ? await pickNamespace(w, me) : null : null;
|
|
41347
|
+
if (on2("repo") && o.hooksScope === "project") await stepRepo(w, me, ns, ssh);
|
|
41348
|
+
if (on2("hooks")) await stepHooks(w, await gitToplevel(w.ctx.deps, w.ctx.deps.cwd));
|
|
41349
|
+
if (on2("instructions")) await stepInstructions(w, await gitToplevel(w.ctx.deps, w.ctx.deps.cwd));
|
|
41350
|
+
if (on2("integrations")) await stepIntegrations(w, ns);
|
|
41351
|
+
if (on2("repo") && o.hooksScope !== "project") await stepRepo(w, me, ns, ssh);
|
|
41352
|
+
if (on2("git")) await stepGit(w);
|
|
41165
41353
|
const failed = w.outcomes.some((x) => x.status === "failed");
|
|
41166
41354
|
const planned = w.outcomes.some((x) => x.status === "planned");
|
|
41167
41355
|
ctx.result(
|
|
@@ -41395,7 +41583,7 @@ function colorEnabled(deps, stream) {
|
|
|
41395
41583
|
if (env.TERM === "dumb") return false;
|
|
41396
41584
|
return stream === "stdout" ? deps.stdoutIsTTY : deps.stderrIsTTY;
|
|
41397
41585
|
}
|
|
41398
|
-
var sgr = (
|
|
41586
|
+
var sgr = (on2, code) => (s) => on2 ? `\x1B[${code}m${s}\x1B[0m` : s;
|
|
41399
41587
|
function paint(enabled) {
|
|
41400
41588
|
return { ok: sgr(enabled, "32"), warn: sgr(enabled, "33"), fail: sgr(enabled, "31"), dim: sgr(enabled, "2"), bold: sgr(enabled, "1"), accent: sgr(enabled, "38;5;104") };
|
|
41401
41589
|
}
|
|
@@ -41571,12 +41759,12 @@ function cells() {
|
|
|
41571
41759
|
const grid = [];
|
|
41572
41760
|
for (let r = 0; r < ROWS; r++) {
|
|
41573
41761
|
const row = [];
|
|
41574
|
-
for (let
|
|
41762
|
+
for (let c5 = 0; c5 < COLS; c5++) {
|
|
41575
41763
|
const times = [];
|
|
41576
41764
|
let head = 0;
|
|
41577
41765
|
for (let sy = 0; sy < SS; sy++)
|
|
41578
41766
|
for (let sx = 0; sx < SS; sx++) {
|
|
41579
|
-
const x = VIEW.x0 + (
|
|
41767
|
+
const x = VIEW.x0 + (c5 + (sx + 0.5) / SS) / COLS * (VIEW.x1 - VIEW.x0);
|
|
41580
41768
|
const y = VIEW.y0 + (r + (sy + 0.5) / SS) / ROWS * (VIEW.y1 - VIEW.y0);
|
|
41581
41769
|
if (!insideMark(g2, x, y)) continue;
|
|
41582
41770
|
times.push(drawTime(g2, x, y));
|
|
@@ -42342,7 +42530,7 @@ var renderTask = (t) => kv({ ...t, claimed_by: t.claim ? `${t.claim.actor.type}
|
|
|
42342
42530
|
${t.description}` : "") + (t.acceptance_criteria.length ? `
|
|
42343
42531
|
|
|
42344
42532
|
Acceptance criteria:
|
|
42345
|
-
${t.acceptance_criteria.map((
|
|
42533
|
+
${t.acceptance_criteria.map((c5) => ` - ${c5}`).join("\n")}` : "");
|
|
42346
42534
|
async function bodyFrom(ctx, o, required2 = true) {
|
|
42347
42535
|
if (o.body !== void 0 && o.file !== void 0) throw usage("pass either --body or --file, not both");
|
|
42348
42536
|
if (o.file !== void 0) return readText(fileSpec(o.file), ctx.input);
|
|
@@ -42368,9 +42556,9 @@ function registerTask(program2, rt) {
|
|
|
42368
42556
|
task.command("view <task>").description("Show a task").action(act(rt, async (ctx, _o, [id2]) => ctx.result(await ctx.client().tasks.get(id2), renderTask)));
|
|
42369
42557
|
task.command("update <task>").description("Update fields; uses the current version unless --expected-version pins it (then stale edits fail with exit 5)").option("--title <title>", "title").option("--body <text>", "description").option("--file <path>", "description from a file or -").option("--state <state>", "open | in_progress | blocked | done | cancelled").option("--owner <user-id>", "owner user id ('none' to clear)").option("--label <label>", "replace labels (repeatable)", repeat).option("--expected-version <n>", "expected version (optimistic concurrency)", (v) => parseIntOption(v, "--expected-version")).action(
|
|
42370
42558
|
act(rt, async (ctx, o, [id2]) => {
|
|
42371
|
-
const
|
|
42372
|
-
const version4 = o.expectedVersion ?? (await
|
|
42373
|
-
const t = await
|
|
42559
|
+
const c5 = ctx.client();
|
|
42560
|
+
const version4 = o.expectedVersion ?? (await c5.tasks.get(id2)).version;
|
|
42561
|
+
const t = await c5.tasks.update(id2, {
|
|
42374
42562
|
title: o.title,
|
|
42375
42563
|
description: await bodyFrom(ctx, o, false),
|
|
42376
42564
|
state: o.state,
|
|
@@ -42411,7 +42599,7 @@ ${table(u.by_feature, ["feature", "calls", "input_tokens", "output_tokens"])}`;
|
|
|
42411
42599
|
var citation = (r) => `${r.path}${r.start_line ? `:${r.start_line}${r.end_line && r.end_line !== r.start_line ? `-${r.end_line}` : ""}` : ""}`;
|
|
42412
42600
|
var renderCited = (label2, a) => [
|
|
42413
42601
|
label2,
|
|
42414
|
-
a.claims.length ? a.claims.map((
|
|
42602
|
+
a.claims.length ? a.claims.map((c5) => ` - ${c5.text} (${c5.refs.map(citation).join(", ")})`).join("\n") : " (no verifiable statements)",
|
|
42415
42603
|
a.follow_ups.length ? `follow-up questions:
|
|
42416
42604
|
${a.follow_ups.map((f) => ` ? ${f}`).join("\n")}` : "",
|
|
42417
42605
|
a.dropped.claims ? `${a.dropped.claims} unverifiable statement(s) discarded` : ""
|
|
@@ -42481,7 +42669,7 @@ function registerAi(program2, rt) {
|
|
|
42481
42669
|
const x = await ctx.client().ai.explainChange(await ctx.changeId(id2));
|
|
42482
42670
|
const ref = (r) => `${r.path}${r.start_line ? `:${r.start_line}${r.end_line && r.end_line !== r.start_line ? `-${r.end_line}` : ""}` : ""}`;
|
|
42483
42671
|
const claims = (title, items) => items.length ? `${title}
|
|
42484
|
-
${items.map((
|
|
42672
|
+
${items.map((c5) => ` - ${c5.severity ? `[${c5.severity}] ` : ""}${c5.text} (${c5.refs.map(ref).join(", ")})`).join("\n")}` : "";
|
|
42485
42673
|
ctx.result(
|
|
42486
42674
|
x,
|
|
42487
42675
|
(v) => [aiLabel(v.ai), claims("Overview", v.overview), claims("Files", v.files.map((f) => ({ text: `${f.path}: ${f.summary}`, refs: [] }))), claims("Risks", v.risks), claims("Notable", v.notable), v.dropped.claims ? `${v.dropped.claims} unverifiable claim(s) discarded` : ""].filter(Boolean).join("\n\n")
|
|
@@ -42549,8 +42737,8 @@ ${v.description}`);
|
|
|
42549
42737
|
}
|
|
42550
42738
|
|
|
42551
42739
|
// packages/cli/src/commands/change.ts
|
|
42552
|
-
var renderChange = (
|
|
42553
|
-
{ ...
|
|
42740
|
+
var renderChange = (c5) => kv(
|
|
42741
|
+
{ ...c5, source: c5.source.workspace_id ?? c5.source.ref, author: `${c5.author.type} ${c5.author.id}`, revision: `#${c5.current_revision.number} ${c5.current_revision.id}` },
|
|
42554
42742
|
["number", "id", "title", "state", "target_ref", "source", "task_id", "author", "revision", "current_revision.head_oid", "revision_count", "merged", "version"]
|
|
42555
42743
|
);
|
|
42556
42744
|
var renderReadiness = (r) => [
|
|
@@ -42565,13 +42753,13 @@ Checks:
|
|
|
42565
42753
|
${table(r.checks, ["name", "status", "satisfied", "evidence_id"])}` : ""
|
|
42566
42754
|
].filter(Boolean).join("\n");
|
|
42567
42755
|
var renderThread = (t) => `${t.id} [${t.state}${t.blocking ? ", blocking" : ""}${t.anchor.outdated ? ", outdated" : ""}] ${t.anchor.path ?? "(change)"}${t.anchor.start_line ? `:${t.anchor.start_line}` : ""}
|
|
42568
|
-
` + t.comments.map((
|
|
42756
|
+
` + t.comments.map((c5) => ` ${c5.author.display_name ?? c5.author.id}: ${c5.body.split("\n").join("\n ")}`).join("\n");
|
|
42569
42757
|
function registerChange(program2, rt) {
|
|
42570
42758
|
const change = program2.command("change").description("Changes (proposed updates to a protected ref)");
|
|
42571
42759
|
change.command("create").description("Create a change from a workspace or a ref in --repo").requiredOption("--title <title>", "title").option("--body <text>", "description (Markdown; @file or - for stdin)").option("--file <path>", "read the description from a file or -").option("--workspace <id>", "source workspace").option("--ref <ref>", "source ref (e.g. refs/heads/feature)").option("--target <ref>", "target ref (default: the repository's default branch)").option("--task <id>", "linked task").option("--draft", "create as draft").action(
|
|
42572
42760
|
act(rt, async (ctx, o) => {
|
|
42573
42761
|
if (!!o.workspace === !!o.ref) throw usage("pass exactly one of --workspace <id> or --ref <ref>");
|
|
42574
|
-
const
|
|
42762
|
+
const c5 = await ctx.client().changes.create(await ctx.repoId(), {
|
|
42575
42763
|
title: o.title,
|
|
42576
42764
|
description: await bodyFrom(ctx, o, false),
|
|
42577
42765
|
source: o.workspace ? { workspace_id: o.workspace } : { ref: o.ref },
|
|
@@ -42579,7 +42767,7 @@ function registerChange(program2, rt) {
|
|
|
42579
42767
|
task_id: o.task,
|
|
42580
42768
|
draft: o.draft ?? false
|
|
42581
42769
|
});
|
|
42582
|
-
ctx.result(
|
|
42770
|
+
ctx.result(c5, renderChange);
|
|
42583
42771
|
})
|
|
42584
42772
|
);
|
|
42585
42773
|
change.command("list").description("List changes in --repo").option("--state <state>", "draft | open | merged | closed").option("--limit <n>", "page size", (v) => parseIntOption(v, "--limit")).option("--cursor <cursor>", "page cursor").action(
|
|
@@ -42608,26 +42796,26 @@ function registerChange(program2, rt) {
|
|
|
42608
42796
|
);
|
|
42609
42797
|
change.command("diff").argument("<change>", CHANGE_ARG).description("Changed files, or the diff of one file with --path").option("--revision <id>", "revision (default: current)").option("--against <base|revision-id>", "compare against the base (default) or another revision").option("--path <path>", "show the hunks for this file").action(
|
|
42610
42798
|
act(rt, async (ctx, o, [spec]) => {
|
|
42611
|
-
const
|
|
42799
|
+
const c5 = ctx.client();
|
|
42612
42800
|
const id2 = await ctx.changeId(spec);
|
|
42613
42801
|
if (o.path) {
|
|
42614
|
-
const d = await
|
|
42802
|
+
const d = await c5.changes.diff(id2, { revision: o.revision, against: o.against, path: o.path });
|
|
42615
42803
|
return ctx.result(d, (v) => unifiedDiff(v));
|
|
42616
42804
|
}
|
|
42617
|
-
const files = await
|
|
42805
|
+
const files = await c5.changes.files(id2, { revision: o.revision, against: o.against });
|
|
42618
42806
|
ctx.result(files, (v) => table(v.files.map((f) => ({ ...f, path: f.new_path ?? f.old_path })), ["status", "path"]) + (v.truncated ? "\n(truncated)" : ""));
|
|
42619
42807
|
})
|
|
42620
42808
|
);
|
|
42621
42809
|
change.command("depend").argument("<change>", CHANGE_ARG).argument("[predecessor]", `the change it depends on: ${CHANGE_ARG}`).description("Make <change> depend on [predecessor]; without it, list dependencies").option("--remove <dependency-id>", "remove a dependency instead").action(
|
|
42622
42810
|
act(rt, async (ctx, o, [spec, predecessor]) => {
|
|
42623
|
-
const
|
|
42811
|
+
const c5 = ctx.client();
|
|
42624
42812
|
const id2 = await ctx.changeId(spec);
|
|
42625
42813
|
if (o.remove) {
|
|
42626
|
-
await
|
|
42814
|
+
await c5.changes.dependencies.remove(id2, o.remove);
|
|
42627
42815
|
return ctx.result({ change_id: id2, removed: o.remove }, `Removed dependency ${o.remove}`);
|
|
42628
42816
|
}
|
|
42629
|
-
if (predecessor) return ctx.result(await
|
|
42630
|
-
const page = await
|
|
42817
|
+
if (predecessor) return ctx.result(await c5.changes.dependencies.add(id2, { predecessor_change_id: await ctx.changeId(predecessor) }), (v) => kv(v, ["id", "predecessor_change_id", "successor_change_id", "predecessor_state"]));
|
|
42818
|
+
const page = await c5.changes.dependencies.list(id2);
|
|
42631
42819
|
ctx.result(page, (v) => listWithCursor(v, ["id", "predecessor_change_id", "predecessor_state", "accessible"]));
|
|
42632
42820
|
})
|
|
42633
42821
|
);
|
|
@@ -42642,10 +42830,10 @@ function registerReview(program2, rt) {
|
|
|
42642
42830
|
);
|
|
42643
42831
|
review.command("comment").argument("<change>", CHANGE_ARG).description("Open a review thread, optionally anchored to a file and line range").option("--body <text>", "comment (Markdown; @file or - for stdin)").option("--file <path>", "read the comment from a file or -").option("--revision <id>", "revision (default: current)").option("--path <path>", "anchor file").option("--line <n>", "anchor start line", (v) => parseIntOption(v, "--line")).option("--end-line <n>", "anchor end line", (v) => parseIntOption(v, "--end-line")).option("--side <side>", "old | new", "new").option("--non-blocking", "do not block merge on this thread").action(
|
|
42644
42832
|
act(rt, async (ctx, o, [spec]) => {
|
|
42645
|
-
const
|
|
42833
|
+
const c5 = ctx.client();
|
|
42646
42834
|
const id2 = await ctx.changeId(spec);
|
|
42647
|
-
const revision = o.revision ?? (await
|
|
42648
|
-
const t = await
|
|
42835
|
+
const revision = o.revision ?? (await c5.changes.get(id2)).current_revision.id;
|
|
42836
|
+
const t = await c5.threads.create(id2, {
|
|
42649
42837
|
revision_id: revision,
|
|
42650
42838
|
body: await bodyFrom(ctx, o),
|
|
42651
42839
|
path: o.path,
|
|
@@ -42660,19 +42848,19 @@ function registerReview(program2, rt) {
|
|
|
42660
42848
|
review.command("reply <thread>").description("Reply to a thread").option("--body <text>", "reply (Markdown; @file or - for stdin)").option("--file <path>", "read the reply from a file or -").action(act(rt, async (ctx, o, [id2]) => ctx.result(await ctx.client().threads.reply(id2, { body: await bodyFrom(ctx, o) }), renderThread)));
|
|
42661
42849
|
review.command("fix <thread>").description("Link the revision that addresses a thread (state becomes fix_submitted; a reviewer resolves it)").option("--revision <id>", "fixing revision").option("--change <change>", `use this change's current revision (${CHANGE_ARG})`).option("--commit <oid>", "fixing commit").option("--note <text>", "note").action(
|
|
42662
42850
|
act(rt, async (ctx, o, [id2]) => {
|
|
42663
|
-
const
|
|
42851
|
+
const c5 = ctx.client();
|
|
42664
42852
|
if (!o.revision && !o.change) throw usage("pass --revision <id> or --change <change>");
|
|
42665
|
-
const revision = o.revision ?? (await
|
|
42666
|
-
ctx.result(await
|
|
42853
|
+
const revision = o.revision ?? (await c5.changes.get(await ctx.changeId(o.change))).current_revision.id;
|
|
42854
|
+
ctx.result(await c5.threads.fix(id2, { revision_id: revision, commit_oid: o.commit, note: o.note }), renderThread);
|
|
42667
42855
|
})
|
|
42668
42856
|
);
|
|
42669
42857
|
review.command("resolve <thread>").description("Resolve a thread (requires review:resolve)").action(act(rt, async (ctx, _o, [id2]) => ctx.result(await ctx.client().threads.resolve(id2), renderThread)));
|
|
42670
42858
|
const decide = (name, decision, description, bodyRequired) => review.command(name).argument("<change>", CHANGE_ARG).description(description).option("--body <text>", "review body (Markdown; @file or - for stdin)").option("--file <path>", "read the body from a file or -").option("--revision <id>", "revision being reviewed (default: current)").action(
|
|
42671
42859
|
act(rt, async (ctx, o, [spec]) => {
|
|
42672
|
-
const
|
|
42860
|
+
const c5 = ctx.client();
|
|
42673
42861
|
const id2 = await ctx.changeId(spec);
|
|
42674
|
-
const revision = o.revision ?? (await
|
|
42675
|
-
const r = await
|
|
42862
|
+
const revision = o.revision ?? (await c5.changes.get(id2)).current_revision.id;
|
|
42863
|
+
const r = await c5.reviews.create(id2, { revision_id: revision, decision, body: await bodyFrom(ctx, o, bodyRequired) });
|
|
42676
42864
|
ctx.result(r, (v) => kv({ ...v, reviewer: `${v.reviewer.type} ${v.reviewer.id}` }, ["id", "decision", "revision_id", "reviewer", "current"]));
|
|
42677
42865
|
})
|
|
42678
42866
|
);
|
|
@@ -42681,18 +42869,18 @@ function registerReview(program2, rt) {
|
|
|
42681
42869
|
}
|
|
42682
42870
|
|
|
42683
42871
|
// packages/cli/src/commands/code-review.ts
|
|
42684
|
-
async function allThreads(
|
|
42872
|
+
async function allThreads(c5, change) {
|
|
42685
42873
|
const out = [];
|
|
42686
42874
|
let cursor2;
|
|
42687
42875
|
do {
|
|
42688
|
-
const page = await
|
|
42876
|
+
const page = await c5.threads.list(change, { limit: 100, cursor: cursor2 });
|
|
42689
42877
|
out.push(...page.items);
|
|
42690
42878
|
cursor2 = page.next_cursor ?? void 0;
|
|
42691
42879
|
} while (cursor2);
|
|
42692
42880
|
return out;
|
|
42693
42881
|
}
|
|
42694
|
-
async function findings(
|
|
42695
|
-
const [ch, list2, threads] = await Promise.all([
|
|
42882
|
+
async function findings(c5, change, all) {
|
|
42883
|
+
const [ch, list2, threads] = await Promise.all([c5.changes.get(change), c5.codeReview.reviews.list(change), allThreads(c5, change)]);
|
|
42696
42884
|
const rev = ch.current_revision.id;
|
|
42697
42885
|
const latest = /* @__PURE__ */ new Map();
|
|
42698
42886
|
for (const r of list2.items) if (r.revision_id === rev && !latest.has(r.provider)) latest.set(r.provider, r);
|
|
@@ -42719,11 +42907,11 @@ ${f.findings.map(renderThread).join("\n\n")}` : f.pending ? "" : "\n\nNo open fi
|
|
|
42719
42907
|
return head + body;
|
|
42720
42908
|
}
|
|
42721
42909
|
async function waitDone(ctx, change, interval, timeout) {
|
|
42722
|
-
const
|
|
42910
|
+
const c5 = ctx.client();
|
|
42723
42911
|
const deadline = Date.now() + timeout * 1e3;
|
|
42724
42912
|
let said = "";
|
|
42725
42913
|
for (; ; ) {
|
|
42726
|
-
const f = await findings(
|
|
42914
|
+
const f = await findings(c5, change, false);
|
|
42727
42915
|
const now = f.reviews.map((r) => `${CODE_REVIEW_PROVIDER_NAMES[r.provider]}: ${r.status}`).join(", ");
|
|
42728
42916
|
if (now && now !== said) ctx.info(now);
|
|
42729
42917
|
said = now;
|
|
@@ -42747,13 +42935,13 @@ function registerCodeReview(program2, rt) {
|
|
|
42747
42935
|
);
|
|
42748
42936
|
cr.command("request").argument("<change>", CHANGE_ARG).description("Review the current revision again (spends the organization's vendor credits; needs repository write)").option("--provider <provider>", `${CODE_REVIEW_PROVIDERS.join(" | ")} (default: every service set up for the repository)`).action(
|
|
42749
42937
|
act(rt, async (ctx, o, [spec]) => {
|
|
42750
|
-
const
|
|
42938
|
+
const c5 = ctx.client();
|
|
42751
42939
|
const id2 = await ctx.changeId(spec);
|
|
42752
42940
|
if (o.provider && !CODE_REVIEW_PROVIDERS.includes(o.provider)) throw usage(`--provider must be one of ${CODE_REVIEW_PROVIDERS.join(", ")}`);
|
|
42753
|
-
const providers = o.provider ? [o.provider] : (await
|
|
42941
|
+
const providers = o.provider ? [o.provider] : (await c5.codeReview.reviews.list(id2)).providers;
|
|
42754
42942
|
if (!providers.length) throw usage("no AI review service is set up for this repository");
|
|
42755
42943
|
const items = [];
|
|
42756
|
-
for (const provider of providers) items.push(await
|
|
42944
|
+
for (const provider of providers) items.push(await c5.codeReview.reviews.request(id2, { provider }));
|
|
42757
42945
|
ctx.result({ items }, (v) => `${table(v.items.map((r) => ({ service: CODE_REVIEW_PROVIDER_NAMES[r.provider], id: r.id, status: r.status })), ["service", "id", "status"])}
|
|
42758
42946
|
|
|
42759
42947
|
Wait for the findings: code-review wait ${spec}`);
|
|
@@ -42769,12 +42957,12 @@ function registerEvidence(program2, rt) {
|
|
|
42769
42957
|
const ev = program2.command("evidence").description("Verification evidence");
|
|
42770
42958
|
ev.command("submit").description("Submit a check result. Origin and independence are assigned by the server from your identity").option("--payload <json>", "base SubmitEvidenceRequest JSON, @file, or -; flags override its fields").option("--check <name>", "check name").option("--result <result>", "queued | running | passed | failed | cancelled | errored | skipped | inconclusive").option("--subject <oid>", "commit the result is about").option("--change <change>", `use this change's current head as subject (and its repository): ${CHANGE_ARG}`).option("--subject-kind <kind>", "head | candidate").option("--promotion <id>", "promotion the candidate belongs to").option("--summary <text>", "summary").option("--command <cmd>", "command that was run").option("--exit-code <n>", "exit code", (v) => parseIntOption(v, "--exit-code")).option("--job-url <url>", "link to the job").option("--external-key <key>", "dedupe key from your system").option("--attach <file>", "upload a file as an attachment (repeatable)", repeat).option("--attachment-id <id>", "existing attachment id (repeatable)", list).action(
|
|
42771
42959
|
act(rt, async (ctx, o) => {
|
|
42772
|
-
const
|
|
42960
|
+
const c5 = ctx.client();
|
|
42773
42961
|
const base2 = o.payload ? await readJsonObject(o.payload, ctx.input, "--payload") : {};
|
|
42774
42962
|
let repo;
|
|
42775
42963
|
let subject = o.subject;
|
|
42776
42964
|
if (o.change) {
|
|
42777
|
-
const ch = await
|
|
42965
|
+
const ch = await c5.changes.get(await ctx.changeId(o.change));
|
|
42778
42966
|
repo = ch.repository_id;
|
|
42779
42967
|
subject ??= ch.current_revision.head_oid;
|
|
42780
42968
|
} else {
|
|
@@ -42789,7 +42977,7 @@ function registerEvidence(program2, rt) {
|
|
|
42789
42977
|
} catch {
|
|
42790
42978
|
throw new CliError(`cannot read attachment ${file2}`, EXIT.USAGE, "USAGE");
|
|
42791
42979
|
}
|
|
42792
|
-
const att = await
|
|
42980
|
+
const att = await c5.evidence.attachments.upload(repo, data, CONTENT_TYPES[extname(file2).toLowerCase()] ?? "application/octet-stream");
|
|
42793
42981
|
ctx.info(`uploaded ${basename3(file2)} as ${att.id}`);
|
|
42794
42982
|
attachmentIds.push(att.id);
|
|
42795
42983
|
}
|
|
@@ -42810,7 +42998,7 @@ function registerEvidence(program2, rt) {
|
|
|
42810
42998
|
attachment_ids: attachmentIds
|
|
42811
42999
|
};
|
|
42812
43000
|
if (!body.check_name || !body.result || !body.subject_oid) throw usage("--check, --result and --subject (or --change) are required (directly or via --payload)");
|
|
42813
|
-
ctx.result(await
|
|
43001
|
+
ctx.result(await c5.evidence.submit(repo, body), renderEvidence);
|
|
42814
43002
|
})
|
|
42815
43003
|
);
|
|
42816
43004
|
ev.command("list").argument("<change>", CHANGE_ARG).description("Evidence attached to a change").action(
|
|
@@ -42833,7 +43021,7 @@ Blockers:
|
|
|
42833
43021
|
${p.blockers.map((b) => ` ${b.code}: ${b.message}`).join("\n")}` : "") + (p.conflicts.length ? `
|
|
42834
43022
|
|
|
42835
43023
|
Conflicts:
|
|
42836
|
-
${p.conflicts.map((
|
|
43024
|
+
${p.conflicts.map((c5) => ` ${c5.kind}: ${c5.path}`).join("\n")}` : "");
|
|
42837
43025
|
function promotionExit(p) {
|
|
42838
43026
|
switch (p.state) {
|
|
42839
43027
|
case "completed":
|
|
@@ -42852,15 +43040,15 @@ function registerMerge(program2, rt) {
|
|
|
42852
43040
|
const merge2 = program2.command("merge").description("Promotion (protected merge) of changes");
|
|
42853
43041
|
merge2.command("request").argument("<change>", CHANGE_ARG).description("Request promotion. With --wait, exits 0 only when the merge completed (7 blocked/timeout, 5 conflicts)").option("--strategy <strategy>", "merge | squash | rebase").option("--idempotency-key <key>", "reuse to retry the same request safely").option("--wait", "poll until the promotion reaches a terminal state").option("--timeout <seconds>", "give up waiting after this long", (v) => parseIntOption(v, "--timeout"), 1800).option("--interval <seconds>", "poll interval", (v) => parseIntOption(v, "--interval"), 3).action(
|
|
42854
43042
|
act(rt, async (ctx, o, [id2]) => {
|
|
42855
|
-
const
|
|
42856
|
-
let p = await
|
|
43043
|
+
const c5 = ctx.client();
|
|
43044
|
+
let p = await c5.promotions.create(await ctx.changeId(id2), { strategy: o.strategy }, o.idempotencyKey ? { idempotencyKey: o.idempotencyKey } : {});
|
|
42857
43045
|
if (o.wait) {
|
|
42858
43046
|
const deadline = Date.now() + o.timeout * 1e3;
|
|
42859
43047
|
let last = p.state;
|
|
42860
43048
|
ctx.info(`promotion ${p.id}: ${p.state}`);
|
|
42861
43049
|
while (!TERMINAL2.has(p.state) && Date.now() < deadline) {
|
|
42862
43050
|
await ctx.deps.sleep(Math.max(1, o.interval) * 1e3);
|
|
42863
|
-
p = await
|
|
43051
|
+
p = await c5.promotions.get(p.id);
|
|
42864
43052
|
if (p.state !== last) ctx.info(`promotion ${p.id}: ${last = p.state}`);
|
|
42865
43053
|
}
|
|
42866
43054
|
if (!TERMINAL2.has(p.state)) ctx.info(`timed out after ${o.timeout}s; promotion is still ${p.state}`);
|
|
@@ -42874,10 +43062,10 @@ function registerMerge(program2, rt) {
|
|
|
42874
43062
|
);
|
|
42875
43063
|
merge2.command("status [promotion]").description("Show a promotion, or all promotions of --change").option("--change <change>", `list promotions of this change: ${CHANGE_ARG}`).action(
|
|
42876
43064
|
act(rt, async (ctx, o, [id2]) => {
|
|
42877
|
-
const
|
|
42878
|
-
if (id2) return ctx.result(await
|
|
43065
|
+
const c5 = ctx.client();
|
|
43066
|
+
if (id2) return ctx.result(await c5.promotions.get(id2), renderPromotion);
|
|
42879
43067
|
if (!o.change) throw usage("pass a promotion id or --change <change>");
|
|
42880
|
-
ctx.result(await
|
|
43068
|
+
ctx.result(await c5.promotions.list(await ctx.changeId(o.change)), (v) => table(v.items, ["id", "state", "strategy", "attempts", "created_at"]));
|
|
42881
43069
|
})
|
|
42882
43070
|
);
|
|
42883
43071
|
for (const action of ["cancel", "retry"]) {
|
|
@@ -42893,9 +43081,9 @@ function registerMerge(program2, rt) {
|
|
|
42893
43081
|
act(rt, async (ctx, o) => {
|
|
42894
43082
|
if (o.disable && o.status) throw usage("pass at most one of --disable and --status");
|
|
42895
43083
|
if (o.strategy && !["merge", "squash", "rebase"].includes(o.strategy)) throw usage("--strategy must be merge, squash or rebase");
|
|
42896
|
-
const
|
|
43084
|
+
const c5 = ctx.client();
|
|
42897
43085
|
const repo = await ctx.repoId();
|
|
42898
|
-
const g2 = o.status ? await
|
|
43086
|
+
const g2 = o.status ? await c5.autoMergeGrant.get(repo) : o.disable ? await c5.autoMergeGrant.revoke(repo) : await c5.autoMergeGrant.set(repo, o.strategy ? { strategy: o.strategy } : {});
|
|
42899
43087
|
ctx.result(g2, (v) => kv(v, ["repository_id", "state", "strategy", "updated_at"]));
|
|
42900
43088
|
})
|
|
42901
43089
|
);
|
|
@@ -42911,44 +43099,44 @@ ${table(a.history.map((h) => ({ ...h, actor: h.actor.display_name ?? h.actor.id
|
|
|
42911
43099
|
var renderRequests = (p) => table(p.items.map((r) => ({ ...r, reviewer: `${r.reviewer.type} ${r.reviewer.name ?? r.reviewer.id}` })), ["id", "reviewer", "source", "state", "created_at"]);
|
|
42912
43100
|
var renderSuggestion = (s) => kv(s, ["id", "state", "path", "start_line", "end_line", "revision_id", "thread_id", "applied.commit_oid"]);
|
|
42913
43101
|
var renderOwners = (r) => `${r.path}: ${r.owners.length ? r.owners.join(" ") : "(no owners)"}${r.rule ? ` [rule ${r.rule.index + 1}: ${r.rule.pattern}]` : ""}${r.required ? " (approval required)" : ""}`;
|
|
42914
|
-
var renderCoverage = (
|
|
42915
|
-
`code owner review ${
|
|
42916
|
-
table(
|
|
43102
|
+
var renderCoverage = (c5) => [
|
|
43103
|
+
`code owner review ${c5.required ? "required" : "not required"} by policy v${c5.policy_version} (revision ${c5.revision_id})${c5.complete ? "" : " \u2014 path list truncated"}`,
|
|
43104
|
+
table(c5.paths.map((p) => ({ ...p, owners: p.owners.join(" ") || "-", approved_by: p.approved_by.join(" ") || "-" })), ["path", "owners", "satisfied", "approved_by"])
|
|
42917
43105
|
].join("\n");
|
|
42918
43106
|
var renderAlerts = (p) => listWithCursor({ ...p, items: p.items.map((a) => ({ ...a, where: `${a.path}:${a.line}`, pushed_by: a.pushed_by.display_name ?? a.pushed_by.id })) }, ["id", "state", "rule", "where", "blob_oid", "masked", "pushed_by", "created_at"]);
|
|
42919
43107
|
function registerGovernance(program2, rt) {
|
|
42920
|
-
const change = program2.commands.find((
|
|
42921
|
-
change.command("draft").argument("<change>", CHANGE_ARG).description("Convert an open change back to a draft (drafts cannot merge and notify nobody)").action(act(rt, async (ctx, _o, [id2]) => ctx.result(await ctx.client().changes.draft(await ctx.changeId(id2)), (
|
|
43108
|
+
const change = program2.commands.find((c5) => c5.name() === "change") ?? program2.command("change");
|
|
43109
|
+
change.command("draft").argument("<change>", CHANGE_ARG).description("Convert an open change back to a draft (drafts cannot merge and notify nobody)").action(act(rt, async (ctx, _o, [id2]) => ctx.result(await ctx.client().changes.draft(await ctx.changeId(id2)), (c5) => kv(c5, ["id", "number", "title", "state"]))));
|
|
42922
43110
|
change.command("request-review").argument("<change>", CHANGE_ARG).description("Request review from people (--user id|email|@handle) or teams (--team slug); --remove <request> withdraws one").option("--user <user>", "reviewer (repeatable or comma-separated)", list).option("--team <team>", "team slug (repeatable or comma-separated)", list).option("--remove <request>", "withdraw a review request by id").action(
|
|
42923
43111
|
act(rt, async (ctx, o, [spec]) => {
|
|
42924
43112
|
if (o.remove && (o.user || o.team)) throw usage("--remove cannot be combined with --user/--team");
|
|
42925
|
-
const
|
|
43113
|
+
const c5 = ctx.client();
|
|
42926
43114
|
const id2 = await ctx.changeId(spec);
|
|
42927
43115
|
if (o.remove) {
|
|
42928
|
-
await
|
|
43116
|
+
await c5.reviewRequests.remove(id2, o.remove);
|
|
42929
43117
|
} else if (o.user?.length || o.team?.length) {
|
|
42930
|
-
await
|
|
43118
|
+
await c5.reviewRequests.request(id2, { users: o.user ?? [], teams: o.team ?? [] });
|
|
42931
43119
|
}
|
|
42932
|
-
ctx.result(await
|
|
43120
|
+
ctx.result(await c5.reviewRequests.list(id2), renderRequests);
|
|
42933
43121
|
})
|
|
42934
43122
|
);
|
|
42935
43123
|
change.command("auto-merge").argument("<change>", CHANGE_ARG).description("Merge automatically once ready (--disable to cancel, --status to show); a new revision by someone else cancels it").option("--strategy <strategy>", "merge | squash (default: the policy default)").option("--disable", "cancel auto-merge").option("--status", "show the auto-merge state and history without changing it").action(
|
|
42936
43124
|
act(rt, async (ctx, o, [spec]) => {
|
|
42937
43125
|
if (o.disable && o.status) throw usage("pass at most one of --disable and --status");
|
|
42938
43126
|
if (o.strategy && o.strategy !== "merge" && o.strategy !== "squash") throw usage("--strategy must be merge or squash");
|
|
42939
|
-
const
|
|
43127
|
+
const c5 = ctx.client();
|
|
42940
43128
|
const id2 = await ctx.changeId(spec);
|
|
42941
|
-
const r = o.status ? await
|
|
43129
|
+
const r = o.status ? await c5.autoMerge.get(id2) : o.disable ? await c5.autoMerge.disable(id2) : await c5.autoMerge.enable(id2, o.strategy ? { strategy: o.strategy } : {});
|
|
42942
43130
|
ctx.result(r, renderAutoMerge);
|
|
42943
43131
|
})
|
|
42944
43132
|
);
|
|
42945
43133
|
const suggestion = program2.command("suggestion").description("Suggested changes on review threads");
|
|
42946
43134
|
suggestion.command("create").argument("<change>", CHANGE_ARG).description("Suggest replacement text for a line range of the current (or --revision) revision").requiredOption("--path <path>", "file path").requiredOption("--line <n>", "first line", (v) => parseIntOption(v, "--line")).option("--end-line <n>", "last line (default: --line)", (v) => parseIntOption(v, "--end-line")).requiredOption("--replacement <text>", "replacement text (@file or - for stdin; empty string deletes the lines)").option("--revision <id>", "revision (default: current)").option("--body <text>", "comment text").option("--blocking", "make the thread blocking").action(
|
|
42947
43135
|
act(rt, async (ctx, o, [spec]) => {
|
|
42948
|
-
const
|
|
43136
|
+
const c5 = ctx.client();
|
|
42949
43137
|
const id2 = await ctx.changeId(spec);
|
|
42950
|
-
const revision = o.revision ?? (await
|
|
42951
|
-
const s = await
|
|
43138
|
+
const revision = o.revision ?? (await c5.changes.get(id2)).current_revision.id;
|
|
43139
|
+
const s = await c5.suggestions.create(id2, {
|
|
42952
43140
|
revision_id: revision,
|
|
42953
43141
|
path: o.path,
|
|
42954
43142
|
start_line: o.line,
|
|
@@ -43126,11 +43314,11 @@ function registerSecretScanning(program2, rt) {
|
|
|
43126
43314
|
ss.command("history").description("Scan the full history of --repo in the background (repository admins); --wait polls until it finishes").option("--wait", "wait for the scan to finish").option("--interval <seconds>", "poll interval with --wait", (v) => parseIntOption(v, "--interval"), 3).action(
|
|
43127
43315
|
act(rt, async (ctx, o) => {
|
|
43128
43316
|
const repo = await ctx.repoId();
|
|
43129
|
-
const
|
|
43130
|
-
let job2 = await
|
|
43317
|
+
const c5 = ctx.client("user");
|
|
43318
|
+
let job2 = await c5.secretScanning.scans.start(repo);
|
|
43131
43319
|
while (o.wait && (job2.state === "queued" || job2.state === "running")) {
|
|
43132
43320
|
await ctx.deps.sleep(Math.max(1, o.interval) * 1e3);
|
|
43133
|
-
job2 = await
|
|
43321
|
+
job2 = await c5.secretScanning.scans.get(repo, job2.id);
|
|
43134
43322
|
}
|
|
43135
43323
|
ctx.result(job2, renderScan);
|
|
43136
43324
|
if (job2.state === "failed") ctx.setExit(EXIT.UNAVAILABLE);
|
|
@@ -43163,7 +43351,7 @@ ${table(v.matches, ["line", "column", "masked"])}` : "\nno matches in the sample
|
|
|
43163
43351
|
|
|
43164
43352
|
// packages/cli/src/commands/impact.ts
|
|
43165
43353
|
var renderStatus2 = (s) => kv(s, ["enabled", "check_name", "integration_id", "webhook_id", "connectors", "settings.llm_summary", "settings.post_suggestions", "settings.hot_table_writes_per_second", "enabled_at"]);
|
|
43166
|
-
var renderConnector = (
|
|
43354
|
+
var renderConnector = (c5) => kv(c5, ["id", "kind", "name", "credentials_set", "config", "last_test", "created_at"]);
|
|
43167
43355
|
function registerImpact(program2, rt) {
|
|
43168
43356
|
const impact = program2.command("impact").description("Production impact analysis of changes (brnch/impact): reports, installation, read-only connectors");
|
|
43169
43357
|
impact.command("show").argument("<change>", CHANGE_ARG).description("Show the impact report of a change (the full structured report with --json); exits 7 when it failed").action(
|
|
@@ -43226,6 +43414,348 @@ ${v.summary}`);
|
|
|
43226
43414
|
);
|
|
43227
43415
|
}
|
|
43228
43416
|
|
|
43417
|
+
// packages/cli/src/commands/inbox.ts
|
|
43418
|
+
var c3 = BRAND.cli;
|
|
43419
|
+
var VIEWS = ["unread", "all", "done", "snoozed"];
|
|
43420
|
+
var KIND_LABELS = {
|
|
43421
|
+
review_requested: "review requested",
|
|
43422
|
+
review_available: "review ready",
|
|
43423
|
+
response_required: "needs reply",
|
|
43424
|
+
check_failed: "check failed",
|
|
43425
|
+
permission_request: "permission",
|
|
43426
|
+
merge_conflict: "conflict",
|
|
43427
|
+
promotion_blocked: "merge blocked",
|
|
43428
|
+
session_blocked: "agent blocked",
|
|
43429
|
+
watching: "watching",
|
|
43430
|
+
secret_alert: "secret alert",
|
|
43431
|
+
mentioned: "mentioned",
|
|
43432
|
+
assigned: "assigned",
|
|
43433
|
+
comment: "comment",
|
|
43434
|
+
approved: "approved",
|
|
43435
|
+
merged: "merged"
|
|
43436
|
+
};
|
|
43437
|
+
var kindLabel = (kind) => KIND_LABELS[kind] ?? kind;
|
|
43438
|
+
var shortId = (id2) => id2.slice(-6);
|
|
43439
|
+
function age(iso, now) {
|
|
43440
|
+
const min = Math.max(0, Math.floor((now - Date.parse(iso)) / 6e4));
|
|
43441
|
+
if (min < 1) return "now";
|
|
43442
|
+
if (min < 60) return `${min}m`;
|
|
43443
|
+
if (min < 24 * 60) return `${Math.floor(min / 60)}h`;
|
|
43444
|
+
if (min < 14 * 24 * 60) return `${Math.floor(min / (24 * 60))}d`;
|
|
43445
|
+
return `${Math.floor(min / (7 * 24 * 60))}w`;
|
|
43446
|
+
}
|
|
43447
|
+
var clip2 = (s, n) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
|
|
43448
|
+
function state(i, now) {
|
|
43449
|
+
if (i.done) return "done";
|
|
43450
|
+
if (i.snoozed_until && Date.parse(i.snoozed_until) > now) return `snoozed ${new Date(i.snoozed_until).toLocaleString(void 0, { dateStyle: "short", timeStyle: "short" })}`;
|
|
43451
|
+
return i.read ? "read" : "unread";
|
|
43452
|
+
}
|
|
43453
|
+
function renderInbox(page, view, repos, now) {
|
|
43454
|
+
if (!page.items.length) return view === "unread" ? `Nothing unread. (\`${c3} inbox list --view all\` shows read items)` : "(none)";
|
|
43455
|
+
const rows2 = page.items.map((i) => ({
|
|
43456
|
+
id: shortId(i.id),
|
|
43457
|
+
kind: kindLabel(i.kind),
|
|
43458
|
+
repository: repos.get(i.repository_id) ?? i.repository_id,
|
|
43459
|
+
title: clip2(i.excerpt ? `${i.title}: \u201C${i.excerpt}\u201D` : i.title, i.excerpt ? 110 : 72),
|
|
43460
|
+
age: age(i.updated_at, now),
|
|
43461
|
+
n: i.count > 1 ? `\xD7${i.count}` : "",
|
|
43462
|
+
state: state(i, now)
|
|
43463
|
+
}));
|
|
43464
|
+
const body = table(rows2, ["id", "kind", "repository", "title", "age", "n", "state"]);
|
|
43465
|
+
return page.next_cursor ? `${body}
|
|
43466
|
+
(more: --cursor ${page.next_cursor})` : body;
|
|
43467
|
+
}
|
|
43468
|
+
var HOUR_MS = 36e5;
|
|
43469
|
+
var UNIT_MS = { m: 6e4, min: 6e4, h: HOUR_MS, d: 24 * HOUR_MS, w: 7 * 24 * HOUR_MS };
|
|
43470
|
+
var MORNING = 8;
|
|
43471
|
+
function parseWhen(spec, now) {
|
|
43472
|
+
const s = spec.trim().toLowerCase();
|
|
43473
|
+
const at = (d, h, m = 0) => new Date(d.getFullYear(), d.getMonth(), d.getDate(), h, m);
|
|
43474
|
+
const days = (n) => new Date(now.getFullYear(), now.getMonth(), now.getDate() + n);
|
|
43475
|
+
let when = null;
|
|
43476
|
+
const dur = /^(\d{1,4})\s*(m|min|h|d|w)$/.exec(s);
|
|
43477
|
+
const clock = /^([01]?\d|2[0-3]):([0-5]\d)$/.exec(s);
|
|
43478
|
+
const date5 = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
|
|
43479
|
+
if (dur) when = new Date(now.getTime() + Number(dur[1]) * UNIT_MS[dur[2]]);
|
|
43480
|
+
else if (s === "tomorrow") when = at(days(1), MORNING);
|
|
43481
|
+
else if (s === "next-week" || s === "next week") when = at(days((8 - now.getDay()) % 7 || 7), MORNING);
|
|
43482
|
+
else if (clock) {
|
|
43483
|
+
when = at(now, Number(clock[1]), Number(clock[2]));
|
|
43484
|
+
if (when <= now) when = at(days(1), Number(clock[1]), Number(clock[2]));
|
|
43485
|
+
} else if (date5) when = new Date(Number(date5[1]), Number(date5[2]) - 1, Number(date5[3]), MORNING);
|
|
43486
|
+
else if (/^\d{4}-\d{2}-\d{2}t/.test(s) && !Number.isNaN(Date.parse(spec))) when = new Date(Date.parse(spec));
|
|
43487
|
+
if (!when || Number.isNaN(when.getTime())) throw usage(`cannot read "${spec}" as a time: use a duration (30m, 2h, 3d, 1w), tomorrow, next-week, HH:MM, a date (2026-10-07) or an ISO time`);
|
|
43488
|
+
if (when <= now) throw usage(`"${spec}" is in the past`);
|
|
43489
|
+
return when;
|
|
43490
|
+
}
|
|
43491
|
+
var CHANNEL_ALIASES = { in_app: "in_app", "in-app": "in_app", inapp: "in_app", app: "in_app", email: "email", push: "push" };
|
|
43492
|
+
function parseChannelModes(pairs) {
|
|
43493
|
+
if (!pairs.length) throw usage(`give at least one <channel>=<mode>, e.g. push=off email=digest (channels: ${NOTIFICATION_CHANNELS.join(", ")})`);
|
|
43494
|
+
const modes = {};
|
|
43495
|
+
for (const p of pairs) {
|
|
43496
|
+
const [k, v, ...rest] = p.split("=");
|
|
43497
|
+
const channel = CHANNEL_ALIASES[(k ?? "").trim().toLowerCase()];
|
|
43498
|
+
if (!channel || !v || rest.length) throw usage(`"${p}" is not <channel>=<mode> (channels: ${NOTIFICATION_CHANNELS.join(", ")})`);
|
|
43499
|
+
modes[channel] = v.trim().toLowerCase();
|
|
43500
|
+
}
|
|
43501
|
+
const parsed = ChannelModesSchema.safeParse(modes);
|
|
43502
|
+
if (!parsed.success) {
|
|
43503
|
+
const bad = parsed.error.issues[0]?.path[0];
|
|
43504
|
+
throw usage(bad === "email" ? "email is off, immediate or digest" : `${String(bad)} is on or off`);
|
|
43505
|
+
}
|
|
43506
|
+
return parsed.data;
|
|
43507
|
+
}
|
|
43508
|
+
function parseReason(spec) {
|
|
43509
|
+
if (spec === "all") return "all";
|
|
43510
|
+
const r = NotificationReasonSchema.safeParse(spec.replace(/-/g, "_"));
|
|
43511
|
+
if (!r.success) throw usage(`unknown reason "${spec}"; one of: all, ${NOTIFICATION_REASONS.join(", ")}`);
|
|
43512
|
+
return r.data;
|
|
43513
|
+
}
|
|
43514
|
+
function parseQuietHours(spec) {
|
|
43515
|
+
if (spec === "off") return null;
|
|
43516
|
+
const m = /^(\d{1,2}:\d{2})\s*[-–]\s*(\d{1,2}:\d{2})$/.exec(spec.trim());
|
|
43517
|
+
const pad = (t) => t.padStart(5, "0");
|
|
43518
|
+
if (!m || ![m[1], m[2]].every((t) => /^([01]\d|2[0-3]):[0-5]\d$/.test(pad(t)))) throw usage(`quiet hours are HH:MM-HH:MM (24-hour, e.g. 22:00-07:00) or off`);
|
|
43519
|
+
return { start: pad(m[1]), end: pad(m[2]) };
|
|
43520
|
+
}
|
|
43521
|
+
function checkTimeZone(tz) {
|
|
43522
|
+
try {
|
|
43523
|
+
new Intl.DateTimeFormat("en", { timeZone: tz });
|
|
43524
|
+
return tz;
|
|
43525
|
+
} catch {
|
|
43526
|
+
throw usage(`unknown time zone "${tz}" (an IANA name such as Europe/Paris)`);
|
|
43527
|
+
}
|
|
43528
|
+
}
|
|
43529
|
+
function renderSettings2(s, orgNames2 = /* @__PURE__ */ new Map(), org) {
|
|
43530
|
+
const overrides = org ? s.orgs[org.id] ?? {} : {};
|
|
43531
|
+
const matrix2 = table(
|
|
43532
|
+
NOTIFICATION_REASONS.filter((r) => s.reasons[r]).map((r) => {
|
|
43533
|
+
const m = { ...s.reasons[r], ...overrides[r] };
|
|
43534
|
+
return { reason: r, in_app: m.in_app, email: m.email, push: m.push, ...org ? { override: overrides[r] ? "yes" : "" } : {} };
|
|
43535
|
+
}),
|
|
43536
|
+
["reason", "in_app", "email", "push", ...org ? ["override"] : []]
|
|
43537
|
+
);
|
|
43538
|
+
const hh = (h) => `${String(h).padStart(2, "0")}:00`;
|
|
43539
|
+
const digest = s.digest.frequency === "off" ? "off" : `${s.digest.frequency} at ${hh(s.digest.hour)}${s.digest.frequency === "weekly" ? " on Mondays" : ""} (${s.digest.time_zone})`;
|
|
43540
|
+
const others = Object.entries(s.orgs).flatMap(
|
|
43541
|
+
([id2, reasons]) => Object.entries(reasons).map(([r, m]) => ` ${orgNames2.get(id2) ?? id2} ${r}: ${Object.entries(m ?? {}).map(([ch, v]) => `${ch}=${v}`).join(" ")}`)
|
|
43542
|
+
);
|
|
43543
|
+
const lines = [
|
|
43544
|
+
...org ? [`In ${org.slug}:`] : [],
|
|
43545
|
+
matrix2,
|
|
43546
|
+
"",
|
|
43547
|
+
kv(
|
|
43548
|
+
{
|
|
43549
|
+
digest,
|
|
43550
|
+
quiet_hours: s.quiet_hours ? `${s.quiet_hours.start}-${s.quiet_hours.end} (${s.digest.time_zone}): push waits until they end` : "off",
|
|
43551
|
+
push_previews: s.push_previews ? "on" : "off (push shows the kind, not the title)",
|
|
43552
|
+
email: s.email_deliverable ? "deliverable" : "no verified, deliverable address: nothing is emailed",
|
|
43553
|
+
push_devices: `${s.push_devices} (\`${c3} notifications devices\`)`,
|
|
43554
|
+
muted: s.muted.length ? `${s.muted.join(", ")} (\`${c3} notifications unmute <key>\`)` : "none"
|
|
43555
|
+
},
|
|
43556
|
+
["digest", "quiet_hours", "push_previews", "email", "push_devices", "muted"]
|
|
43557
|
+
)
|
|
43558
|
+
];
|
|
43559
|
+
if (!org && others.length) lines.push("", "Organization overrides:", ...others);
|
|
43560
|
+
return lines.join("\n");
|
|
43561
|
+
}
|
|
43562
|
+
var renderDevices = (v) => v.items.length ? table(
|
|
43563
|
+
v.items.map((d) => ({ id: d.id, name: d.name ?? "-", environment: d.environment, app_version: d.app_version ?? "-", last_seen: d.last_seen_at, current: d.current ? "yes" : "" })),
|
|
43564
|
+
["id", "name", "environment", "app_version", "last_seen", "current"]
|
|
43565
|
+
) : "No push devices. The iOS app registers itself when you allow notifications.";
|
|
43566
|
+
var PAGE2 = 100;
|
|
43567
|
+
var MAX_PAGES2 = 10;
|
|
43568
|
+
async function findItems(client, specs) {
|
|
43569
|
+
const wanted = specs.map((s) => s.trim().toLowerCase());
|
|
43570
|
+
for (const s of wanted) if (s.length < 4) throw usage(`"${s}" is too short to name an inbox item: use the id \`${c3} inbox list\` shows`);
|
|
43571
|
+
const found = new Map(wanted.map((s) => [s, []]));
|
|
43572
|
+
const seen = /* @__PURE__ */ new Set();
|
|
43573
|
+
for (const view of ["all", "snoozed", "done"]) {
|
|
43574
|
+
let cursor2;
|
|
43575
|
+
for (let i = 0; i < MAX_PAGES2; i++) {
|
|
43576
|
+
const page = await client.inbox.list({ view, limit: PAGE2, ...cursor2 ? { cursor: cursor2 } : {} });
|
|
43577
|
+
for (const item of page.items) {
|
|
43578
|
+
if (seen.has(item.id)) continue;
|
|
43579
|
+
seen.add(item.id);
|
|
43580
|
+
for (const s of wanted) if (item.id === s || item.id.endsWith(s)) found.get(s).push(item);
|
|
43581
|
+
}
|
|
43582
|
+
if (!page.next_cursor) break;
|
|
43583
|
+
cursor2 = page.next_cursor;
|
|
43584
|
+
}
|
|
43585
|
+
if (wanted.every((s) => found.get(s).length)) break;
|
|
43586
|
+
}
|
|
43587
|
+
return wanted.map((s) => {
|
|
43588
|
+
const hits = found.get(s);
|
|
43589
|
+
const exact = hits.find((h) => h.id === s);
|
|
43590
|
+
if (exact) return exact;
|
|
43591
|
+
if (hits.length > 1) throw usage(`"${s}" matches ${hits.length} inbox items (${hits.map((h) => h.id).join(", ")}); give more of the id`);
|
|
43592
|
+
if (!hits[0]) throw new CliError(`no inbox item "${s}" (muted items are not listed)`, EXIT.NOT_FOUND, "NOT_FOUND");
|
|
43593
|
+
return hits[0];
|
|
43594
|
+
});
|
|
43595
|
+
}
|
|
43596
|
+
async function itemIds(client, specs) {
|
|
43597
|
+
const full = (s) => /^notif_[0-9a-z]{26}$/.test(s);
|
|
43598
|
+
const short2 = specs.filter((s) => !full(s));
|
|
43599
|
+
const items = short2.length ? await findItems(client, short2) : [];
|
|
43600
|
+
return specs.map((s) => full(s) ? s : items[short2.indexOf(s)].id);
|
|
43601
|
+
}
|
|
43602
|
+
async function repoNames(client, items) {
|
|
43603
|
+
const ids = [...new Set(items.map((i) => i.repository_id))];
|
|
43604
|
+
const names = await Promise.all(ids.map((id2) => client.repos.get(id2).then((r) => `${r.org_slug}/${r.name}`, () => null)));
|
|
43605
|
+
return new Map(ids.flatMap((id2, k) => names[k] ? [[id2, names[k]]] : []));
|
|
43606
|
+
}
|
|
43607
|
+
function liveLine(e) {
|
|
43608
|
+
const time3 = new Date(e.at).toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit" });
|
|
43609
|
+
return e.type === "item" ? `${time3} ${shortId(e.item_id)} ${kindLabel(e.kind)}: ${e.title} (${e.unread} unread)` : `${time3} ${e.unread} unread`;
|
|
43610
|
+
}
|
|
43611
|
+
function registerInbox(program2, rt) {
|
|
43612
|
+
const inbox = program2.command("inbox").description("Your inbox: what needs your attention (people only; agent sessions have no inbox)");
|
|
43613
|
+
inbox.command("list", { isDefault: true }).description("Inbox items, most urgent first. IDS are short ids: pass them to read, done, snooze, mute or open").option("--view <view>", `one of ${VIEWS.join(", ")}`, "unread").option("--limit <n>", "page size (at most 100)", (v) => parseIntOption(v, "--limit")).option("--cursor <cursor>", "page cursor").action(
|
|
43614
|
+
act(rt, async (ctx, o) => {
|
|
43615
|
+
if (!VIEWS.includes(o.view)) throw usage(`--view must be one of ${VIEWS.join(", ")}`);
|
|
43616
|
+
const view = o.view;
|
|
43617
|
+
const client = ctx.client("user");
|
|
43618
|
+
const page = await client.inbox.list({ view, ...o.limit ? { limit: o.limit } : {}, ...o.cursor ? { cursor: o.cursor } : {} });
|
|
43619
|
+
const repos = ctx.json ? /* @__PURE__ */ new Map() : await repoNames(client, page.items);
|
|
43620
|
+
ctx.result(page, (v) => renderInbox(v, view, repos, ctx.deps.sys.now()));
|
|
43621
|
+
})
|
|
43622
|
+
);
|
|
43623
|
+
inbox.command("count").description("Print the number of unread items (for prompts and status lines)").action(act(rt, async (ctx) => ctx.result(await ctx.client("user").inbox.count(), (v) => String(v.unread))));
|
|
43624
|
+
for (const action of ["read", "unread", "done", "undone"]) {
|
|
43625
|
+
const bulk = action !== "undone";
|
|
43626
|
+
const cmd = inbox.command(`${action} [ids...]`).description(`Mark items ${action === "undone" ? "not done (back in the inbox)" : action}${bulk ? `; --all for every item${action === "done" ? " (asks first)" : ""}` : ""}`);
|
|
43627
|
+
if (bulk) cmd.option("--all", "every item in your inbox");
|
|
43628
|
+
cmd.action(
|
|
43629
|
+
act(rt, async (ctx, o, specs) => {
|
|
43630
|
+
const client = ctx.client("user");
|
|
43631
|
+
if (o.all) {
|
|
43632
|
+
if (specs.length) throw usage("give ids or --all, not both");
|
|
43633
|
+
if (action === "done") await ctx.confirm("mark every inbox item done");
|
|
43634
|
+
const r = await client.inbox.bulk({ action, all: true });
|
|
43635
|
+
return ctx.result({ action, ...r }, `${r.changed} marked ${action}`);
|
|
43636
|
+
}
|
|
43637
|
+
if (!specs.length) throw usage(`give the ids of the items to mark ${action} (from \`${c3} inbox list\`)${bulk ? ", or --all" : ""}`);
|
|
43638
|
+
const ids = await itemIds(client, specs);
|
|
43639
|
+
for (const id2 of ids) await client.inbox[action](id2);
|
|
43640
|
+
ctx.result({ action, ids }, `${ids.map(shortId).join(", ")} marked ${action}`);
|
|
43641
|
+
})
|
|
43642
|
+
);
|
|
43643
|
+
}
|
|
43644
|
+
inbox.command("snooze <id> <until>").description("Hide an item until a time: 30m, 2h, 3d, 1w, tomorrow, next-week, 17:30, 2026-10-07 or an ISO time").action(
|
|
43645
|
+
act(rt, async (ctx, _o, [spec, when]) => {
|
|
43646
|
+
const until = parseWhen(when, new Date(ctx.deps.sys.now())).toISOString();
|
|
43647
|
+
const client = ctx.client("user");
|
|
43648
|
+
const [id2] = await itemIds(client, [spec]);
|
|
43649
|
+
await client.inbox.snooze(id2, until);
|
|
43650
|
+
ctx.result({ id: id2, snoozed_until: until }, `${shortId(id2)} snoozed until ${new Date(until).toLocaleString()}`);
|
|
43651
|
+
})
|
|
43652
|
+
);
|
|
43653
|
+
inbox.command("mute <id>").description("Stop notifications about this item's change or agent session, and mark its items done").action(
|
|
43654
|
+
act(rt, async (ctx, _o, [spec]) => {
|
|
43655
|
+
const client = ctx.client("user");
|
|
43656
|
+
const [item] = await findItems(client, [spec]);
|
|
43657
|
+
const target = item.change_id ? { change_id: item.change_id } : item.session_id ? { session_id: item.session_id } : null;
|
|
43658
|
+
if (!target) throw new CliError(`${shortId(item.id)} is not about a change or an agent session, so there is nothing to mute; mark it done instead`, EXIT.VALIDATION, "VALIDATION_FAILED");
|
|
43659
|
+
const settings = await client.inbox.mute(target);
|
|
43660
|
+
ctx.result(settings, `muted ${target.change_id ?? target.session_id} (\`${c3} notifications\` lists mutes)`);
|
|
43661
|
+
})
|
|
43662
|
+
);
|
|
43663
|
+
inbox.command("open <id>").description("Open an item in your browser (prints the link when no browser can be started)").action(
|
|
43664
|
+
act(rt, async (ctx, _o, [spec]) => {
|
|
43665
|
+
const [item] = await findItems(ctx.client("user"), [spec]);
|
|
43666
|
+
const url2 = new URL(item.url, ctx.baseUrl).toString();
|
|
43667
|
+
const opened = ctx.json ? false : await ctx.deps.openUrl(url2);
|
|
43668
|
+
ctx.result({ id: item.id, url: url2, opened }, opened ? `opened ${url2}` : url2);
|
|
43669
|
+
})
|
|
43670
|
+
);
|
|
43671
|
+
inbox.command("watch").description("Print a line for each new item and each change of the unread count until Ctrl-C. With --json, one JSON object per line").action(
|
|
43672
|
+
act(rt, async (ctx) => {
|
|
43673
|
+
const client = ctx.client("user");
|
|
43674
|
+
if (!ctx.json) ctx.info(`watching your inbox: ${(await client.inbox.count()).unread} unread (Ctrl-C to stop)`);
|
|
43675
|
+
for await (const e of client.inbox.watch()) ctx.deps.stdout.write(`${ctx.json ? JSON.stringify(e) : liveLine(e)}
|
|
43676
|
+
`);
|
|
43677
|
+
})
|
|
43678
|
+
);
|
|
43679
|
+
}
|
|
43680
|
+
async function orgNames(client, s) {
|
|
43681
|
+
const ids = Object.keys(s.orgs);
|
|
43682
|
+
const slugs = await Promise.all(ids.map((id2) => client.orgs.get(id2).then((o) => o.slug, () => null)));
|
|
43683
|
+
return new Map(ids.flatMap((id2, k) => slugs[k] ? [[id2, slugs[k]]] : []));
|
|
43684
|
+
}
|
|
43685
|
+
function registerNotifications(program2, rt) {
|
|
43686
|
+
const n = program2.command("notifications").description("How you are notified: per reason and channel (in_app, email, push), digest, quiet hours, devices");
|
|
43687
|
+
n.command("get", { isDefault: true }).alias("show").description("Your settings: every reason \xD7 channel, digest, quiet hours, push previews, devices and mutes. With --org, what applies in that organization").action(
|
|
43688
|
+
act(rt, async (ctx) => {
|
|
43689
|
+
const client = ctx.client("user");
|
|
43690
|
+
const s = await client.notifications.get();
|
|
43691
|
+
const org = ctx.globals.org ? await client.orgs.get(ctx.globals.org) : void 0;
|
|
43692
|
+
const names = ctx.json || org ? /* @__PURE__ */ new Map() : await orgNames(client, s);
|
|
43693
|
+
ctx.result(s, (v) => renderSettings2(v, names, org));
|
|
43694
|
+
})
|
|
43695
|
+
);
|
|
43696
|
+
n.command("set [reason] [modes...]").description(
|
|
43697
|
+
`Change settings; only what is given changes. <reason> (or all) with channels in_app=on|off, email=off|immediate|digest, push=on|off; with --org, an override in that organization only. Reasons: ${NOTIFICATION_REASONS.join(", ")}`
|
|
43698
|
+
).option("--reset", "with --org: drop that organization's overrides (your personal choices apply again)").option("--digest <frequency>", "email digest: off, daily or weekly (Mondays)").option("--digest-hour <h>", "hour of the digest, 0-23, in --tz", (v) => parseIntOption(v, "--digest-hour")).option("--tz <zone>", "IANA time zone of the digest and quiet hours, e.g. Europe/Paris").option("--quiet-hours <hours>", "hold push notifications HH:MM-HH:MM (e.g. 22:00-07:00), or off").option("--previews <on|off>", "whether push notifications show titles (on) or only the kind of item (off)").action(
|
|
43699
|
+
act(rt, async (ctx, o, [reason, ...pairs]) => {
|
|
43700
|
+
const orgSpec = ctx.globals.org;
|
|
43701
|
+
if (o.reset && !orgSpec) throw usage("--reset drops an organization's overrides: give --org");
|
|
43702
|
+
if (o.reset && reason) throw usage("give --reset or a reason, not both");
|
|
43703
|
+
if (o.digest !== void 0 && !["off", "daily", "weekly"].includes(o.digest)) throw usage("--digest is off, daily or weekly");
|
|
43704
|
+
if (o.digestHour !== void 0 && (o.digestHour < 0 || o.digestHour > 23)) throw usage("--digest-hour is 0-23");
|
|
43705
|
+
if (o.previews !== void 0 && o.previews !== "on" && o.previews !== "off") throw usage("--previews is on or off");
|
|
43706
|
+
const r = reason ? parseReason(reason) : void 0;
|
|
43707
|
+
const modes = r ? parseChannelModes(pairs) : void 0;
|
|
43708
|
+
const quiet = o.quietHours !== void 0 ? parseQuietHours(o.quietHours) : void 0;
|
|
43709
|
+
const tz = o.tz ? checkTimeZone(o.tz) : void 0;
|
|
43710
|
+
const touchesDigest = o.digest !== void 0 || o.digestHour !== void 0 || tz !== void 0;
|
|
43711
|
+
if (!r && !o.reset && !touchesDigest && quiet === void 0 && o.previews === void 0) {
|
|
43712
|
+
throw usage(`nothing to change: give a reason and channels (e.g. \`${c3} notifications set mentioned push=off\`), --digest, --quiet-hours, --previews, or --org \u2026 --reset`);
|
|
43713
|
+
}
|
|
43714
|
+
const client = ctx.client("user");
|
|
43715
|
+
const org = orgSpec ? await client.orgs.get(orgSpec) : void 0;
|
|
43716
|
+
const patch = {};
|
|
43717
|
+
const byReason = r && modes ? Object.fromEntries((r === "all" ? NOTIFICATION_REASONS : [r]).map((k) => [k, modes])) : void 0;
|
|
43718
|
+
if (org && (byReason || o.reset)) patch.orgs = { [org.id]: o.reset ? {} : byReason };
|
|
43719
|
+
else if (byReason) patch.reasons = byReason;
|
|
43720
|
+
if (touchesDigest) {
|
|
43721
|
+
const current = (await client.notifications.get()).digest;
|
|
43722
|
+
patch.digest = { frequency: o.digest ?? current.frequency, hour: o.digestHour ?? current.hour, time_zone: tz ?? current.time_zone };
|
|
43723
|
+
}
|
|
43724
|
+
if (quiet !== void 0) patch.quiet_hours = quiet;
|
|
43725
|
+
if (o.previews !== void 0) patch.push_previews = o.previews === "on";
|
|
43726
|
+
const s = await client.notifications.update(patch);
|
|
43727
|
+
const names = ctx.json || org ? /* @__PURE__ */ new Map() : await orgNames(client, s);
|
|
43728
|
+
ctx.result(s, (v) => renderSettings2(v, names, org));
|
|
43729
|
+
})
|
|
43730
|
+
);
|
|
43731
|
+
n.command("unmute <key>").description("Notify again about a muted change or agent session (a chg_\u2026 or ses_\u2026 id, or a key `notifications` lists under muted)").action(
|
|
43732
|
+
act(rt, async (ctx, _o, [spec]) => {
|
|
43733
|
+
const key = /^chg_/.test(spec) ? `change:${spec}` : /^ses_/.test(spec) ? `session:${spec}` : spec;
|
|
43734
|
+
const client = ctx.client("user");
|
|
43735
|
+
const { muted } = await client.notifications.get();
|
|
43736
|
+
if (!muted.includes(key)) throw new CliError(`"${key}" is not muted (muted: ${muted.length ? muted.join(", ") : "none"})`, EXIT.NOT_FOUND, "NOT_FOUND");
|
|
43737
|
+
ctx.result(await client.notifications.update({ muted: muted.filter((m) => m !== key) }), (v) => renderSettings2(v));
|
|
43738
|
+
})
|
|
43739
|
+
);
|
|
43740
|
+
const devices = n.command("devices").description("Devices that receive push notifications (the iOS app registers them)");
|
|
43741
|
+
devices.command("list", { isDefault: true }).description("Registered push devices").action(act(rt, async (ctx) => ctx.result(await ctx.client("user").notifications.devices.list(), renderDevices)));
|
|
43742
|
+
devices.command("remove <id>").description("Stop pushing to a device. Requires --yes when non-interactive").action(
|
|
43743
|
+
act(rt, async (ctx, _o, [id2]) => {
|
|
43744
|
+
await ctx.confirm(`stop push notifications to device ${id2}`);
|
|
43745
|
+
await ctx.client("user").notifications.devices.remove(id2);
|
|
43746
|
+
ctx.result({ removed: id2 }, `removed ${id2}`);
|
|
43747
|
+
})
|
|
43748
|
+
);
|
|
43749
|
+
n.command("test-push").description("Send a test push notification to your devices").option("--message <text>", "What the notification says (at most 120 characters)").action(
|
|
43750
|
+
act(rt, async (ctx, o) => {
|
|
43751
|
+
const r = await ctx.client("user").notifications.devices.test(o.message ? { message: o.message } : {});
|
|
43752
|
+
if (r.devices && !r.delivered) ctx.setExit(EXIT.UNAVAILABLE);
|
|
43753
|
+
ctx.result(r, () => r.devices ? `delivered to ${r.delivered} of ${r.devices} device(s)${r.errors.length ? `
|
|
43754
|
+
${r.errors.join("\n")}` : ""}` : `No push devices. The iOS app registers itself when you allow notifications.`);
|
|
43755
|
+
})
|
|
43756
|
+
);
|
|
43757
|
+
}
|
|
43758
|
+
|
|
43229
43759
|
// packages/cli/src/commands/integrations.ts
|
|
43230
43760
|
var where2 = (g2) => g2.repository_name ? `${g2.org_slug}/${g2.repository_name}` : g2.include_repos ? `${g2.org_slug} (and all repositories)` : g2.org_slug;
|
|
43231
43761
|
var renderGrants = (v) => v.items.length ? table(
|
|
@@ -43257,9 +43787,9 @@ function registerIntegrations(program2, rt) {
|
|
|
43257
43787
|
);
|
|
43258
43788
|
integrations.command("shares [credential]").description("Where a credential is shared (owner view), or with no argument what is shared with --org (or --repo with --for-repo)").option("--for-repo", "list what is shared with --repo instead of --org").option("--include-revoked", "include revoked grants").action(
|
|
43259
43789
|
act(rt, async (ctx, o, [id2]) => {
|
|
43260
|
-
const
|
|
43790
|
+
const c5 = ctx.client("user").grants;
|
|
43261
43791
|
const q = id2 ? subjectOf(id2) : o.forRepo ? { repository: await ctx.repoId(void 0, "user") } : { org: ctx.org() };
|
|
43262
|
-
ctx.result(await
|
|
43792
|
+
ctx.result(await c5.list({ ...q, ...o.includeRevoked ? { include_revoked: true } : {} }), renderGrants);
|
|
43263
43793
|
})
|
|
43264
43794
|
);
|
|
43265
43795
|
integrations.command("accept <grant>").description("Accept a credential a member offered to the organization (org admins)").action(act(rt, async (ctx, _o, [id2]) => ctx.result(await ctx.client("user").grants.accept(id2), (v) => `${v.id}: ${v.state}`)));
|
|
@@ -43341,11 +43871,11 @@ function targetOptions(cmd) {
|
|
|
43341
43871
|
return cmd.option("--platform <platform>", "workers | pages").option("--connection <connection>", "deploy connection (icn_\u2026)").option("--account-id <id>", "Cloudflare account id").option("--env <name>", "Wrangler environment (deploys with --env)").option("--worker <name>", "Worker name (or Pages project name)").option("--root <dir>", "root directory (where the Wrangler config lives)").option("--branch <name>", "production branch (default: the repository's default branch)").option("--install <cmd>", "install command").option("--build <cmd>", "build command").option("--output-dir <dir>", "Pages: the built site").option("--previews", "upload a preview of every open change").option("--no-previews", "no previews").option("--preview-agent-changes", "also preview changes made by agents or integrations, isolated (Worker Previews only)").option("--no-preview-agent-changes", "previews only for changes people upload").option("--preview-mode <mode>", "versions (preview version with an alias) | worker_previews (`wrangler preview`: Durable Objects allowed, bindings from the `previews` block)").option("--preview-check <name>", "report previews as this check").option("--name <name>", "target name").option("--steps <json>", `pre/post steps as a JSON array, @file or - (replaces the list), e.g. '[{"id":"migrate","kind":"d1_migrations","phase":"pre"}]'`);
|
|
43342
43872
|
}
|
|
43343
43873
|
async function planSetup(ctx, repo, o) {
|
|
43344
|
-
const
|
|
43874
|
+
const c5 = ctx.client("user").deploy;
|
|
43345
43875
|
const why = [];
|
|
43346
43876
|
const platform2 = o.platform ?? "workers";
|
|
43347
43877
|
if (platform2 !== "workers" && platform2 !== "pages") throw usage("--platform must be workers or pages");
|
|
43348
|
-
const conns = (await
|
|
43878
|
+
const conns = (await c5.connections(repo)).items.filter((x) => x.state === "active");
|
|
43349
43879
|
let conn;
|
|
43350
43880
|
if (o.connection) {
|
|
43351
43881
|
const found = conns.find((x) => x.id === o.connection);
|
|
@@ -43361,14 +43891,14 @@ async function planSetup(ctx, repo, o) {
|
|
|
43361
43891
|
account = conn.account_id;
|
|
43362
43892
|
why.push(`account ${conn.account_label ?? account}: the connection's account`);
|
|
43363
43893
|
} else if (!account) {
|
|
43364
|
-
const accounts = (await
|
|
43894
|
+
const accounts = (await c5.resources(repo, conn.id, "accounts")).items;
|
|
43365
43895
|
if (!accounts.length) throw new CliError(`connection ${conn.id} sees no Cloudflare account`, EXIT.NOT_FOUND, "NOT_FOUND");
|
|
43366
43896
|
const a = await pick3(ctx, "Cloudflare account", "--account-id", accounts, (x) => `${x.id} ${x.name}`);
|
|
43367
43897
|
account = a.id;
|
|
43368
43898
|
why.push(`account ${a.name}${accounts.length === 1 ? ": the only account" : ""}`);
|
|
43369
43899
|
}
|
|
43370
43900
|
let suggested = true;
|
|
43371
|
-
const sug = await
|
|
43901
|
+
const sug = await c5.suggestions(repo).catch((e) => {
|
|
43372
43902
|
if (!o.worker) throw e;
|
|
43373
43903
|
ctx.info("note: this server suggests no Wrangler configurations; using the flags as given");
|
|
43374
43904
|
suggested = false;
|
|
@@ -43447,8 +43977,8 @@ Merges to ${v.branch} deploy automatically. Deploy now: brnch deploy run ${v.id}
|
|
|
43447
43977
|
targetOptions(deploy.command("update <target>").description("Change a deploy target (only the given flags; an empty value clears a command or the environment)")).option("--disable", "stop deploying (merges no longer deploy)").option("--enable", "deploy again").action(
|
|
43448
43978
|
act(rt, async (ctx, o, [ref]) => {
|
|
43449
43979
|
if (o.disable && o.enable) throw usage("give either --disable or --enable");
|
|
43450
|
-
const
|
|
43451
|
-
const cur = await
|
|
43980
|
+
const c5 = ctx.client("user").deploy.targets;
|
|
43981
|
+
const cur = await c5.get(await targetId(ctx, ref));
|
|
43452
43982
|
const patch = {
|
|
43453
43983
|
name: o.name,
|
|
43454
43984
|
platform: o.platform,
|
|
@@ -43470,7 +44000,7 @@ Merges to ${v.branch} deploy automatically. Deploy now: brnch deploy run ${v.id}
|
|
|
43470
44000
|
};
|
|
43471
44001
|
const changes = Object.fromEntries(Object.entries(patch).filter(([, v]) => v !== void 0));
|
|
43472
44002
|
if (!Object.keys(changes).length) throw usage("nothing to change: pass at least one option");
|
|
43473
|
-
ctx.result(await
|
|
44003
|
+
ctx.result(await c5.update(cur.id, { ...changes, expected_version: cur.version }), renderTarget);
|
|
43474
44004
|
})
|
|
43475
44005
|
);
|
|
43476
44006
|
deploy.command("remove <target>").description("Delete a deploy target (its deployments stay listed). Requires --yes when non-interactive").action(
|
|
@@ -43559,13 +44089,13 @@ var renderDelegation = (d) => kv(
|
|
|
43559
44089
|
},
|
|
43560
44090
|
["id", "agent", "status", "origin", "task_id", "change_id", "sponsor", "model", "branch", "automatic", "budget", "updated_at", "version"]
|
|
43561
44091
|
) + renderIterations(d);
|
|
43562
|
-
async function watchHints(
|
|
44092
|
+
async function watchHints(c5, web, d) {
|
|
43563
44093
|
const hints = [];
|
|
43564
|
-
const repo = await
|
|
44094
|
+
const repo = await c5.repos.get(d.repository_id).catch(() => null);
|
|
43565
44095
|
if (repo) {
|
|
43566
44096
|
const base2 = `${web}/${repo.org_slug}/${repo.name}`;
|
|
43567
|
-
const change = d.change_id ? await
|
|
43568
|
-
const task = !change && d.task_id ? await
|
|
44097
|
+
const change = d.change_id ? await c5.changes.get(d.change_id).catch(() => null) : null;
|
|
44098
|
+
const task = !change && d.task_id ? await c5.tasks.get(d.task_id).catch(() => null) : null;
|
|
43569
44099
|
if (change) hints.push(`${base2}/changes/${change.number}`);
|
|
43570
44100
|
else if (task) hints.push(`${base2}/issues/${task.number}`);
|
|
43571
44101
|
const run3 = d.current_iteration?.run_id;
|
|
@@ -43584,7 +44114,7 @@ async function renderStarted2(ctx, d, what) {
|
|
|
43584
44114
|
].join("\n");
|
|
43585
44115
|
}
|
|
43586
44116
|
async function waitForIteration(ctx, start, o) {
|
|
43587
|
-
const
|
|
44117
|
+
const c5 = ctx.client("user");
|
|
43588
44118
|
const target = start.current_iteration?.id ?? null;
|
|
43589
44119
|
const deadline = Date.now() + (o.timeout ?? start.budget.iteration_minutes * 60 + 300) * 1e3;
|
|
43590
44120
|
let d = start;
|
|
@@ -43597,7 +44127,7 @@ async function waitForIteration(ctx, start, o) {
|
|
|
43597
44127
|
if (it ? ITERATION_DONE.has(it.state) : d.state !== "working") return { d, timedOut: false };
|
|
43598
44128
|
if (Date.now() > deadline) return { d, timedOut: true };
|
|
43599
44129
|
await ctx.deps.sleep(Math.max(1, o.interval) * 1e3);
|
|
43600
|
-
d = await
|
|
44130
|
+
d = await c5.delegations.get(start.id);
|
|
43601
44131
|
}
|
|
43602
44132
|
}
|
|
43603
44133
|
function waitExit(d, target, timedOut) {
|
|
@@ -43614,15 +44144,15 @@ async function finish(ctx, d, o, what) {
|
|
|
43614
44144
|
if (r.timedOut) ctx.info(`still working; follow with \`${BRAND.cli} agents status ${d.id}\``);
|
|
43615
44145
|
}
|
|
43616
44146
|
async function delegationFor(ctx, spec) {
|
|
43617
|
-
const
|
|
43618
|
-
if (spec.startsWith("dlg_")) return
|
|
43619
|
-
const ref = await resolveWorkRef(spec,
|
|
44147
|
+
const c5 = ctx.client("user");
|
|
44148
|
+
if (spec.startsWith("dlg_")) return c5.delegations.get(spec);
|
|
44149
|
+
const ref = await resolveWorkRef(spec, c5, () => ctx.repoId(void 0, "user"));
|
|
43620
44150
|
if (ref.kind === "change") {
|
|
43621
|
-
const d2 = await
|
|
44151
|
+
const d2 = await c5.delegations.forChange(ref.id);
|
|
43622
44152
|
if (!d2) throw new CliError(`no agent is delegated on change ${spec}`, EXIT.NOT_FOUND, "NOT_FOUND");
|
|
43623
44153
|
return d2;
|
|
43624
44154
|
}
|
|
43625
|
-
const { items } = await
|
|
44155
|
+
const { items } = await c5.delegations.forTask(ref.id);
|
|
43626
44156
|
const d = items.find((x) => x.state !== "stopped") ?? [...items].sort((a, b) => b.created_at.localeCompare(a.created_at))[0];
|
|
43627
44157
|
if (!d) throw new CliError(`no agent is delegated on issue ${spec}`, EXIT.NOT_FOUND, "NOT_FOUND");
|
|
43628
44158
|
return d;
|
|
@@ -43639,8 +44169,8 @@ function registerDelegate(program2, rt) {
|
|
|
43639
44169
|
const agent = vendorArg(o.agent);
|
|
43640
44170
|
if (o.prompt !== void 0 && o.promptFile !== void 0) throw usage("pass either --prompt or --prompt-file, not both");
|
|
43641
44171
|
const prompt2 = o.promptFile !== void 0 ? await readText(fileSpec(o.promptFile), ctx.input) : o.prompt ?? "";
|
|
43642
|
-
const
|
|
43643
|
-
const ref = await resolveWorkRef(target,
|
|
44172
|
+
const c5 = ctx.client("user");
|
|
44173
|
+
const ref = await resolveWorkRef(target, c5, () => ctx.repoId(void 0, "user"));
|
|
43644
44174
|
const budget = {
|
|
43645
44175
|
...o.maxIterations !== void 0 ? { max_iterations: o.maxIterations } : {},
|
|
43646
44176
|
...o.maxTokens !== void 0 ? { max_tokens: o.maxTokens } : {},
|
|
@@ -43648,7 +44178,7 @@ function registerDelegate(program2, rt) {
|
|
|
43648
44178
|
};
|
|
43649
44179
|
const body = { agent, prompt: prompt2, ...o.model ? { model: o.model } : {}, budget, auto_on_review: !!o.autoReview, auto_on_check_failure: !!o.autoChecks };
|
|
43650
44180
|
const options = { idempotencyKey: o.idempotencyKey ?? crypto.randomUUID() };
|
|
43651
|
-
const d = ref.kind === "issue" ? await
|
|
44181
|
+
const d = ref.kind === "issue" ? await c5.delegations.delegateTask(ref.id, body, options) : await c5.delegations.delegateChange(ref.id, body, options);
|
|
43652
44182
|
await finish(ctx, d, o, `Delegated ${ref.kind} ${target} to`);
|
|
43653
44183
|
})
|
|
43654
44184
|
);
|
|
@@ -43826,9 +44356,12 @@ function registerCodingAgents(program2, rt) {
|
|
|
43826
44356
|
// packages/cli/src/commands/platform.ts
|
|
43827
44357
|
function registerEvents(program2, rt) {
|
|
43828
44358
|
const events = program2.command("events").description("Platform and session event streams");
|
|
43829
|
-
events.command("watch").description("Follow
|
|
44359
|
+
events.command("watch").description("Follow new events of --org (or one agent session with --session). With --json, prints one JSON object per line").option("--session <id>", "follow this agent session's activity instead of the org").option("--after <cursor>", "start after this event id / cursor / sequence (replays what came since) instead of now").option("--max <n>", "stop after this many events", (v) => parseIntOption(v, "--max")).action(
|
|
43830
44360
|
act(rt, async (ctx, o) => {
|
|
43831
|
-
const stream = o.session ? ctx.client("agent").sessions.stream(o.session, { after: o.after }) :
|
|
44361
|
+
const stream = o.session ? ctx.client("agent").sessions.stream(o.session, { after: o.after }) : (
|
|
44362
|
+
// Organization events are polled from the replay (there is no push stream for them); without --after, only new ones.
|
|
44363
|
+
ctx.client("user").events.stream(ctx.org(), o.after ? { after: o.after } : { fromNow: true })
|
|
44364
|
+
);
|
|
43832
44365
|
let n = 0;
|
|
43833
44366
|
if (!ctx.json) ctx.info(`watching ${o.session ? `session ${o.session}` : `org ${ctx.org()}`} (Ctrl-C to stop)`);
|
|
43834
44367
|
for await (const ev of stream) {
|
|
@@ -43853,12 +44386,12 @@ function registerPolicy(program2, rt) {
|
|
|
43853
44386
|
act(rt, async (ctx, o, [file2]) => {
|
|
43854
44387
|
const doc = await readJsonObject(fileSpec(file2), ctx.input, "policy file");
|
|
43855
44388
|
const rules = doc.rules ?? doc;
|
|
43856
|
-
const
|
|
44389
|
+
const c5 = ctx.client("user");
|
|
43857
44390
|
const repo = await ctx.repoId(void 0, "user");
|
|
43858
44391
|
let expected = o.expectedVersion ?? (typeof doc.expected_version === "number" ? doc.expected_version : void 0);
|
|
43859
44392
|
if (expected === void 0) {
|
|
43860
44393
|
try {
|
|
43861
|
-
expected = (await
|
|
44394
|
+
expected = (await c5.repos.policy.get(repo)).version;
|
|
43862
44395
|
} catch (e) {
|
|
43863
44396
|
if (!isForgeApiError(e) || e.code !== "NOT_FOUND") throw e;
|
|
43864
44397
|
expected = 0;
|
|
@@ -43866,7 +44399,7 @@ function registerPolicy(program2, rt) {
|
|
|
43866
44399
|
}
|
|
43867
44400
|
await ctx.confirm(`adopt a new policy for ${ctx.repoSpec()} (replacing version ${expected})`);
|
|
43868
44401
|
const note = o.note ?? (typeof doc.note === "string" ? doc.note : void 0);
|
|
43869
|
-
ctx.result(await
|
|
44402
|
+
ctx.result(await c5.repos.policy.adopt(repo, { rules, expected_version: expected, note }), renderPolicy);
|
|
43870
44403
|
})
|
|
43871
44404
|
);
|
|
43872
44405
|
}
|
|
@@ -43916,15 +44449,15 @@ var renderFork = (r) => kv({ ...r, parent: r.fork?.parent.full_name ?? r.fork?.p
|
|
|
43916
44449
|
]);
|
|
43917
44450
|
var renderSync = (r) => r.status === "up_to_date" ? `${r.ref} is up to date with ${r.parent.full_name} (${r.new_oid.slice(0, 12)})` : `${r.ref} fast-forwarded ${r.old_oid ? r.old_oid.slice(0, 12) : "(new)"} \u2192 ${r.new_oid.slice(0, 12)} from ${r.parent.full_name}`;
|
|
43918
44451
|
function registerForks(program2, rt) {
|
|
43919
|
-
const repo = program2.commands.find((
|
|
44452
|
+
const repo = program2.commands.find((c5) => c5.name() === "repo");
|
|
43920
44453
|
if (!repo) throw new Error("internal: repo command must be registered before forks");
|
|
43921
44454
|
repo.command("fork <namespace>").description("Fork --repo into <namespace> (an organization you can create repositories in)").option("--name <name>", "name of the fork (defaults to the source name)").option("--description <text>", "description (defaults to the source description)").option("--default-branch-only", "copy only the default branch").option("--idempotency-key <key>", "reuse to retry the same request safely").action(
|
|
43922
44455
|
act(rt, async (ctx, o, [namespace]) => {
|
|
43923
44456
|
if (!namespace) throw usage("pass the target namespace");
|
|
43924
44457
|
const source = await ctx.repoId(void 0, "user");
|
|
43925
|
-
const
|
|
44458
|
+
const c5 = ctx.client("user");
|
|
43926
44459
|
ctx.info("forking (this can take a while for large repositories)\u2026");
|
|
43927
|
-
const fork = await
|
|
44460
|
+
const fork = await c5.forks.create(source, { namespace, name: o.name, description: o.description, default_branch_only: !!o.defaultBranchOnly }, o.idempotencyKey ? { idempotencyKey: o.idempotencyKey } : {});
|
|
43928
44461
|
ctx.result(fork, renderFork);
|
|
43929
44462
|
})
|
|
43930
44463
|
);
|
|
@@ -43970,7 +44503,7 @@ function render2(v) {
|
|
|
43970
44503
|
const checks = p?.readiness.required_checks.length ? `
|
|
43971
44504
|
|
|
43972
44505
|
Required checks:
|
|
43973
|
-
${p.readiness.required_checks.map((
|
|
44506
|
+
${p.readiness.required_checks.map((c5) => ` ${c5.name}: ${c5.status} on ${c5.subject}${c5.covers_merged_tree === void 0 ? "" : c5.covers_merged_tree ? " (covered the merged tree)" : " (did NOT cover the merged tree)"}`).join("\n")}` : "";
|
|
43974
44507
|
const evidence = p?.evidence.length ? `
|
|
43975
44508
|
|
|
43976
44509
|
Evidence:
|
|
@@ -43987,11 +44520,11 @@ function mergedTreeTested(p) {
|
|
|
43987
44520
|
if (t) return `yes: every required check passed on tree ${p.readiness.candidate_tree_oid} (base ${p.readiness.target_oid})`;
|
|
43988
44521
|
return p.readiness.required_checks.length ? "NO: only the branch head was tested for some required checks; the merged result is untested" : "NO: the policy required no checks";
|
|
43989
44522
|
}
|
|
43990
|
-
async function resolveRepoId(ctx,
|
|
44523
|
+
async function resolveRepoId(ctx, c5) {
|
|
43991
44524
|
const spec = ctx.repoSpec();
|
|
43992
44525
|
const slash = spec.indexOf("/");
|
|
43993
44526
|
if (slash === -1) return spec;
|
|
43994
|
-
return (await
|
|
44527
|
+
return (await c5.repos.getByName(spec.slice(0, slash), spec.slice(slash + 1))).id;
|
|
43995
44528
|
}
|
|
43996
44529
|
async function readKeys(ctx, file2) {
|
|
43997
44530
|
const full = isAbsolute8(file2) ? file2 : resolve8(ctx.deps.cwd, file2);
|
|
@@ -44009,7 +44542,7 @@ function registerVerify(program2, rt) {
|
|
|
44009
44542
|
program2.command("verify <target>").description("Verify the merge receipt of a commit (or a receipt id rcp_\u2026) offline. Exit 0 verified, 1 invalid, 3 no receipt").option("--keys <file>", "pinned key set (JSON from /.well-known/brnch-keys) instead of fetching it from the server").option("--no-local", "skip the comparison with the local git clone").action(
|
|
44010
44543
|
act(rt, async (ctx, o, [target]) => {
|
|
44011
44544
|
if (!target) throw usage("pass a commit or a receipt id");
|
|
44012
|
-
const
|
|
44545
|
+
const c5 = ctx.token("user").token ? ctx.client("user") : ctx.client("user", { anonymous: true });
|
|
44013
44546
|
const git3 = (args) => ctx.deps.gitOutput(args, ctx.deps.cwd);
|
|
44014
44547
|
const inClone = o.local && (await git3(["rev-parse", "--is-inside-work-tree"])).stdout.trim() === "true";
|
|
44015
44548
|
const out = { verified: false, status: "invalid", target, receipt_id: null, repository: null, ref: null, commit: null, tree: null, key_id: null, key_status: null, digest: null, local: { status: o.local ? "not_a_clone" : "skipped", tree: null }, errors: [], statement: null };
|
|
@@ -44017,7 +44550,7 @@ function registerVerify(program2, rt) {
|
|
|
44017
44550
|
let expectCommit = null;
|
|
44018
44551
|
try {
|
|
44019
44552
|
if (/^rcp_[0-9a-z]+$/.test(target)) {
|
|
44020
|
-
receipt = await
|
|
44553
|
+
receipt = await c5.receipts.get(target);
|
|
44021
44554
|
} else {
|
|
44022
44555
|
expectCommit = /^[0-9a-f]{40}$/.test(target) ? target : null;
|
|
44023
44556
|
if (!expectCommit && inClone) {
|
|
@@ -44025,7 +44558,7 @@ function registerVerify(program2, rt) {
|
|
|
44025
44558
|
if (r.code === 0) expectCommit = r.stdout.trim();
|
|
44026
44559
|
}
|
|
44027
44560
|
if (!expectCommit) throw usage("pass a full 40-character commit id or a receipt id (rcp_\u2026); revisions like HEAD resolve only inside a clone");
|
|
44028
|
-
receipt = await
|
|
44561
|
+
receipt = await c5.receipts.forCommit(await resolveRepoId(ctx, c5), expectCommit);
|
|
44029
44562
|
}
|
|
44030
44563
|
} catch (e) {
|
|
44031
44564
|
if (isForgeApiError(e) && e.code === "NOT_FOUND") {
|
|
@@ -44035,7 +44568,7 @@ function registerVerify(program2, rt) {
|
|
|
44035
44568
|
}
|
|
44036
44569
|
throw e;
|
|
44037
44570
|
}
|
|
44038
|
-
const keys = o.keys ? await readKeys(ctx, o.keys) : (await
|
|
44571
|
+
const keys = o.keys ? await readKeys(ctx, o.keys) : (await c5.receipts.keys()).keys;
|
|
44039
44572
|
if (!keys.length) throw new CliError("the server publishes no signing keys", EXIT.UNAVAILABLE, "NO_KEYS");
|
|
44040
44573
|
const v = await verifyReceipt(receipt.envelope, keys, { expect: expectCommit ? { commit: expectCommit } : {} });
|
|
44041
44574
|
const subject = v.statement?.subject?.[0]?.digest;
|
|
@@ -44112,7 +44645,7 @@ var REPO_FIELDS = ["id", "org_slug", "name", "description", "visibility", "defau
|
|
|
44112
44645
|
var renderRepo2 = (r) => kv(r, REPO_FIELDS) + (r.import ? `
|
|
44113
44646
|
import ${r.import.status}${r.import.shallow ? " (shallow)" : ""}` : "");
|
|
44114
44647
|
function renderLog(p) {
|
|
44115
|
-
const rows2 = p.items.map((
|
|
44648
|
+
const rows2 = p.items.map((c5) => ({ oid: c5.oid.slice(0, 12), date: c5.committer.date.slice(0, 10), author: c5.author.name, subject: c5.message.split("\n", 1)[0] }));
|
|
44116
44649
|
const lines = [table(rows2, ["oid", "date", "author", "subject"])];
|
|
44117
44650
|
const s = p.path_scan;
|
|
44118
44651
|
if (s) lines.push(s.complete ? `scanned ${s.scanned_total} commits: full first-parent history of ${s.path}` : `scanned ${s.scanned_total} commits so far; older history not searched yet (more: --cursor ${p.next_cursor})`);
|
|
@@ -44157,7 +44690,7 @@ Yours: ${choices.join(", ")}
|
|
|
44157
44690
|
Set it with \`${BRAND.cli} org switch <org>\`.`);
|
|
44158
44691
|
}
|
|
44159
44692
|
const n = Number((await ctx.deps.prompt(`? Default organization?
|
|
44160
|
-
${choices.map((
|
|
44693
|
+
${choices.map((c5, i) => ` ${i + 1}) ${c5}`).join("\n")}
|
|
44161
44694
|
`)).trim());
|
|
44162
44695
|
if (!Number.isInteger(n) || n < 1 || n > namespaces.length) throw new CliError("aborted", EXIT.USAGE, "ABORTED");
|
|
44163
44696
|
slug2 = namespaces[n - 1].slug;
|
|
@@ -44206,18 +44739,18 @@ function registerRepo(program2, rt) {
|
|
|
44206
44739
|
);
|
|
44207
44740
|
repo.command("list").description("Repositories in --org").option("--limit <n>", "page size", (v) => parseIntOption(v, "--limit")).option("--cursor <cursor>", "page cursor").option("--all", "follow every page").action(
|
|
44208
44741
|
act(rt, async (ctx, o) => {
|
|
44209
|
-
const
|
|
44742
|
+
const c5 = ctx.client("agent");
|
|
44210
44743
|
const orgSlug = ctx.org();
|
|
44211
|
-
const page = o.all ? { items: await collect(paginate((cursor2) =>
|
|
44744
|
+
const page = o.all ? { items: await collect(paginate((cursor2) => c5.repos.list(orgSlug, { cursor: cursor2, limit: o.limit }))), next_cursor: null } : await c5.repos.list(orgSlug, { limit: o.limit, cursor: o.cursor });
|
|
44212
44745
|
ctx.result(page, (v) => listWithCursor(v, ["name", "visibility", "lifecycle", "default_branch", "id"]));
|
|
44213
44746
|
})
|
|
44214
44747
|
);
|
|
44215
44748
|
repo.command("migrate <provider> <source>").description("Import GitHub/GitLab issues, pull/merge requests, comments and releases as historical records (provider: github | gitlab; source: owner/repo)").option("--name <name>", "create the repository by importing its default branch").option("--into <repo>", "import metadata into an existing repository (org/name or id), e.g. after git push --mirror").option("--no-pull-requests", "skip pull/merge requests").option("--token-stdin", "read a source read-token from stdin (never pass tokens as arguments)").option("--wait", "poll until the migration finishes; exit 0 only when completed").action(
|
|
44216
44749
|
act(rt, async (ctx, o, [provider, source]) => {
|
|
44217
44750
|
if (provider !== "github" && provider !== "gitlab") throw usage("provider must be github or gitlab");
|
|
44218
|
-
const
|
|
44751
|
+
const c5 = ctx.client("user");
|
|
44219
44752
|
const sourceToken = o.tokenStdin ? (await new Response(process.stdin).text()).trim() : void 0;
|
|
44220
|
-
let job2 = await
|
|
44753
|
+
let job2 = await c5.migrations.start(ctx.org(), {
|
|
44221
44754
|
provider,
|
|
44222
44755
|
source,
|
|
44223
44756
|
repository_id: o.into ? await ctx.repoId(o.into) : void 0,
|
|
@@ -44227,7 +44760,7 @@ function registerRepo(program2, rt) {
|
|
|
44227
44760
|
});
|
|
44228
44761
|
while (o.wait && (job2.state === "queued" || job2.state === "running")) {
|
|
44229
44762
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
44230
|
-
job2 = await
|
|
44763
|
+
job2 = await c5.migrations.get(job2.id);
|
|
44231
44764
|
}
|
|
44232
44765
|
const view = { id: job2.id, state: job2.state, issues: job2.report.counts.issues, pull_requests: job2.report.counts.pull_requests, comments: job2.report.counts.comments, releases: job2.report.counts.releases, missing: job2.report.missing.join("; ") || "-" };
|
|
44233
44766
|
ctx.result(job2, () => kv(view, Object.keys(view)));
|
|
@@ -44255,8 +44788,8 @@ function registerRepo(program2, rt) {
|
|
|
44255
44788
|
repo.command("clone [repo] [directory]").description("git clone over SSH when this machine is set up for it (`ssh setup`) and the key can be used now, else HTTPS with your login (never written to .git/config)").option("--ssh", "clone over SSH").option("--https", "clone over HTTPS").action(
|
|
44256
44789
|
act(rt, async (ctx, o, [spec, dir]) => {
|
|
44257
44790
|
if (o.ssh && o.https) throw usage("--ssh and --https are mutually exclusive");
|
|
44258
|
-
const
|
|
44259
|
-
const r = await
|
|
44791
|
+
const c5 = ctx.client("agent");
|
|
44792
|
+
const r = await c5.repos.get(await ctx.repoId(spec));
|
|
44260
44793
|
const directory = dir ?? r.name;
|
|
44261
44794
|
const t = await chooseTransport(ctx, o);
|
|
44262
44795
|
if (t.transport === "ssh") {
|
|
@@ -44342,7 +44875,7 @@ function registerRelease(program2, rt) {
|
|
|
44342
44875
|
}
|
|
44343
44876
|
|
|
44344
44877
|
// packages/cli/src/commands/social.ts
|
|
44345
|
-
var pageOptions = (
|
|
44878
|
+
var pageOptions = (c5) => c5.option("--limit <n>", "page size", (v) => parseIntOption(v, "--limit")).option("--cursor <cursor>", "page cursor");
|
|
44346
44879
|
function reader(ctx) {
|
|
44347
44880
|
return ctx.token("user").token ? ctx.client("user") : ctx.client("user", { anonymous: true });
|
|
44348
44881
|
}
|
|
@@ -44367,7 +44900,7 @@ var renderProfile = (p) => kv({ ...p, orgs: p.orgs.map((o) => o.slug).join(", ")
|
|
|
44367
44900
|
var followName = (f) => f.type === "user" ? f.user.handle ?? f.user.id : f.org.slug;
|
|
44368
44901
|
var renderFollows = (p) => listWithCursor({ ...p, items: p.items.map((f) => ({ type: f.type, name: followName(f), since: f.followed_at })) }, ["type", "name", "since"]);
|
|
44369
44902
|
var repoColumns = ["org_slug", "name", "stars_count", "visibility", "description"];
|
|
44370
|
-
var renderReactions = (s) => REACTION_CONTENTS.filter((
|
|
44903
|
+
var renderReactions = (s) => REACTION_CONTENTS.filter((c5) => s[c5] > 0).map((c5) => `${c5} ${s[c5]}${s.viewer.includes(c5) ? " (you)" : ""}`).join(" ") || "(no reactions)";
|
|
44371
44904
|
function subjectOf2(id2) {
|
|
44372
44905
|
const prefix = id2.split("_")[0];
|
|
44373
44906
|
const map2 = { chg: "change", task: "task", cmt: "comment", rel: "release" };
|
|
@@ -44425,12 +44958,12 @@ ${table(v.days.filter((d) => d.count > 0), ["date", "count", "pushes", "changes_
|
|
|
44425
44958
|
await ctx.client("user").social.unfollow(name);
|
|
44426
44959
|
ctx.result({ following: null, unfollowed: name, ok: true }, `Unfollowed ${name}`);
|
|
44427
44960
|
}));
|
|
44428
|
-
const starAction = (
|
|
44429
|
-
const
|
|
44961
|
+
const starAction = (on2) => act(rt, async (ctx, _o, [repo]) => {
|
|
44962
|
+
const c5 = ctx.client("user");
|
|
44430
44963
|
const id2 = await ctx.repoId(repo, "user");
|
|
44431
|
-
await (
|
|
44432
|
-
const r = await
|
|
44433
|
-
ctx.result(r, (v) => `${
|
|
44964
|
+
await (on2 ? c5.social.star(id2) : c5.social.unstar(id2));
|
|
44965
|
+
const r = await c5.repos.get(id2);
|
|
44966
|
+
ctx.result(r, (v) => `${on2 ? "Starred" : "Unstarred"} ${v.org_slug}/${v.name} (${v.stars_count ?? 0} stars)`);
|
|
44434
44967
|
});
|
|
44435
44968
|
program2.command("star [repo]").description("Star a repository (org/name or id; default --repo)").action(starAction(true));
|
|
44436
44969
|
program2.command("unstar [repo]").description("Remove your star").action(starAction(false));
|
|
@@ -44442,12 +44975,12 @@ ${table(v.days.filter((d) => d.count > 0), ["date", "count", "pushes", "changes_
|
|
|
44442
44975
|
);
|
|
44443
44976
|
program2.command("watch [repo]").description("Set your notification level for a repository").option("--level <level>", SUBSCRIPTION_LEVELS.join(" | "), "watching").option("--reset", "remove your subscription (back to participating)").action(
|
|
44444
44977
|
act(rt, async (ctx, o, [repo]) => {
|
|
44445
|
-
const
|
|
44978
|
+
const c5 = ctx.client("user");
|
|
44446
44979
|
const id2 = await ctx.repoId(repo, "user");
|
|
44447
|
-
if (o.reset) await
|
|
44980
|
+
if (o.reset) await c5.social.unsubscribe(id2);
|
|
44448
44981
|
else if (!SUBSCRIPTION_LEVELS.includes(o.level)) throw usage(`--level must be one of ${SUBSCRIPTION_LEVELS.join(", ")}`);
|
|
44449
|
-
else await
|
|
44450
|
-
ctx.result(await
|
|
44982
|
+
else await c5.social.subscribe(id2, o.level);
|
|
44983
|
+
ctx.result(await c5.social.subscription(id2), (v) => `Notification level: ${v.level}${v.explicit ? "" : " (default)"}`);
|
|
44451
44984
|
})
|
|
44452
44985
|
);
|
|
44453
44986
|
const explore = pageOptions(
|
|
@@ -44486,16 +45019,16 @@ ${table(v.days.filter((d) => d.count > 0), ["date", "count", "pushes", "changes_
|
|
|
44486
45019
|
);
|
|
44487
45020
|
label2.command("edit <label>").description("Rename or recolor a label (name or id); uses the current version unless --expected-version pins it").option("--name <name>", "new name").option("--color <hex>", "new color").option("--description <text>", "new description").option("--expected-version <n>", "expected version (optimistic concurrency)", (v) => parseIntOption(v, "--expected-version")).action(
|
|
44488
45021
|
act(rt, async (ctx, o, [ref]) => {
|
|
44489
|
-
const
|
|
45022
|
+
const c5 = ctx.client("user");
|
|
44490
45023
|
const repo = await ctx.repoId(void 0, "user");
|
|
44491
45024
|
let version4 = o.expectedVersion;
|
|
44492
45025
|
if (version4 === void 0) {
|
|
44493
|
-
const all = await
|
|
45026
|
+
const all = await c5.social.labels.list(repo, { limit: 100 });
|
|
44494
45027
|
const cur = all.items.find((l2) => l2.id === ref || l2.name.toLowerCase() === ref.toLowerCase());
|
|
44495
45028
|
if (!cur) throw usage(`no label ${ref} in this repository`);
|
|
44496
45029
|
version4 = cur.version;
|
|
44497
45030
|
}
|
|
44498
|
-
const l = await
|
|
45031
|
+
const l = await c5.social.labels.update(repo, ref, { name: o.name, color: o.color, description: o.description, version: version4 });
|
|
44499
45032
|
ctx.result(l, (v) => kv(v, ["id", "name", "color", "description", "version"]));
|
|
44500
45033
|
})
|
|
44501
45034
|
);
|
|
@@ -44529,8 +45062,8 @@ ${table(v.days.filter((d) => d.count > 0), ["date", "count", "pushes", "changes_
|
|
|
44529
45062
|
act(rt, async (ctx, o, [id2, content]) => {
|
|
44530
45063
|
if (!REACTION_CONTENTS.includes(content)) throw usage(`reaction must be one of: ${REACTION_CONTENTS.join(" ")}`);
|
|
44531
45064
|
const body = { subject_type: subjectOf2(id2), subject_id: id2, content };
|
|
44532
|
-
const
|
|
44533
|
-
ctx.result(await (o.remove ?
|
|
45065
|
+
const c5 = ctx.client("user").social;
|
|
45066
|
+
ctx.result(await (o.remove ? c5.unreact(body) : c5.react(body)), renderReactions);
|
|
44534
45067
|
})
|
|
44535
45068
|
);
|
|
44536
45069
|
}
|
|
@@ -44624,7 +45157,7 @@ function registerStack(program2, rt) {
|
|
|
44624
45157
|
else if (p.state === "blocked") ctx.setExit(EXIT.NOT_READY);
|
|
44625
45158
|
})
|
|
44626
45159
|
);
|
|
44627
|
-
const change = program2.commands.find((
|
|
45160
|
+
const change = program2.commands.find((c5) => c5.name() === "change") ?? program2.command("change");
|
|
44628
45161
|
change.command("range-diff").argument("<change>", CHANGE_ARG).description("Compare two revisions of a change robustly to rebases (like git range-diff)").requiredOption("--from <revision>", "older revision (number or id)").option("--to <revision>", "newer revision (default: current)").option("--creation-factor <percent>", "pairing threshold, as git range-diff", (v) => parseIntOption(v, "--creation-factor")).action(
|
|
44629
45162
|
act(rt, async (ctx, o, [id2]) => {
|
|
44630
45163
|
ctx.result(await ctx.client().stacks.rangeDiff(await ctx.changeId(id2), { from: o.from, to: o.to, creation_factor: o.creationFactor }), renderRangeDiff);
|
|
@@ -44652,7 +45185,7 @@ next: --cursor ${v.next_cursor}` : "") : listWithCursor(v, ["id"]));
|
|
|
44652
45185
|
}
|
|
44653
45186
|
|
|
44654
45187
|
// packages/cli/src/commands/coordination.ts
|
|
44655
|
-
var holderOf = (
|
|
45188
|
+
var holderOf = (c5) => `${c5.holder.display_name ?? c5.holder.id}${c5.session_id ? ` (${c5.session_id})` : ""}`;
|
|
44656
45189
|
var renderClaim = (r) => [
|
|
44657
45190
|
`${r.already_held ? "Already yours" : "Claimed"}: ${r.claim.key}${r.claim.change ? ` (change #${r.claim.change.number})` : ""}`,
|
|
44658
45191
|
...r.skipped.length ? [`Taken by others: ${r.skipped.join(", ")}`] : [],
|
|
@@ -44686,7 +45219,7 @@ function registerCoordination(program2, rt) {
|
|
|
44686
45219
|
ctx.result(
|
|
44687
45220
|
r,
|
|
44688
45221
|
() => r.items.length ? table(
|
|
44689
|
-
r.items.map((
|
|
45222
|
+
r.items.map((c5) => ({ key: c5.key, status: c5.status, holder: holderOf(c5), change: c5.change ? `#${c5.change.number}` : "", note: c5.note ?? "" })),
|
|
44690
45223
|
["key", "status", "holder", "change", "note"]
|
|
44691
45224
|
) : "No claimed keys."
|
|
44692
45225
|
);
|
|
@@ -44698,7 +45231,7 @@ function registerCoordination(program2, rt) {
|
|
|
44698
45231
|
var SHELLS2 = ["bash", "zsh", "fish"];
|
|
44699
45232
|
var HELP = { flags: ["-h", "--help"], description: "display help for command", takesValue: false };
|
|
44700
45233
|
function completionTree(cmd) {
|
|
44701
|
-
const hidden = (
|
|
45234
|
+
const hidden = (c5) => c5._hidden === true;
|
|
44702
45235
|
return {
|
|
44703
45236
|
name: cmd.name(),
|
|
44704
45237
|
description: cmd.description(),
|
|
@@ -44706,7 +45239,7 @@ function completionTree(cmd) {
|
|
|
44706
45239
|
...cmd.options.filter((o) => !o.hidden).map((o) => ({ flags: [o.short, o.long].filter((f) => !!f), description: o.description, takesValue: o.required || o.optional })),
|
|
44707
45240
|
HELP
|
|
44708
45241
|
],
|
|
44709
|
-
subcommands: cmd.commands.filter((
|
|
45242
|
+
subcommands: cmd.commands.filter((c5) => !hidden(c5)).flatMap((c5) => [c5.name(), ...c5.aliases()].map((name) => ({ ...completionTree(c5), name })))
|
|
44710
45243
|
};
|
|
44711
45244
|
}
|
|
44712
45245
|
function rows(root) {
|
|
@@ -45207,7 +45740,7 @@ async function runDoctor(ctx) {
|
|
|
45207
45740
|
const agentSession = await checkAgentSession(ctx, auth.me).catch((e) => check2("agent_session", "warn", `cannot check the agent session: ${e.message}`));
|
|
45208
45741
|
const checks = [checkNode(sys.nodeVersion), git3, config2, checkProxy(ctx.deps.env), server.connectivity, server.minVersion, server.clock, auth.check, remote, credentials, ssh, ...agentSession ? [agentSession] : [], update];
|
|
45209
45742
|
const install2 = detectInstall(sys.scriptPath, sys.platform);
|
|
45210
|
-
return { ok: !checks.some((
|
|
45743
|
+
return { ok: !checks.some((c5) => c5.status === "fail"), version: BRAND.version, url: ctx.baseUrl, install: { method: install2.method, path: install2.path }, checks };
|
|
45211
45744
|
}
|
|
45212
45745
|
|
|
45213
45746
|
// packages/cli/src/commands/tooling.ts
|
|
@@ -45284,7 +45817,7 @@ ${manualInstructions(m)}`, EXIT.USAGE, "UPGRADE_UNSUPPORTED", { install_method:
|
|
|
45284
45817
|
report3,
|
|
45285
45818
|
(r) => [
|
|
45286
45819
|
`${p.bold(`${BRAND.cli} ${r.version}`)} (${r.install.method}) \u2192 ${r.url}`,
|
|
45287
|
-
...r.checks.map((
|
|
45820
|
+
...r.checks.map((c5) => `${mark[c5.status]} ${c5.id.padEnd(14)} ${c5.summary}`),
|
|
45288
45821
|
r.ok ? p.ok("No problems found.") : p.fail("Problems found: see FAIL lines above.")
|
|
45289
45822
|
].join("\n")
|
|
45290
45823
|
);
|
|
@@ -45391,19 +45924,19 @@ function parseCron(source) {
|
|
|
45391
45924
|
const [mi, h, d, mo, w] = fields.map((x, i) => parseField(x, FIELDS[i]));
|
|
45392
45925
|
return { source, minutes: mi, hours: h, days: d, months: mo, weekdays: w, daysRestricted: fields[2] !== "*", weekdaysRestricted: fields[4] !== "*" };
|
|
45393
45926
|
}
|
|
45394
|
-
function minIntervalMinutes(
|
|
45395
|
-
const m =
|
|
45927
|
+
function minIntervalMinutes(c5) {
|
|
45928
|
+
const m = c5.minutes;
|
|
45396
45929
|
let gap = 60;
|
|
45397
45930
|
for (let i = 1; i < m.length; i++) gap = Math.min(gap, m[i] - m[i - 1]);
|
|
45398
|
-
const consecutiveHours =
|
|
45931
|
+
const consecutiveHours = c5.hours.some((h) => c5.hours.includes((h + 1) % 24));
|
|
45399
45932
|
if (consecutiveHours) gap = Math.min(gap, 60 - m[m.length - 1] + m[0]);
|
|
45400
45933
|
return gap;
|
|
45401
45934
|
}
|
|
45402
45935
|
function validateCron(source) {
|
|
45403
|
-
const
|
|
45404
|
-
const gap = minIntervalMinutes(
|
|
45936
|
+
const c5 = parseCron(source);
|
|
45937
|
+
const gap = minIntervalMinutes(c5);
|
|
45405
45938
|
if (gap < LIMITS.minCronIntervalMinutes) throw new CronError(`schedule "${source}" fires every ${gap} minute(s); the minimum interval is ${LIMITS.minCronIntervalMinutes} minutes`);
|
|
45406
|
-
return
|
|
45939
|
+
return c5;
|
|
45407
45940
|
}
|
|
45408
45941
|
|
|
45409
45942
|
// packages/workflows/src/expressions.ts
|
|
@@ -45421,12 +45954,12 @@ function tokenize(src) {
|
|
|
45421
45954
|
const out = [];
|
|
45422
45955
|
let i = 0;
|
|
45423
45956
|
while (i < src.length) {
|
|
45424
|
-
const
|
|
45425
|
-
if (
|
|
45957
|
+
const c5 = src[i];
|
|
45958
|
+
if (c5 === " " || c5 === " " || c5 === "\n" || c5 === "\r") {
|
|
45426
45959
|
i++;
|
|
45427
45960
|
continue;
|
|
45428
45961
|
}
|
|
45429
|
-
if (
|
|
45962
|
+
if (c5 === "'") {
|
|
45430
45963
|
let s = "";
|
|
45431
45964
|
const at = i;
|
|
45432
45965
|
i++;
|
|
@@ -45447,8 +45980,8 @@ function tokenize(src) {
|
|
|
45447
45980
|
out.push({ t: "str", v: s, at });
|
|
45448
45981
|
continue;
|
|
45449
45982
|
}
|
|
45450
|
-
if (
|
|
45451
|
-
if (/[0-9]/.test(
|
|
45983
|
+
if (c5 === '"') throw new ExpressionError("string literals use single quotes", i);
|
|
45984
|
+
if (/[0-9]/.test(c5) || c5 === "-" && /[0-9.]/.test(src[i + 1] ?? "") && !isOperandEnd(out) || c5 === "." && /[0-9]/.test(src[i + 1] ?? "")) {
|
|
45452
45985
|
const m = /^-?(0x[0-9a-fA-F]+|(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?)/.exec(src.slice(i));
|
|
45453
45986
|
if (!m) throw new ExpressionError("invalid number", i);
|
|
45454
45987
|
const v = Number(m[0]);
|
|
@@ -45457,7 +45990,7 @@ function tokenize(src) {
|
|
|
45457
45990
|
i += m[0].length;
|
|
45458
45991
|
continue;
|
|
45459
45992
|
}
|
|
45460
|
-
if (/[A-Za-z_]/.test(
|
|
45993
|
+
if (/[A-Za-z_]/.test(c5)) {
|
|
45461
45994
|
const m = /^[A-Za-z_][A-Za-z0-9_-]*/.exec(src.slice(i));
|
|
45462
45995
|
out.push({ t: "ident", v: m[0], at: i });
|
|
45463
45996
|
i += m[0].length;
|
|
@@ -45469,12 +46002,12 @@ function tokenize(src) {
|
|
|
45469
46002
|
i += 2;
|
|
45470
46003
|
continue;
|
|
45471
46004
|
}
|
|
45472
|
-
if ("!<>.[](),*".includes(
|
|
45473
|
-
out.push({ t: "op", v:
|
|
46005
|
+
if ("!<>.[](),*".includes(c5)) {
|
|
46006
|
+
out.push({ t: "op", v: c5, at: i });
|
|
45474
46007
|
i++;
|
|
45475
46008
|
continue;
|
|
45476
46009
|
}
|
|
45477
|
-
throw new ExpressionError(`unexpected character '${
|
|
46010
|
+
throw new ExpressionError(`unexpected character '${c5}'`, i);
|
|
45478
46011
|
}
|
|
45479
46012
|
out.push({ t: "end", at: src.length });
|
|
45480
46013
|
return out;
|
|
@@ -45741,8 +46274,8 @@ function bounded(s) {
|
|
|
45741
46274
|
function formatString(fmt, args) {
|
|
45742
46275
|
let out = "";
|
|
45743
46276
|
for (let i = 0; i < fmt.length; i++) {
|
|
45744
|
-
const
|
|
45745
|
-
if (
|
|
46277
|
+
const c5 = fmt[i];
|
|
46278
|
+
if (c5 === "{") {
|
|
45746
46279
|
if (fmt[i + 1] === "{") {
|
|
45747
46280
|
out += "{";
|
|
45748
46281
|
i++;
|
|
@@ -45754,11 +46287,11 @@ function formatString(fmt, args) {
|
|
|
45754
46287
|
if (idx >= args.length) throw new ExpressionError(`format(): placeholder {${idx}} has no argument`);
|
|
45755
46288
|
out += toStr(args[idx]);
|
|
45756
46289
|
i += m[0].length - 1;
|
|
45757
|
-
} else if (
|
|
46290
|
+
} else if (c5 === "}") {
|
|
45758
46291
|
if (fmt[i + 1] !== "}") throw new ExpressionError(`format(): unescaped '}' in '${fmt}'`);
|
|
45759
46292
|
out += "}";
|
|
45760
46293
|
i++;
|
|
45761
|
-
} else out +=
|
|
46294
|
+
} else out += c5;
|
|
45762
46295
|
bounded(out);
|
|
45763
46296
|
}
|
|
45764
46297
|
return out;
|
|
@@ -45781,9 +46314,9 @@ function evaluateNode(node2, ctx, opts = {}) {
|
|
|
45781
46314
|
case "lit":
|
|
45782
46315
|
return n.v;
|
|
45783
46316
|
case "ctx": {
|
|
45784
|
-
const
|
|
45785
|
-
if (
|
|
45786
|
-
return
|
|
46317
|
+
const c5 = ctx[n.name];
|
|
46318
|
+
if (c5 === void 0 && n.name === "brnch") return ctx.github ?? null;
|
|
46319
|
+
return c5 ?? null;
|
|
45787
46320
|
}
|
|
45788
46321
|
case "member":
|
|
45789
46322
|
return getProp(ev(n.obj), n.prop);
|
|
@@ -45880,14 +46413,14 @@ function splitTemplate(s) {
|
|
|
45880
46413
|
let inStr = false;
|
|
45881
46414
|
let close = -1;
|
|
45882
46415
|
while (j < s.length) {
|
|
45883
|
-
const
|
|
46416
|
+
const c5 = s[j];
|
|
45884
46417
|
if (inStr) {
|
|
45885
|
-
if (
|
|
46418
|
+
if (c5 === "'") {
|
|
45886
46419
|
if (s[j + 1] === "'") j++;
|
|
45887
46420
|
else inStr = false;
|
|
45888
46421
|
}
|
|
45889
|
-
} else if (
|
|
45890
|
-
else if (
|
|
46422
|
+
} else if (c5 === "'") inStr = true;
|
|
46423
|
+
else if (c5 === "}" && s[j + 1] === "}") {
|
|
45891
46424
|
close = j;
|
|
45892
46425
|
break;
|
|
45893
46426
|
}
|
|
@@ -45960,8 +46493,8 @@ function expandMatrix(spec) {
|
|
|
45960
46493
|
}
|
|
45961
46494
|
base2 = base2.filter((combo) => !spec.exclude.some((ex) => Object.entries(ex).every(([k, v]) => deepEqual(combo[k], v))));
|
|
45962
46495
|
const dimensionKeys = new Set(spec.dimensions.map(([k]) => k));
|
|
45963
|
-
const originals = base2.map((
|
|
45964
|
-
const result = base2.map((
|
|
46496
|
+
const originals = base2.map((c5) => ({ ...c5 }));
|
|
46497
|
+
const result = base2.map((c5) => ({ ...c5 }));
|
|
45965
46498
|
const extra = [];
|
|
45966
46499
|
for (const inc of spec.include) {
|
|
45967
46500
|
let matched = false;
|
|
@@ -45982,24 +46515,24 @@ function expandMatrix(spec) {
|
|
|
45982
46515
|
function patternToRegExp(pattern) {
|
|
45983
46516
|
let re = "^";
|
|
45984
46517
|
for (let i = 0; i < pattern.length; i++) {
|
|
45985
|
-
const
|
|
45986
|
-
if (
|
|
46518
|
+
const c5 = pattern[i];
|
|
46519
|
+
if (c5 === "\\" && i + 1 < pattern.length) {
|
|
45987
46520
|
re += pattern[++i].replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
45988
|
-
} else if (
|
|
46521
|
+
} else if (c5 === "*") {
|
|
45989
46522
|
if (pattern[i + 1] === "*") {
|
|
45990
46523
|
re += ".*";
|
|
45991
46524
|
i++;
|
|
45992
46525
|
} else re += "[^/]*";
|
|
45993
|
-
} else if (
|
|
45994
|
-
re += i === 0 ? `\\${
|
|
45995
|
-
} else if (
|
|
46526
|
+
} else if (c5 === "?" || c5 === "+") {
|
|
46527
|
+
re += i === 0 ? `\\${c5}` : c5;
|
|
46528
|
+
} else if (c5 === "[") {
|
|
45996
46529
|
const end2 = pattern.indexOf("]", i + 1);
|
|
45997
46530
|
if (end2 < 0) re += "\\[";
|
|
45998
46531
|
else {
|
|
45999
46532
|
re += `[${pattern.slice(i + 1, end2).replace(/\\/g, "\\\\")}]`;
|
|
46000
46533
|
i = end2;
|
|
46001
46534
|
}
|
|
46002
|
-
} else re +=
|
|
46535
|
+
} else re += c5.replace(/[.^${}()|\]/]/g, "\\$&");
|
|
46003
46536
|
}
|
|
46004
46537
|
return new RegExp(`${re}$`);
|
|
46005
46538
|
}
|
|
@@ -46055,98 +46588,98 @@ var Ctx = class {
|
|
|
46055
46588
|
function join22(path3, key) {
|
|
46056
46589
|
return path3 ? `${path3}.${key}` : key;
|
|
46057
46590
|
}
|
|
46058
|
-
function entries(
|
|
46591
|
+
function entries(c5, node2, path3, what = "a mapping") {
|
|
46059
46592
|
if (!(0, import_yaml.isMap)(node2)) {
|
|
46060
|
-
|
|
46593
|
+
c5.err(node2, path3, `${path3 || "document"} must be ${what}`);
|
|
46061
46594
|
return null;
|
|
46062
46595
|
}
|
|
46063
46596
|
const out = [];
|
|
46064
46597
|
for (const pair of node2.items) {
|
|
46065
46598
|
const k = pair.key;
|
|
46066
46599
|
if (!(0, import_yaml.isScalar)(k) || typeof k.value === "object") {
|
|
46067
|
-
|
|
46600
|
+
c5.err(k, path3, "keys must be plain strings");
|
|
46068
46601
|
continue;
|
|
46069
46602
|
}
|
|
46070
46603
|
const key = String(k.value);
|
|
46071
46604
|
if (key === "<<") {
|
|
46072
|
-
|
|
46605
|
+
c5.err(k, path3, "YAML merge keys (<<) are not supported");
|
|
46073
46606
|
continue;
|
|
46074
46607
|
}
|
|
46075
46608
|
out.push({ key, keyNode: k, value: pair.value ?? null, path: join22(path3, key) });
|
|
46076
46609
|
}
|
|
46077
46610
|
return out;
|
|
46078
46611
|
}
|
|
46079
|
-
function scalar(
|
|
46612
|
+
function scalar(c5, node2, path3) {
|
|
46080
46613
|
if (node2 === null) return null;
|
|
46081
46614
|
if (!(0, import_yaml.isScalar)(node2)) {
|
|
46082
|
-
|
|
46615
|
+
c5.err(node2, path3, `${path3} must be a single value`);
|
|
46083
46616
|
return void 0;
|
|
46084
46617
|
}
|
|
46085
46618
|
const v = node2.value;
|
|
46086
46619
|
if (v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean") return v;
|
|
46087
|
-
|
|
46620
|
+
c5.err(node2, path3, `${path3} has an unsupported value type`);
|
|
46088
46621
|
return void 0;
|
|
46089
46622
|
}
|
|
46090
|
-
function str4(
|
|
46091
|
-
const v = scalar(
|
|
46623
|
+
function str4(c5, node2, path3, opts = {}) {
|
|
46624
|
+
const v = scalar(c5, node2, path3);
|
|
46092
46625
|
if (v === void 0) return null;
|
|
46093
46626
|
if (v === null || v === "" && !opts.allowEmpty) {
|
|
46094
|
-
|
|
46627
|
+
c5.err(node2, path3, `${path3} must not be empty`);
|
|
46095
46628
|
return null;
|
|
46096
46629
|
}
|
|
46097
46630
|
const s = String(v);
|
|
46098
46631
|
if (s.length > (opts.max ?? 64 * 1024)) {
|
|
46099
|
-
|
|
46632
|
+
c5.err(node2, path3, `${path3} is longer than ${opts.max ?? 64 * 1024} characters`);
|
|
46100
46633
|
return null;
|
|
46101
46634
|
}
|
|
46102
46635
|
return s;
|
|
46103
46636
|
}
|
|
46104
|
-
function bool(
|
|
46105
|
-
const v = scalar(
|
|
46637
|
+
function bool(c5, node2, path3) {
|
|
46638
|
+
const v = scalar(c5, node2, path3);
|
|
46106
46639
|
if (typeof v === "boolean") return v;
|
|
46107
|
-
if (v !== void 0)
|
|
46640
|
+
if (v !== void 0) c5.err(node2, path3, `${path3} must be true or false`);
|
|
46108
46641
|
return null;
|
|
46109
46642
|
}
|
|
46110
|
-
function boolOrExpr(
|
|
46111
|
-
const v = scalar(
|
|
46643
|
+
function boolOrExpr(c5, node2, path3, allowed) {
|
|
46644
|
+
const v = scalar(c5, node2, path3);
|
|
46112
46645
|
if (typeof v === "boolean") return v;
|
|
46113
46646
|
if (typeof v === "string" && hasExpressions(v)) {
|
|
46114
|
-
checkExpressions(
|
|
46647
|
+
checkExpressions(c5, v, node2, path3, allowed);
|
|
46115
46648
|
return v;
|
|
46116
46649
|
}
|
|
46117
|
-
if (v !== void 0)
|
|
46650
|
+
if (v !== void 0) c5.err(node2, path3, `${path3} must be true, false or a \${{ }} expression`);
|
|
46118
46651
|
return false;
|
|
46119
46652
|
}
|
|
46120
|
-
function int2(
|
|
46121
|
-
const v = scalar(
|
|
46653
|
+
function int2(c5, node2, path3, min, max) {
|
|
46654
|
+
const v = scalar(c5, node2, path3);
|
|
46122
46655
|
if (typeof v === "number" && Number.isInteger(v) && v >= min && v <= max) return v;
|
|
46123
|
-
if (v !== void 0)
|
|
46656
|
+
if (v !== void 0) c5.err(node2, path3, `${path3} must be an integer between ${min} and ${max}`);
|
|
46124
46657
|
return null;
|
|
46125
46658
|
}
|
|
46126
|
-
function strList(
|
|
46659
|
+
function strList(c5, node2, path3) {
|
|
46127
46660
|
if ((0, import_yaml.isScalar)(node2)) {
|
|
46128
|
-
const s = str4(
|
|
46661
|
+
const s = str4(c5, node2, path3);
|
|
46129
46662
|
return s === null ? null : [s];
|
|
46130
46663
|
}
|
|
46131
46664
|
if (!(0, import_yaml.isSeq)(node2)) {
|
|
46132
|
-
|
|
46665
|
+
c5.err(node2, path3, `${path3} must be a list of strings`);
|
|
46133
46666
|
return null;
|
|
46134
46667
|
}
|
|
46135
46668
|
const out = [];
|
|
46136
46669
|
node2.items.forEach((item, i) => {
|
|
46137
|
-
const s = str4(
|
|
46670
|
+
const s = str4(c5, item, `${path3}[${i}]`);
|
|
46138
46671
|
if (s !== null) out.push(s);
|
|
46139
46672
|
});
|
|
46140
46673
|
return out;
|
|
46141
46674
|
}
|
|
46142
|
-
function checkExpressions(
|
|
46675
|
+
function checkExpressions(c5, text2, node2, path3, allowed, wholeIsExpression = false) {
|
|
46143
46676
|
const exprs = [];
|
|
46144
46677
|
if (wholeIsExpression) exprs.push({ expr: conditionExpression(text2), offset: 0 });
|
|
46145
46678
|
else {
|
|
46146
46679
|
try {
|
|
46147
46680
|
for (const p of splitTemplate(text2)) if (p.kind === "expr") exprs.push({ expr: p.expr, offset: p.offset });
|
|
46148
46681
|
} catch (e) {
|
|
46149
|
-
|
|
46682
|
+
c5.err(node2, path3, `${path3}: ${e.message}`, locate2(node2, text2, e.offset ?? 0));
|
|
46150
46683
|
return;
|
|
46151
46684
|
}
|
|
46152
46685
|
}
|
|
@@ -46154,11 +46687,11 @@ function checkExpressions(c4, text2, node2, path3, allowed, wholeIsExpression =
|
|
|
46154
46687
|
try {
|
|
46155
46688
|
const refs = references(parseExpression(expr));
|
|
46156
46689
|
for (const ctx of refs.contexts) {
|
|
46157
|
-
if (!allowed.has(ctx))
|
|
46690
|
+
if (!allowed.has(ctx)) c5.err(node2, path3, `${path3}: context "${ctx}" is not available here (available: ${[...allowed].join(", ")})`, locate2(node2, text2, offset));
|
|
46158
46691
|
}
|
|
46159
|
-
if (refs.functions.has("hashfiles") && SERVER_FIELDS.has(allowed))
|
|
46692
|
+
if (refs.functions.has("hashfiles") && SERVER_FIELDS.has(allowed)) c5.err(node2, path3, `${path3}: hashFiles() is only available in steps`, locate2(node2, text2, offset));
|
|
46160
46693
|
} catch (e) {
|
|
46161
|
-
|
|
46694
|
+
c5.err(node2, path3, `${path3}: invalid expression: ${e.message}`, locate2(node2, text2, offset));
|
|
46162
46695
|
}
|
|
46163
46696
|
}
|
|
46164
46697
|
}
|
|
@@ -46169,90 +46702,90 @@ function locate2(node2, text2, valueOffset) {
|
|
|
46169
46702
|
const quoted = node2.type === "QUOTE_DOUBLE" || node2.type === "QUOTE_SINGLE" ? 1 : 0;
|
|
46170
46703
|
return node2.type === "BLOCK_LITERAL" || node2.type === "BLOCK_FOLDED" ? 0 : valueOffset + quoted;
|
|
46171
46704
|
}
|
|
46172
|
-
function envMap(
|
|
46705
|
+
function envMap(c5, node2, path3, allowed) {
|
|
46173
46706
|
const out = {};
|
|
46174
|
-
const es = entries(
|
|
46707
|
+
const es = entries(c5, node2, path3);
|
|
46175
46708
|
if (!es) return out;
|
|
46176
|
-
if (es.length > LIMITS.maxEnvEntries)
|
|
46709
|
+
if (es.length > LIMITS.maxEnvEntries) c5.err(node2, path3, `${path3} has more than ${LIMITS.maxEnvEntries} entries`);
|
|
46177
46710
|
for (const e of es) {
|
|
46178
46711
|
if (!ENV_NAME_RE.test(e.key)) {
|
|
46179
|
-
|
|
46712
|
+
c5.err(e.keyNode, e.path, `invalid environment variable name "${e.key}"`);
|
|
46180
46713
|
continue;
|
|
46181
46714
|
}
|
|
46182
|
-
const v = scalar(
|
|
46715
|
+
const v = scalar(c5, e.value, e.path);
|
|
46183
46716
|
if (v === void 0) continue;
|
|
46184
46717
|
const s = v === null ? "" : String(v);
|
|
46185
|
-
checkExpressions(
|
|
46718
|
+
checkExpressions(c5, s, e.value, e.path, allowed);
|
|
46186
46719
|
out[e.key] = s;
|
|
46187
46720
|
}
|
|
46188
46721
|
return out;
|
|
46189
46722
|
}
|
|
46190
|
-
function defaults(
|
|
46723
|
+
function defaults(c5, node2, path3) {
|
|
46191
46724
|
const d = { shell: null, working_directory: null };
|
|
46192
|
-
for (const e of entries(
|
|
46725
|
+
for (const e of entries(c5, node2, path3) ?? []) {
|
|
46193
46726
|
if (e.key !== "run") {
|
|
46194
|
-
|
|
46727
|
+
c5.err(e.keyNode, e.path, `unsupported key "${e.key}" in defaults (only defaults.run is supported)`);
|
|
46195
46728
|
continue;
|
|
46196
46729
|
}
|
|
46197
|
-
for (const r of entries(
|
|
46198
|
-
if (r.key === "shell") d.shell = shell(
|
|
46199
|
-
else if (r.key === "working-directory") d.working_directory = str4(
|
|
46200
|
-
else
|
|
46730
|
+
for (const r of entries(c5, e.value, e.path) ?? []) {
|
|
46731
|
+
if (r.key === "shell") d.shell = shell(c5, r.value, r.path);
|
|
46732
|
+
else if (r.key === "working-directory") d.working_directory = str4(c5, r.value, r.path, { max: 1024 });
|
|
46733
|
+
else c5.err(r.keyNode, r.path, `unsupported key "${r.key}" in defaults.run (supported: shell, working-directory)`);
|
|
46201
46734
|
}
|
|
46202
46735
|
}
|
|
46203
46736
|
return d;
|
|
46204
46737
|
}
|
|
46205
|
-
function shell(
|
|
46206
|
-
const s = str4(
|
|
46738
|
+
function shell(c5, node2, path3) {
|
|
46739
|
+
const s = str4(c5, node2, path3);
|
|
46207
46740
|
if (s === "bash" || s === "sh") return s;
|
|
46208
|
-
if (s !== null)
|
|
46741
|
+
if (s !== null) c5.err(node2, path3, `shell "${s}" is not supported (supported: bash, sh)`);
|
|
46209
46742
|
return null;
|
|
46210
46743
|
}
|
|
46211
|
-
function filterPair(
|
|
46744
|
+
function filterPair(c5, cfg, include, exclude) {
|
|
46212
46745
|
const inc = cfg.get(include);
|
|
46213
46746
|
const exc = cfg.get(exclude);
|
|
46214
|
-
if (inc && exc)
|
|
46215
|
-
return [inc ? strList(
|
|
46747
|
+
if (inc && exc) c5.err(exc.keyNode, exc.path, `${include} and ${exclude} cannot be used together`);
|
|
46748
|
+
return [inc ? strList(c5, inc.value, inc.path) : null, exc ? strList(c5, exc.value, exc.path) : null];
|
|
46216
46749
|
}
|
|
46217
|
-
function triggers(
|
|
46750
|
+
function triggers(c5, node2) {
|
|
46218
46751
|
const t = { push: null, change: null, workflow_dispatch: null, schedule: [] };
|
|
46219
46752
|
let events = [];
|
|
46220
46753
|
if ((0, import_yaml.isScalar)(node2) || (0, import_yaml.isSeq)(node2)) {
|
|
46221
|
-
const names = strList(
|
|
46754
|
+
const names = strList(c5, node2, "on") ?? [];
|
|
46222
46755
|
events = names.map((n) => ({ key: n, keyNode: node2, value: null, path: `on.${n}` }));
|
|
46223
|
-
} else events = entries(
|
|
46224
|
-
if (!events.length)
|
|
46756
|
+
} else events = entries(c5, node2, "on", "an event name, a list of event names, or a mapping") ?? [];
|
|
46757
|
+
if (!events.length) c5.err(node2, "on", "on must declare at least one event");
|
|
46225
46758
|
for (const ev of events) {
|
|
46226
|
-
const cfgEntries = ev.value === null || ev.key === "schedule" ? [] : entries(
|
|
46759
|
+
const cfgEntries = ev.value === null || ev.key === "schedule" ? [] : entries(c5, ev.value, ev.path) ?? [];
|
|
46227
46760
|
const cfg = new Map(cfgEntries.map((e) => [e.key, e]));
|
|
46228
46761
|
const allowOnly = (keys) => {
|
|
46229
|
-
for (const e of cfgEntries) if (!keys.includes(e.key))
|
|
46762
|
+
for (const e of cfgEntries) if (!keys.includes(e.key)) c5.err(e.keyNode, e.path, `unsupported key "${e.key}" in on.${ev.key} (supported: ${keys.join(", ") || "none"})`);
|
|
46230
46763
|
};
|
|
46231
46764
|
switch (ev.key) {
|
|
46232
46765
|
case "push": {
|
|
46233
46766
|
allowOnly(["branches", "branches-ignore", "tags", "tags-ignore", "paths", "paths-ignore"]);
|
|
46234
|
-
const [branches, branches_ignore] = filterPair(
|
|
46235
|
-
const [tags, tags_ignore] = filterPair(
|
|
46236
|
-
const [paths, paths_ignore] = filterPair(
|
|
46767
|
+
const [branches, branches_ignore] = filterPair(c5, cfg, "branches", "branches-ignore");
|
|
46768
|
+
const [tags, tags_ignore] = filterPair(c5, cfg, "tags", "tags-ignore");
|
|
46769
|
+
const [paths, paths_ignore] = filterPair(c5, cfg, "paths", "paths-ignore");
|
|
46237
46770
|
t.push = { branches, branches_ignore, tags, tags_ignore, paths, paths_ignore };
|
|
46238
46771
|
break;
|
|
46239
46772
|
}
|
|
46240
46773
|
case "change":
|
|
46241
46774
|
case "pull_request": {
|
|
46242
|
-
if (t.change)
|
|
46775
|
+
if (t.change) c5.err(ev.keyNode, ev.path, "declare either on.change or on.pull_request, not both");
|
|
46243
46776
|
allowOnly(["types", "branches", "branches-ignore", "paths", "paths-ignore"]);
|
|
46244
46777
|
let types = ["opened", "revised", "reopened"];
|
|
46245
46778
|
const ty = cfg.get("types");
|
|
46246
46779
|
if (ty) {
|
|
46247
46780
|
types = [];
|
|
46248
|
-
for (const [i, raw] of (strList(
|
|
46781
|
+
for (const [i, raw] of (strList(c5, ty.value, ty.path) ?? []).entries()) {
|
|
46249
46782
|
const v = raw === "synchronize" ? "revised" : raw;
|
|
46250
46783
|
if (v === "opened" || v === "revised" || v === "reopened") types.push(v);
|
|
46251
|
-
else
|
|
46784
|
+
else c5.err((0, import_yaml.isSeq)(ty.value) ? ty.value.items[i] : ty.value, `${ty.path}[${i}]`, `unsupported ${ev.key} type "${raw}" (supported: opened, revised (alias synchronize), reopened)`);
|
|
46252
46785
|
}
|
|
46253
46786
|
}
|
|
46254
|
-
const [branches, branches_ignore] = filterPair(
|
|
46255
|
-
const [paths, paths_ignore] = filterPair(
|
|
46787
|
+
const [branches, branches_ignore] = filterPair(c5, cfg, "branches", "branches-ignore");
|
|
46788
|
+
const [paths, paths_ignore] = filterPair(c5, cfg, "paths", "paths-ignore");
|
|
46256
46789
|
t.change = { key: ev.key, types, branches, branches_ignore, paths, paths_ignore };
|
|
46257
46790
|
break;
|
|
46258
46791
|
}
|
|
@@ -46260,28 +46793,28 @@ function triggers(c4, node2) {
|
|
|
46260
46793
|
allowOnly(["inputs"]);
|
|
46261
46794
|
const inputs = {};
|
|
46262
46795
|
const inEntry = cfg.get("inputs");
|
|
46263
|
-
const ins = inEntry ? entries(
|
|
46264
|
-
if (ins.length > LIMITS.maxDispatchInputs)
|
|
46796
|
+
const ins = inEntry ? entries(c5, inEntry.value, inEntry.path) ?? [] : [];
|
|
46797
|
+
if (ins.length > LIMITS.maxDispatchInputs) c5.err(inEntry.value, inEntry.path, `at most ${LIMITS.maxDispatchInputs} inputs are supported`);
|
|
46265
46798
|
for (const inp of ins) {
|
|
46266
|
-
if (!ID_RE.test(inp.key))
|
|
46799
|
+
if (!ID_RE.test(inp.key)) c5.err(inp.keyNode, inp.path, `invalid input name "${inp.key}"`);
|
|
46267
46800
|
const d = { type: "string", description: "", required: false, default: null, options: [] };
|
|
46268
|
-
for (const f of inp.value === null ? [] : entries(
|
|
46269
|
-
if (f.key === "description") d.description = str4(
|
|
46270
|
-
else if (f.key === "required") d.required = bool(
|
|
46801
|
+
for (const f of inp.value === null ? [] : entries(c5, inp.value, inp.path) ?? []) {
|
|
46802
|
+
if (f.key === "description") d.description = str4(c5, f.value, f.path, { allowEmpty: true, max: 1e3 }) ?? "";
|
|
46803
|
+
else if (f.key === "required") d.required = bool(c5, f.value, f.path) ?? false;
|
|
46271
46804
|
else if (f.key === "type") {
|
|
46272
|
-
const ty2 = str4(
|
|
46805
|
+
const ty2 = str4(c5, f.value, f.path);
|
|
46273
46806
|
if (ty2 === "string" || ty2 === "boolean" || ty2 === "choice") d.type = ty2;
|
|
46274
|
-
else if (ty2 !== null)
|
|
46807
|
+
else if (ty2 !== null) c5.err(f.value, f.path, `unsupported input type "${ty2}" (supported: string, boolean, choice)`);
|
|
46275
46808
|
} else if (f.key === "default") {
|
|
46276
|
-
const v = scalar(
|
|
46809
|
+
const v = scalar(c5, f.value, f.path);
|
|
46277
46810
|
if (v !== void 0) d.default = typeof v === "boolean" ? v : v === null ? null : String(v);
|
|
46278
|
-
} else if (f.key === "options") d.options = strList(
|
|
46279
|
-
else
|
|
46811
|
+
} else if (f.key === "options") d.options = strList(c5, f.value, f.path) ?? [];
|
|
46812
|
+
else c5.err(f.keyNode, f.path, `unsupported key "${f.key}" in workflow_dispatch input (supported: description, required, type, default, options)`);
|
|
46280
46813
|
}
|
|
46281
|
-
if (d.type === "choice" && d.options.length === 0)
|
|
46282
|
-
if (d.type !== "choice" && d.options.length)
|
|
46283
|
-
if (d.type === "boolean" && d.default !== null && typeof d.default !== "boolean")
|
|
46284
|
-
if (d.type === "choice" && d.default !== null && !d.options.includes(String(d.default)))
|
|
46814
|
+
if (d.type === "choice" && d.options.length === 0) c5.err(inp.value, inp.path, `choice input "${inp.key}" needs options`);
|
|
46815
|
+
if (d.type !== "choice" && d.options.length) c5.err(inp.value, inp.path, `options are only valid for choice inputs`);
|
|
46816
|
+
if (d.type === "boolean" && d.default !== null && typeof d.default !== "boolean") c5.err(inp.value, inp.path, `default of boolean input "${inp.key}" must be true or false`);
|
|
46817
|
+
if (d.type === "choice" && d.default !== null && !d.options.includes(String(d.default))) c5.err(inp.value, inp.path, `default of choice input "${inp.key}" must be one of its options`);
|
|
46285
46818
|
inputs[inp.key] = d;
|
|
46286
46819
|
}
|
|
46287
46820
|
t.workflow_dispatch = { inputs };
|
|
@@ -46289,136 +46822,136 @@ function triggers(c4, node2) {
|
|
|
46289
46822
|
}
|
|
46290
46823
|
case "schedule": {
|
|
46291
46824
|
if (!(0, import_yaml.isSeq)(ev.value)) {
|
|
46292
|
-
|
|
46825
|
+
c5.err(ev.value ?? ev.keyNode, ev.path, "on.schedule must be a list of { cron: '\u2026' } entries");
|
|
46293
46826
|
break;
|
|
46294
46827
|
}
|
|
46295
|
-
if (ev.value.items.length > LIMITS.maxSchedules)
|
|
46828
|
+
if (ev.value.items.length > LIMITS.maxSchedules) c5.err(ev.value, ev.path, `at most ${LIMITS.maxSchedules} schedules are supported`);
|
|
46296
46829
|
ev.value.items.forEach((item, i) => {
|
|
46297
46830
|
const p = `${ev.path}[${i}]`;
|
|
46298
|
-
const es = entries(
|
|
46831
|
+
const es = entries(c5, item, p) ?? [];
|
|
46299
46832
|
const cron = es.find((e) => e.key === "cron");
|
|
46300
|
-
for (const e of es) if (e.key !== "cron")
|
|
46833
|
+
for (const e of es) if (e.key !== "cron") c5.err(e.keyNode, e.path, `unsupported key "${e.key}" in schedule (only cron)`);
|
|
46301
46834
|
if (!cron) {
|
|
46302
|
-
|
|
46835
|
+
c5.err(item, p, "schedule entry needs a cron expression");
|
|
46303
46836
|
return;
|
|
46304
46837
|
}
|
|
46305
|
-
const expr = str4(
|
|
46838
|
+
const expr = str4(c5, cron.value, cron.path);
|
|
46306
46839
|
if (expr === null) return;
|
|
46307
46840
|
try {
|
|
46308
46841
|
validateCron(expr);
|
|
46309
46842
|
t.schedule.push(expr);
|
|
46310
46843
|
} catch (e) {
|
|
46311
|
-
|
|
46844
|
+
c5.err(cron.value, cron.path, e instanceof CronError ? e.message : String(e));
|
|
46312
46845
|
}
|
|
46313
46846
|
});
|
|
46314
46847
|
break;
|
|
46315
46848
|
}
|
|
46316
46849
|
default:
|
|
46317
|
-
|
|
46850
|
+
c5.err(ev.keyNode, ev.path, UNSUPPORTED_TRIGGERS[ev.key] ?? `unsupported trigger "${ev.key}" (supported: push, change, pull_request, workflow_dispatch, schedule)`);
|
|
46318
46851
|
}
|
|
46319
46852
|
}
|
|
46320
46853
|
return t;
|
|
46321
46854
|
}
|
|
46322
|
-
function runsOn(
|
|
46855
|
+
function runsOn(c5, node2, path3) {
|
|
46323
46856
|
if (node2 === null) {
|
|
46324
|
-
|
|
46857
|
+
c5.err(node2, path3, `${path3} is required`);
|
|
46325
46858
|
return null;
|
|
46326
46859
|
}
|
|
46327
46860
|
if ((0, import_yaml.isMap)(node2)) {
|
|
46328
46861
|
let group = null;
|
|
46329
46862
|
let labelsNode = null;
|
|
46330
|
-
for (const e of entries(
|
|
46863
|
+
for (const e of entries(c5, node2, path3) ?? []) {
|
|
46331
46864
|
if (e.key === "group") {
|
|
46332
|
-
group = str4(
|
|
46333
|
-
if (group !== null && !LABEL_RE.test(group))
|
|
46865
|
+
group = str4(c5, e.value, e.path, { max: 64 })?.toLowerCase() ?? null;
|
|
46866
|
+
if (group !== null && !LABEL_RE.test(group)) c5.err(e.value, e.path, `invalid runner group "${group}"`);
|
|
46334
46867
|
} else if (e.key === "labels") labelsNode = e.value;
|
|
46335
|
-
else
|
|
46868
|
+
else c5.err(e.keyNode, e.path, `unsupported key "${e.key}" in runs-on (supported: group, labels)`);
|
|
46336
46869
|
}
|
|
46337
|
-
const ls = labelsNode ? strList(
|
|
46338
|
-
if (!group && !ls.length)
|
|
46870
|
+
const ls = labelsNode ? strList(c5, labelsNode, `${path3}.labels`) ?? [] : [];
|
|
46871
|
+
if (!group && !ls.length) c5.err(node2, path3, `${path3} needs a group or labels`);
|
|
46339
46872
|
const rest = [...new Set(ls.filter((l) => l !== "self-hosted").map((l) => l.toLowerCase()))];
|
|
46340
|
-
for (const l of rest) if (!LABEL_RE.test(l))
|
|
46341
|
-
if (rest.length > LIMITS.maxLabels)
|
|
46873
|
+
for (const l of rest) if (!LABEL_RE.test(l)) c5.err(labelsNode, `${path3}.labels`, `invalid runner label "${l}"`);
|
|
46874
|
+
if (rest.length > LIMITS.maxLabels) c5.err(labelsNode, `${path3}.labels`, `at most ${LIMITS.maxLabels} labels are supported`);
|
|
46342
46875
|
return { kind: "self_hosted", labels: rest, group };
|
|
46343
46876
|
}
|
|
46344
|
-
const labels = strList(
|
|
46877
|
+
const labels = strList(c5, node2, path3);
|
|
46345
46878
|
if (!labels || !labels.length) return null;
|
|
46346
46879
|
if (labels.some((l) => hasExpressions(l))) {
|
|
46347
|
-
|
|
46880
|
+
c5.err(node2, path3, `${path3} must be literal labels; expressions are not supported`);
|
|
46348
46881
|
return null;
|
|
46349
46882
|
}
|
|
46350
46883
|
if (labels.includes("self-hosted")) {
|
|
46351
46884
|
const rest = [...new Set(labels.filter((l) => l !== "self-hosted").map((l) => l.toLowerCase()))];
|
|
46352
|
-
if (rest.length > LIMITS.maxLabels)
|
|
46353
|
-
for (const l of rest) if (!LABEL_RE.test(l))
|
|
46885
|
+
if (rest.length > LIMITS.maxLabels) c5.err(node2, path3, `at most ${LIMITS.maxLabels} labels are supported`);
|
|
46886
|
+
for (const l of rest) if (!LABEL_RE.test(l)) c5.err(node2, path3, `invalid runner label "${l}"`);
|
|
46354
46887
|
return { kind: "self_hosted", labels: rest, group: null };
|
|
46355
46888
|
}
|
|
46356
46889
|
if (labels.length === 1 && (labels[0] === "ubuntu-latest" || labels[0] === "brnch-hosted")) return { kind: "hosted", label: labels[0] };
|
|
46357
|
-
|
|
46890
|
+
c5.err(node2, path3, `runs-on ${JSON.stringify(labels.length === 1 ? labels[0] : labels)} is not available: use ubuntu-latest / brnch-hosted (hosted runner) or [self-hosted, <labels>]`);
|
|
46358
46891
|
return null;
|
|
46359
46892
|
}
|
|
46360
|
-
function literal2(
|
|
46893
|
+
function literal2(c5, node2, path3, depth = 0) {
|
|
46361
46894
|
if (depth > 16) {
|
|
46362
|
-
|
|
46895
|
+
c5.err(node2, path3, `${path3} is nested too deeply`);
|
|
46363
46896
|
return null;
|
|
46364
46897
|
}
|
|
46365
46898
|
if ((0, import_yaml.isAlias)(node2)) {
|
|
46366
|
-
|
|
46899
|
+
c5.err(node2, path3, "YAML aliases are not supported");
|
|
46367
46900
|
return null;
|
|
46368
46901
|
}
|
|
46369
46902
|
if ((0, import_yaml.isScalar)(node2)) {
|
|
46370
46903
|
const v = node2.value;
|
|
46371
46904
|
if (typeof v === "string" && hasExpressions(v)) {
|
|
46372
|
-
|
|
46905
|
+
c5.err(node2, path3, `${path3}: matrix values must be literals; expressions are not supported`);
|
|
46373
46906
|
return null;
|
|
46374
46907
|
}
|
|
46375
46908
|
return v;
|
|
46376
46909
|
}
|
|
46377
|
-
if ((0, import_yaml.isSeq)(node2)) return node2.items.map((x, i) => literal2(
|
|
46910
|
+
if ((0, import_yaml.isSeq)(node2)) return node2.items.map((x, i) => literal2(c5, x, `${path3}[${i}]`, depth + 1));
|
|
46378
46911
|
if ((0, import_yaml.isMap)(node2)) {
|
|
46379
46912
|
const o = {};
|
|
46380
|
-
for (const e of entries(
|
|
46913
|
+
for (const e of entries(c5, node2, path3) ?? []) o[e.key] = literal2(c5, e.value, e.path, depth + 1);
|
|
46381
46914
|
return o;
|
|
46382
46915
|
}
|
|
46383
46916
|
return null;
|
|
46384
46917
|
}
|
|
46385
|
-
function matrix(
|
|
46918
|
+
function matrix(c5, node2, path3) {
|
|
46386
46919
|
if ((0, import_yaml.isScalar)(node2) && typeof node2.value === "string" && hasExpressions(node2.value)) {
|
|
46387
|
-
|
|
46920
|
+
c5.err(node2, path3, `${path3}: a matrix computed from an expression is not supported; list the values`);
|
|
46388
46921
|
return null;
|
|
46389
46922
|
}
|
|
46390
|
-
const es = entries(
|
|
46923
|
+
const es = entries(c5, node2, path3);
|
|
46391
46924
|
if (!es) return null;
|
|
46392
46925
|
const spec = { dimensions: [], include: [], exclude: [] };
|
|
46393
46926
|
for (const e of es) {
|
|
46394
46927
|
if (e.key === "include" || e.key === "exclude") {
|
|
46395
46928
|
if (!(0, import_yaml.isSeq)(e.value)) {
|
|
46396
|
-
|
|
46929
|
+
c5.err(e.value ?? e.keyNode, e.path, `${e.path} must be a list of mappings`);
|
|
46397
46930
|
continue;
|
|
46398
46931
|
}
|
|
46399
46932
|
e.value.items.forEach((item, i) => {
|
|
46400
46933
|
if (!(0, import_yaml.isMap)(item)) {
|
|
46401
|
-
|
|
46934
|
+
c5.err(item, `${e.path}[${i}]`, `${e.path}[${i}] must be a mapping`);
|
|
46402
46935
|
return;
|
|
46403
46936
|
}
|
|
46404
|
-
spec[e.key].push(literal2(
|
|
46937
|
+
spec[e.key].push(literal2(c5, item, `${e.path}[${i}]`));
|
|
46405
46938
|
});
|
|
46406
46939
|
continue;
|
|
46407
46940
|
}
|
|
46408
|
-
if (!ID_RE.test(e.key))
|
|
46941
|
+
if (!ID_RE.test(e.key)) c5.err(e.keyNode, e.path, `invalid matrix key "${e.key}"`);
|
|
46409
46942
|
if (!(0, import_yaml.isSeq)(e.value) || e.value.items.length === 0) {
|
|
46410
|
-
|
|
46943
|
+
c5.err(e.value ?? e.keyNode, e.path, `${e.path} must be a non-empty list of values`);
|
|
46411
46944
|
continue;
|
|
46412
46945
|
}
|
|
46413
|
-
spec.dimensions.push([e.key, literal2(
|
|
46946
|
+
spec.dimensions.push([e.key, literal2(c5, e.value, e.path)]);
|
|
46414
46947
|
}
|
|
46415
46948
|
if (productSize(spec) > MAX_MATRIX_PRODUCT) {
|
|
46416
|
-
|
|
46949
|
+
c5.err(node2, path3, `${path3} has ${productSize(spec)} combinations before include/exclude (limit ${LIMITS.maxMatrixCombinations})`);
|
|
46417
46950
|
return null;
|
|
46418
46951
|
}
|
|
46419
46952
|
const combos = expandMatrix(spec);
|
|
46420
|
-
if (combos.length === 0)
|
|
46421
|
-
if (combos.length > LIMITS.maxMatrixCombinations)
|
|
46953
|
+
if (combos.length === 0) c5.err(node2, path3, `${path3} produces no combinations`);
|
|
46954
|
+
if (combos.length > LIMITS.maxMatrixCombinations) c5.err(node2, path3, `${path3} produces ${combos.length} combinations (limit ${LIMITS.maxMatrixCombinations})`);
|
|
46422
46955
|
return spec;
|
|
46423
46956
|
}
|
|
46424
46957
|
var ACTION_INPUTS = {
|
|
@@ -46430,17 +46963,17 @@ var ACTION_INPUTS = {
|
|
|
46430
46963
|
var CONNECTION_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9 ._-]{0,99}$/;
|
|
46431
46964
|
var INFISICAL_ENV_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
46432
46965
|
var INFISICAL_PATH_RE = /^\/[A-Za-z0-9_./-]{0,499}$/;
|
|
46433
|
-
function infisicalInputs(
|
|
46434
|
-
for (const [k, v] of Object.entries(w)) if (hasExpressions(v))
|
|
46435
|
-
if (!w.connection)
|
|
46436
|
-
else if (!CONNECTION_NAME_RE.test(w.connection))
|
|
46437
|
-
if (!w.environment)
|
|
46438
|
-
else if (!INFISICAL_ENV_RE.test(w.environment))
|
|
46439
|
-
if (w.path !== void 0 && (!INFISICAL_PATH_RE.test(w.path) || w.path.includes("..")))
|
|
46440
|
-
if (w.recursive !== void 0 && w.recursive !== "true" && w.recursive !== "false")
|
|
46441
|
-
}
|
|
46442
|
-
function step(
|
|
46443
|
-
const es = entries(
|
|
46966
|
+
function infisicalInputs(c5, node2, path3, w) {
|
|
46967
|
+
for (const [k, v] of Object.entries(w)) if (hasExpressions(v)) c5.err(node2, `${path3}.with.${k}`, `brnch/infisical@v1 inputs must be literal values (they are resolved when the job starts): ${k}`);
|
|
46968
|
+
if (!w.connection) c5.err(node2, path3, "brnch/infisical@v1 requires with.connection (the name of an Infisical connection in the organization's integrations)");
|
|
46969
|
+
else if (!CONNECTION_NAME_RE.test(w.connection)) c5.err(node2, `${path3}.with.connection`, `invalid connection name "${w.connection}"`);
|
|
46970
|
+
if (!w.environment) c5.err(node2, path3, "brnch/infisical@v1 requires with.environment (an Infisical environment slug, e.g. prod)");
|
|
46971
|
+
else if (!INFISICAL_ENV_RE.test(w.environment)) c5.err(node2, `${path3}.with.environment`, `invalid environment slug "${w.environment}"`);
|
|
46972
|
+
if (w.path !== void 0 && (!INFISICAL_PATH_RE.test(w.path) || w.path.includes(".."))) c5.err(node2, `${path3}.with.path`, "with.path must be an absolute secret path such as / or /api");
|
|
46973
|
+
if (w.recursive !== void 0 && w.recursive !== "true" && w.recursive !== "false") c5.err(node2, `${path3}.with.recursive`, "with.recursive must be true or false");
|
|
46974
|
+
}
|
|
46975
|
+
function step(c5, node2, path3, index) {
|
|
46976
|
+
const es = entries(c5, node2, path3);
|
|
46444
46977
|
if (!es) return null;
|
|
46445
46978
|
const s = { index, id: null, name: null, run: null, uses: null, with: {}, shell: null, working_directory: null, env: {}, if: null, continue_on_error: false, timeout_minutes: null };
|
|
46446
46979
|
let withEntry = null;
|
|
@@ -46448,29 +46981,29 @@ function step(c4, node2, path3, index) {
|
|
|
46448
46981
|
for (const e of es) {
|
|
46449
46982
|
switch (e.key) {
|
|
46450
46983
|
case "id": {
|
|
46451
|
-
const v = str4(
|
|
46452
|
-
if (v !== null && !ID_RE.test(v))
|
|
46984
|
+
const v = str4(c5, e.value, e.path);
|
|
46985
|
+
if (v !== null && !ID_RE.test(v)) c5.err(e.value, e.path, `invalid step id "${v}" (letters, digits, _ and -; must not start with a digit)`);
|
|
46453
46986
|
s.id = v;
|
|
46454
46987
|
break;
|
|
46455
46988
|
}
|
|
46456
46989
|
case "name":
|
|
46457
|
-
s.name = str4(
|
|
46458
|
-
if (s.name) checkExpressions(
|
|
46990
|
+
s.name = str4(c5, e.value, e.path, { max: 500 });
|
|
46991
|
+
if (s.name) checkExpressions(c5, s.name, e.value, e.path, CTX.runner);
|
|
46459
46992
|
break;
|
|
46460
46993
|
case "run":
|
|
46461
|
-
s.run = str4(
|
|
46462
|
-
if (s.run) checkExpressions(
|
|
46994
|
+
s.run = str4(c5, e.value, e.path);
|
|
46995
|
+
if (s.run) checkExpressions(c5, s.run, e.value, e.path, CTX.runner);
|
|
46463
46996
|
break;
|
|
46464
46997
|
case "uses": {
|
|
46465
46998
|
usesNode = e.value;
|
|
46466
|
-
const v = str4(
|
|
46999
|
+
const v = str4(c5, e.value, e.path);
|
|
46467
47000
|
if (v === null) break;
|
|
46468
47001
|
if (BUILTIN_ACTIONS.includes(v)) s.uses = v;
|
|
46469
|
-
else if (v.startsWith("./") || v.startsWith("docker://"))
|
|
47002
|
+
else if (v.startsWith("./") || v.startsWith("docker://")) c5.err(e.value, e.path, `${v.startsWith("./") ? "local/composite" : "Docker"} actions are not supported (built-in actions: ${BUILTIN_ACTIONS.join(", ")})`);
|
|
46470
47003
|
else {
|
|
46471
47004
|
const base2 = v.split("@")[0];
|
|
46472
47005
|
const builtin = BUILTIN_ACTIONS.find((a) => a.startsWith(`${base2}@`));
|
|
46473
|
-
|
|
47006
|
+
c5.err(e.value, e.path, builtin ? `unsupported version "${v}": only ${builtin} is available` : `unsupported action "${v}": only the built-in actions ${BUILTIN_ACTIONS.join(", ")} are available`);
|
|
46474
47007
|
}
|
|
46475
47008
|
break;
|
|
46476
47009
|
}
|
|
@@ -46478,59 +47011,59 @@ function step(c4, node2, path3, index) {
|
|
|
46478
47011
|
withEntry = e;
|
|
46479
47012
|
break;
|
|
46480
47013
|
case "shell":
|
|
46481
|
-
s.shell = shell(
|
|
47014
|
+
s.shell = shell(c5, e.value, e.path);
|
|
46482
47015
|
break;
|
|
46483
47016
|
case "working-directory":
|
|
46484
|
-
s.working_directory = str4(
|
|
46485
|
-
if (s.working_directory) checkExpressions(
|
|
47017
|
+
s.working_directory = str4(c5, e.value, e.path, { max: 1024 });
|
|
47018
|
+
if (s.working_directory) checkExpressions(c5, s.working_directory, e.value, e.path, CTX.runner);
|
|
46486
47019
|
break;
|
|
46487
47020
|
case "env":
|
|
46488
|
-
s.env = envMap(
|
|
47021
|
+
s.env = envMap(c5, e.value, e.path, CTX.runner);
|
|
46489
47022
|
break;
|
|
46490
47023
|
case "if": {
|
|
46491
|
-
const v = scalar(
|
|
47024
|
+
const v = scalar(c5, e.value, e.path);
|
|
46492
47025
|
if (typeof v === "boolean") s.if = v ? "true" : "false";
|
|
46493
47026
|
else if (typeof v === "string" && v.trim()) {
|
|
46494
47027
|
s.if = v;
|
|
46495
|
-
checkExpressions(
|
|
46496
|
-
} else if (v !== void 0)
|
|
47028
|
+
checkExpressions(c5, v, e.value, e.path, CTX.runner, true);
|
|
47029
|
+
} else if (v !== void 0) c5.err(e.value, e.path, `${e.path} must be an expression`);
|
|
46497
47030
|
break;
|
|
46498
47031
|
}
|
|
46499
47032
|
case "continue-on-error":
|
|
46500
|
-
s.continue_on_error = boolOrExpr(
|
|
47033
|
+
s.continue_on_error = boolOrExpr(c5, e.value, e.path, CTX.runner);
|
|
46501
47034
|
break;
|
|
46502
47035
|
case "timeout-minutes":
|
|
46503
|
-
s.timeout_minutes = int2(
|
|
47036
|
+
s.timeout_minutes = int2(c5, e.value, e.path, 1, LIMITS.maxTimeoutMinutes);
|
|
46504
47037
|
break;
|
|
46505
47038
|
default:
|
|
46506
|
-
|
|
47039
|
+
c5.err(e.keyNode, e.path, `unsupported step key "${e.key}" (supported: name, id, run, uses, with, shell, working-directory, env, if, continue-on-error, timeout-minutes)`);
|
|
46507
47040
|
}
|
|
46508
47041
|
}
|
|
46509
|
-
if (s.run === null && s.uses === null && !usesNode)
|
|
46510
|
-
if (s.run !== null && usesNode)
|
|
47042
|
+
if (s.run === null && s.uses === null && !usesNode) c5.err(node2, path3, "a step needs either run or uses");
|
|
47043
|
+
if (s.run !== null && usesNode) c5.err(node2, path3, "a step cannot have both run and uses");
|
|
46511
47044
|
if (withEntry) {
|
|
46512
|
-
if (!usesNode)
|
|
46513
|
-
for (const w of entries(
|
|
46514
|
-
const v = scalar(
|
|
47045
|
+
if (!usesNode) c5.err(withEntry.keyNode, withEntry.path, "with is only valid together with uses");
|
|
47046
|
+
for (const w of entries(c5, withEntry.value, withEntry.path) ?? []) {
|
|
47047
|
+
const v = scalar(c5, w.value, w.path);
|
|
46515
47048
|
if (v === void 0) continue;
|
|
46516
47049
|
if (s.uses && !ACTION_INPUTS[s.uses].includes(w.key)) {
|
|
46517
|
-
|
|
47050
|
+
c5.err(w.keyNode, w.path, `${s.uses} does not support input "${w.key}" (supported: ${ACTION_INPUTS[s.uses].join(", ")})`);
|
|
46518
47051
|
continue;
|
|
46519
47052
|
}
|
|
46520
47053
|
const sv = v === null ? "" : String(v);
|
|
46521
|
-
checkExpressions(
|
|
47054
|
+
checkExpressions(c5, sv, w.value, w.path, CTX.runner);
|
|
46522
47055
|
s.with[w.key] = sv;
|
|
46523
47056
|
}
|
|
46524
47057
|
}
|
|
46525
|
-
if (s.uses === "actions/upload-artifact@v4" && !s.with.path)
|
|
46526
|
-
if (s.uses === "actions/setup-node@v4" && !s.with["node-version"])
|
|
46527
|
-
if (s.uses && (s.shell || s.working_directory))
|
|
46528
|
-
if (s.uses === "brnch/infisical@v1") infisicalInputs(
|
|
47058
|
+
if (s.uses === "actions/upload-artifact@v4" && !s.with.path) c5.err(node2, path3, "actions/upload-artifact@v4 requires with.path");
|
|
47059
|
+
if (s.uses === "actions/setup-node@v4" && !s.with["node-version"]) c5.err(node2, path3, "actions/setup-node@v4 requires with.node-version");
|
|
47060
|
+
if (s.uses && (s.shell || s.working_directory)) c5.err(node2, path3, "shell and working-directory are only valid for run steps");
|
|
47061
|
+
if (s.uses === "brnch/infisical@v1") infisicalInputs(c5, node2, path3, s.with);
|
|
46529
47062
|
return s;
|
|
46530
47063
|
}
|
|
46531
|
-
function job(
|
|
46532
|
-
if (!ID_RE.test(id2))
|
|
46533
|
-
const es = entries(
|
|
47064
|
+
function job(c5, id2, keyNode, node2, path3) {
|
|
47065
|
+
if (!ID_RE.test(id2)) c5.err(keyNode, path3, `invalid job id "${id2}" (letters, digits, _ and -; must not start with a digit)`);
|
|
47066
|
+
const es = entries(c5, node2, path3);
|
|
46534
47067
|
if (!es) return null;
|
|
46535
47068
|
const j = {
|
|
46536
47069
|
id: id2,
|
|
@@ -46553,62 +47086,62 @@ function job(c4, id2, keyNode, node2, path3) {
|
|
|
46553
47086
|
for (const e of es) {
|
|
46554
47087
|
switch (e.key) {
|
|
46555
47088
|
case "name":
|
|
46556
|
-
j.name = str4(
|
|
46557
|
-
if (j.name) checkExpressions(
|
|
47089
|
+
j.name = str4(c5, e.value, e.path, { max: 200 });
|
|
47090
|
+
if (j.name) checkExpressions(c5, j.name, e.value, e.path, CTX.jobName);
|
|
46558
47091
|
break;
|
|
46559
47092
|
case "runs-on": {
|
|
46560
47093
|
sawRunsOn = true;
|
|
46561
|
-
const r = runsOn(
|
|
47094
|
+
const r = runsOn(c5, e.value, e.path);
|
|
46562
47095
|
if (r) j.runs_on = r;
|
|
46563
47096
|
break;
|
|
46564
47097
|
}
|
|
46565
47098
|
case "needs":
|
|
46566
|
-
j.needs = strList(
|
|
47099
|
+
j.needs = strList(c5, e.value, e.path) ?? [];
|
|
46567
47100
|
break;
|
|
46568
47101
|
case "if": {
|
|
46569
|
-
const v = scalar(
|
|
47102
|
+
const v = scalar(c5, e.value, e.path);
|
|
46570
47103
|
if (typeof v === "boolean") j.if = v ? "true" : "false";
|
|
46571
47104
|
else if (typeof v === "string" && v.trim()) {
|
|
46572
47105
|
j.if = v;
|
|
46573
|
-
checkExpressions(
|
|
46574
|
-
} else if (v !== void 0)
|
|
47106
|
+
checkExpressions(c5, v, e.value, e.path, CTX.jobIf, true);
|
|
47107
|
+
} else if (v !== void 0) c5.err(e.value, e.path, `${e.path} must be an expression`);
|
|
46575
47108
|
break;
|
|
46576
47109
|
}
|
|
46577
47110
|
case "env":
|
|
46578
|
-
j.env = envMap(
|
|
47111
|
+
j.env = envMap(c5, e.value, e.path, CTX.runner);
|
|
46579
47112
|
break;
|
|
46580
47113
|
case "timeout-minutes":
|
|
46581
|
-
j.timeout_minutes = int2(
|
|
47114
|
+
j.timeout_minutes = int2(c5, e.value, e.path, 1, LIMITS.maxTimeoutMinutes) ?? LIMITS.defaultTimeoutMinutes;
|
|
46582
47115
|
break;
|
|
46583
47116
|
case "continue-on-error":
|
|
46584
|
-
j.continue_on_error = boolOrExpr(
|
|
47117
|
+
j.continue_on_error = boolOrExpr(c5, e.value, e.path, CTX.jobContinue);
|
|
46585
47118
|
break;
|
|
46586
47119
|
case "strategy":
|
|
46587
|
-
for (const s of entries(
|
|
46588
|
-
if (s.key === "matrix") j.strategy.matrix = matrix(
|
|
46589
|
-
else if (s.key === "fail-fast") j.strategy.fail_fast = bool(
|
|
46590
|
-
else if (s.key === "max-parallel") j.strategy.max_parallel = int2(
|
|
46591
|
-
else
|
|
47120
|
+
for (const s of entries(c5, e.value, e.path) ?? []) {
|
|
47121
|
+
if (s.key === "matrix") j.strategy.matrix = matrix(c5, s.value, s.path);
|
|
47122
|
+
else if (s.key === "fail-fast") j.strategy.fail_fast = bool(c5, s.value, s.path) ?? true;
|
|
47123
|
+
else if (s.key === "max-parallel") j.strategy.max_parallel = int2(c5, s.value, s.path, 1, LIMITS.maxMatrixCombinations);
|
|
47124
|
+
else c5.err(s.keyNode, s.path, `unsupported key "${s.key}" in strategy (supported: matrix, fail-fast, max-parallel)`);
|
|
46592
47125
|
}
|
|
46593
47126
|
break;
|
|
46594
47127
|
case "defaults":
|
|
46595
|
-
j.defaults = defaults(
|
|
47128
|
+
j.defaults = defaults(c5, e.value, e.path);
|
|
46596
47129
|
break;
|
|
46597
47130
|
case "permissions":
|
|
46598
|
-
j.permissions = permissions(
|
|
47131
|
+
j.permissions = permissions(c5, e.value, e.path);
|
|
46599
47132
|
break;
|
|
46600
47133
|
case "container":
|
|
46601
47134
|
containerEntry = e;
|
|
46602
|
-
j.container = container(
|
|
47135
|
+
j.container = container(c5, e.value, e.path);
|
|
46603
47136
|
break;
|
|
46604
47137
|
case "outputs": {
|
|
46605
|
-
const os = entries(
|
|
46606
|
-
if (os.length > LIMITS.maxOutputs)
|
|
47138
|
+
const os = entries(c5, e.value, e.path) ?? [];
|
|
47139
|
+
if (os.length > LIMITS.maxOutputs) c5.err(e.value, e.path, `at most ${LIMITS.maxOutputs} outputs are supported`);
|
|
46607
47140
|
for (const o of os) {
|
|
46608
|
-
if (!ID_RE.test(o.key))
|
|
46609
|
-
const v = str4(
|
|
47141
|
+
if (!ID_RE.test(o.key)) c5.err(o.keyNode, o.path, `invalid output name "${o.key}"`);
|
|
47142
|
+
const v = str4(c5, o.value, o.path, { allowEmpty: true });
|
|
46610
47143
|
if (v === null) continue;
|
|
46611
|
-
checkExpressions(
|
|
47144
|
+
checkExpressions(c5, v, o.value, o.path, CTX.runner);
|
|
46612
47145
|
j.outputs[o.key] = v;
|
|
46613
47146
|
}
|
|
46614
47147
|
break;
|
|
@@ -46616,131 +47149,131 @@ function job(c4, id2, keyNode, node2, path3) {
|
|
|
46616
47149
|
case "steps": {
|
|
46617
47150
|
sawSteps = true;
|
|
46618
47151
|
if (!(0, import_yaml.isSeq)(e.value)) {
|
|
46619
|
-
|
|
47152
|
+
c5.err(e.value ?? e.keyNode, e.path, `${e.path} must be a list`);
|
|
46620
47153
|
break;
|
|
46621
47154
|
}
|
|
46622
|
-
if (e.value.items.length === 0)
|
|
46623
|
-
if (e.value.items.length > LIMITS.maxStepsPerJob)
|
|
47155
|
+
if (e.value.items.length === 0) c5.err(e.value, e.path, `${e.path} must contain at least one step`);
|
|
47156
|
+
if (e.value.items.length > LIMITS.maxStepsPerJob) c5.err(e.value, e.path, `a job can have at most ${LIMITS.maxStepsPerJob} steps`);
|
|
46624
47157
|
e.value.items.slice(0, LIMITS.maxStepsPerJob).forEach((item, i) => {
|
|
46625
|
-
const s = step(
|
|
47158
|
+
const s = step(c5, item, `${e.path}[${i}]`, i);
|
|
46626
47159
|
if (s) j.steps.push(s);
|
|
46627
47160
|
});
|
|
46628
47161
|
const ids = /* @__PURE__ */ new Set();
|
|
46629
47162
|
for (const s of j.steps) {
|
|
46630
47163
|
if (!s.id) continue;
|
|
46631
|
-
if (ids.has(s.id))
|
|
47164
|
+
if (ids.has(s.id)) c5.err(e.value.items[s.index], `${e.path}[${s.index}].id`, `duplicate step id "${s.id}"`);
|
|
46632
47165
|
ids.add(s.id);
|
|
46633
47166
|
}
|
|
46634
47167
|
break;
|
|
46635
47168
|
}
|
|
46636
47169
|
default:
|
|
46637
|
-
|
|
47170
|
+
c5.err(e.keyNode, e.path, UNSUPPORTED_JOB[e.key] ?? `unsupported job key "${e.key}" (supported: name, runs-on, needs, if, env, timeout-minutes, continue-on-error, strategy, defaults, permissions, outputs, container, steps)`);
|
|
46638
47171
|
}
|
|
46639
47172
|
}
|
|
46640
47173
|
if (containerEntry && j.runs_on.kind === "hosted") {
|
|
46641
|
-
|
|
47174
|
+
c5.err(containerEntry.keyNode, containerEntry.path, "job containers are only supported on self-hosted runners with Docker; hosted jobs already run in the brnch-hosted image");
|
|
46642
47175
|
}
|
|
46643
|
-
if (!sawRunsOn)
|
|
46644
|
-
if (!sawSteps)
|
|
47176
|
+
if (!sawRunsOn) c5.err(node2, path3, `${path3}.runs-on is required`);
|
|
47177
|
+
if (!sawSteps) c5.err(node2, path3, `${path3}.steps is required`);
|
|
46645
47178
|
return j;
|
|
46646
47179
|
}
|
|
46647
47180
|
var IMAGE_RE = /^[a-z0-9][a-z0-9._/:@-]{0,254}$/i;
|
|
46648
|
-
function container(
|
|
47181
|
+
function container(c5, node2, path3) {
|
|
46649
47182
|
let image = null;
|
|
46650
47183
|
let env = {};
|
|
46651
|
-
if ((0, import_yaml.isScalar)(node2)) image = str4(
|
|
47184
|
+
if ((0, import_yaml.isScalar)(node2)) image = str4(c5, node2, path3);
|
|
46652
47185
|
else {
|
|
46653
|
-
for (const e of entries(
|
|
46654
|
-
if (e.key === "image") image = str4(
|
|
46655
|
-
else if (e.key === "env") env = envMap(
|
|
46656
|
-
else
|
|
47186
|
+
for (const e of entries(c5, node2, path3) ?? []) {
|
|
47187
|
+
if (e.key === "image") image = str4(c5, e.value, e.path);
|
|
47188
|
+
else if (e.key === "env") env = envMap(c5, e.value, e.path, CTX.runner);
|
|
47189
|
+
else c5.err(e.keyNode, e.path, `unsupported key "${e.key}" in container (supported: image, env)`);
|
|
46657
47190
|
}
|
|
46658
47191
|
}
|
|
46659
47192
|
if (image === null) {
|
|
46660
|
-
|
|
47193
|
+
c5.err(node2, path3, `${path3}.image is required`);
|
|
46661
47194
|
return null;
|
|
46662
47195
|
}
|
|
46663
47196
|
if (hasExpressions(image) || !IMAGE_RE.test(image)) {
|
|
46664
|
-
|
|
47197
|
+
c5.err(node2, path3, `${path3}: invalid image reference "${image}" (literal image names only)`);
|
|
46665
47198
|
return null;
|
|
46666
47199
|
}
|
|
46667
47200
|
return { image, env };
|
|
46668
47201
|
}
|
|
46669
|
-
function permissions(
|
|
47202
|
+
function permissions(c5, node2, path3) {
|
|
46670
47203
|
const out = {};
|
|
46671
47204
|
if ((0, import_yaml.isScalar)(node2)) {
|
|
46672
|
-
const v = str4(
|
|
47205
|
+
const v = str4(c5, node2, path3);
|
|
46673
47206
|
if (v === "read-all") out.contents = "read";
|
|
46674
|
-
else if (v !== null)
|
|
47207
|
+
else if (v !== null) c5.err(node2, path3, `${path3}: "${v}" is not supported; job tokens are read-only (use read-all or contents: read)`);
|
|
46675
47208
|
return out;
|
|
46676
47209
|
}
|
|
46677
|
-
for (const e of entries(
|
|
46678
|
-
const v = str4(
|
|
47210
|
+
for (const e of entries(c5, node2, path3) ?? []) {
|
|
47211
|
+
const v = str4(c5, e.value, e.path);
|
|
46679
47212
|
if (e.key === "id-token") {
|
|
46680
47213
|
if (v === "write" || v === "none") out[e.key] = v;
|
|
46681
|
-
else if (v !== null)
|
|
47214
|
+
else if (v !== null) c5.err(e.value, e.path, `${e.path} must be write or none`);
|
|
46682
47215
|
continue;
|
|
46683
47216
|
}
|
|
46684
47217
|
if (v === "read" || v === "none") out[e.key] = v;
|
|
46685
|
-
else if (v === "write")
|
|
46686
|
-
else if (v !== null)
|
|
47218
|
+
else if (v === "write") c5.err(e.value, e.path, `${e.path}: write permissions are not supported; job tokens can only read the repository and report their own results (only id-token: write is accepted)`);
|
|
47219
|
+
else if (v !== null) c5.err(e.value, e.path, `${e.path} must be read or none`);
|
|
46687
47220
|
}
|
|
46688
47221
|
return out;
|
|
46689
47222
|
}
|
|
46690
|
-
function checkNeeds(
|
|
47223
|
+
function checkNeeds(c5, jobs, keyNodes) {
|
|
46691
47224
|
const ids = new Set(jobs.map((j) => j.id));
|
|
46692
47225
|
for (const j of jobs) {
|
|
46693
47226
|
for (const n of j.needs) {
|
|
46694
|
-
if (n === j.id)
|
|
46695
|
-
else if (!ids.has(n))
|
|
47227
|
+
if (n === j.id) c5.err(keyNodes.get(j.id) ?? null, `jobs.${j.id}.needs`, `job "${j.id}" cannot need itself`);
|
|
47228
|
+
else if (!ids.has(n)) c5.err(keyNodes.get(j.id) ?? null, `jobs.${j.id}.needs`, `job "${j.id}" needs unknown job "${n}"`);
|
|
46696
47229
|
}
|
|
46697
47230
|
}
|
|
46698
|
-
const
|
|
47231
|
+
const state2 = /* @__PURE__ */ new Map();
|
|
46699
47232
|
const byId = new Map(jobs.map((j) => [j.id, j]));
|
|
46700
47233
|
const visit2 = (id2, trail) => {
|
|
46701
|
-
const s =
|
|
47234
|
+
const s = state2.get(id2) ?? 0;
|
|
46702
47235
|
if (s === 2) return;
|
|
46703
47236
|
if (s === 1) {
|
|
46704
47237
|
const cycle = [...trail.slice(trail.indexOf(id2)), id2];
|
|
46705
|
-
|
|
47238
|
+
c5.err(keyNodes.get(id2) ?? null, `jobs.${id2}.needs`, `jobs form a cycle: ${cycle.join(" -> ")}`);
|
|
46706
47239
|
return;
|
|
46707
47240
|
}
|
|
46708
|
-
|
|
47241
|
+
state2.set(id2, 1);
|
|
46709
47242
|
for (const n of byId.get(id2)?.needs ?? []) if (byId.has(n)) visit2(n, [...trail, id2]);
|
|
46710
|
-
|
|
47243
|
+
state2.set(id2, 2);
|
|
46711
47244
|
};
|
|
46712
47245
|
for (const j of jobs) visit2(j.id, []);
|
|
46713
47246
|
}
|
|
46714
47247
|
function parseWorkflow(file2, source) {
|
|
46715
47248
|
const lc = new import_yaml.LineCounter();
|
|
46716
|
-
const
|
|
47249
|
+
const c5 = new Ctx(file2, lc);
|
|
46717
47250
|
if (new TextEncoder().encode(source).byteLength > LIMITS.maxFileBytes) {
|
|
46718
47251
|
return { workflow: null, issues: [{ file: file2, line: 1, column: 1, path: "", message: `workflow file is larger than ${LIMITS.maxFileBytes} bytes` }] };
|
|
46719
47252
|
}
|
|
46720
47253
|
const doc = (0, import_yaml.parseDocument)(source, { lineCounter: lc, prettyErrors: false, uniqueKeys: true, version: "1.2", schema: "core" });
|
|
46721
47254
|
for (const e of doc.errors) {
|
|
46722
47255
|
const { line: line2, col } = lc.linePos(e.pos[0]);
|
|
46723
|
-
|
|
47256
|
+
c5.issues.push({ file: file2, line: line2, column: col, path: "", message: `YAML: ${e.message.split("\n")[0]}` });
|
|
46724
47257
|
}
|
|
46725
|
-
if (
|
|
47258
|
+
if (c5.issues.length) return { workflow: null, issues: c5.issues.slice(0, MAX_ISSUES) };
|
|
46726
47259
|
let aliasFound = false;
|
|
46727
47260
|
const scan = (n) => {
|
|
46728
47261
|
if (aliasFound || !n || typeof n !== "object") return;
|
|
46729
47262
|
if ((0, import_yaml.isAlias)(n)) {
|
|
46730
47263
|
aliasFound = true;
|
|
46731
|
-
|
|
47264
|
+
c5.err(n, "", "YAML anchors and aliases are not supported");
|
|
46732
47265
|
return;
|
|
46733
47266
|
}
|
|
46734
47267
|
if ((0, import_yaml.isMap)(n) || (0, import_yaml.isSeq)(n)) for (const it of n.items) scan((0, import_yaml.isMap)(n) ? it.value : it);
|
|
46735
47268
|
if ((0, import_yaml.isScalar)(n) && n.anchor) {
|
|
46736
47269
|
aliasFound = true;
|
|
46737
|
-
|
|
47270
|
+
c5.err(n, "", "YAML anchors and aliases are not supported");
|
|
46738
47271
|
}
|
|
46739
47272
|
};
|
|
46740
47273
|
scan(doc.contents);
|
|
46741
47274
|
const root = doc.contents;
|
|
46742
|
-
const es = entries(
|
|
46743
|
-
if (!es) return { workflow: null, issues:
|
|
47275
|
+
const es = entries(c5, root, "", "a mapping with on and jobs");
|
|
47276
|
+
if (!es) return { workflow: null, issues: c5.issues };
|
|
46744
47277
|
const wf = {
|
|
46745
47278
|
file: file2,
|
|
46746
47279
|
name: file2,
|
|
@@ -46757,68 +47290,68 @@ function parseWorkflow(file2, source) {
|
|
|
46757
47290
|
for (const e of es) {
|
|
46758
47291
|
switch (e.key) {
|
|
46759
47292
|
case "name":
|
|
46760
|
-
wf.name = str4(
|
|
46761
|
-
if (hasExpressions(wf.name))
|
|
47293
|
+
wf.name = str4(c5, e.value, e.path, { max: 200 }) ?? file2;
|
|
47294
|
+
if (hasExpressions(wf.name)) c5.err(e.value, e.path, "the workflow name must be literal");
|
|
46762
47295
|
break;
|
|
46763
47296
|
case "on":
|
|
46764
47297
|
sawOn = true;
|
|
46765
|
-
wf.on = triggers(
|
|
47298
|
+
wf.on = triggers(c5, e.value);
|
|
46766
47299
|
break;
|
|
46767
47300
|
case "env":
|
|
46768
|
-
wf.env = envMap(
|
|
47301
|
+
wf.env = envMap(c5, e.value, e.path, CTX.workflowEnv);
|
|
46769
47302
|
break;
|
|
46770
47303
|
case "concurrency": {
|
|
46771
47304
|
if ((0, import_yaml.isScalar)(e.value)) {
|
|
46772
|
-
const g2 = str4(
|
|
47305
|
+
const g2 = str4(c5, e.value, e.path, { max: 400 });
|
|
46773
47306
|
if (g2) {
|
|
46774
|
-
checkExpressions(
|
|
47307
|
+
checkExpressions(c5, g2, e.value, e.path, CTX.concurrency);
|
|
46775
47308
|
wf.concurrency = { group: g2, cancel_in_progress: false };
|
|
46776
47309
|
}
|
|
46777
47310
|
break;
|
|
46778
47311
|
}
|
|
46779
47312
|
let group = null;
|
|
46780
47313
|
let cancel = false;
|
|
46781
|
-
for (const f of entries(
|
|
47314
|
+
for (const f of entries(c5, e.value, e.path) ?? []) {
|
|
46782
47315
|
if (f.key === "group") {
|
|
46783
|
-
group = str4(
|
|
46784
|
-
if (group) checkExpressions(
|
|
46785
|
-
} else if (f.key === "cancel-in-progress") cancel = boolOrExpr(
|
|
46786
|
-
else
|
|
47316
|
+
group = str4(c5, f.value, f.path, { max: 400 });
|
|
47317
|
+
if (group) checkExpressions(c5, group, f.value, f.path, CTX.concurrency);
|
|
47318
|
+
} else if (f.key === "cancel-in-progress") cancel = boolOrExpr(c5, f.value, f.path, CTX.concurrency);
|
|
47319
|
+
else c5.err(f.keyNode, f.path, `unsupported key "${f.key}" in concurrency (supported: group, cancel-in-progress)`);
|
|
46787
47320
|
}
|
|
46788
|
-
if (!group)
|
|
47321
|
+
if (!group) c5.err(e.value, e.path, "concurrency.group is required");
|
|
46789
47322
|
else wf.concurrency = { group, cancel_in_progress: cancel };
|
|
46790
47323
|
break;
|
|
46791
47324
|
}
|
|
46792
47325
|
case "permissions":
|
|
46793
|
-
wf.permissions = permissions(
|
|
47326
|
+
wf.permissions = permissions(c5, e.value, e.path);
|
|
46794
47327
|
break;
|
|
46795
47328
|
case "defaults":
|
|
46796
|
-
wf.defaults = defaults(
|
|
47329
|
+
wf.defaults = defaults(c5, e.value, e.path);
|
|
46797
47330
|
break;
|
|
46798
47331
|
case "jobs": {
|
|
46799
47332
|
sawJobs = true;
|
|
46800
|
-
const js = entries(
|
|
46801
|
-
if (js.length === 0)
|
|
46802
|
-
if (js.length > LIMITS.maxJobs)
|
|
47333
|
+
const js = entries(c5, e.value, "jobs") ?? [];
|
|
47334
|
+
if (js.length === 0) c5.err(e.value ?? e.keyNode, "jobs", "jobs must define at least one job");
|
|
47335
|
+
if (js.length > LIMITS.maxJobs) c5.err(e.value, "jobs", `a workflow can have at most ${LIMITS.maxJobs} jobs`);
|
|
46803
47336
|
for (const je of js.slice(0, LIMITS.maxJobs)) {
|
|
46804
47337
|
jobKeyNodes.set(je.key, je.keyNode);
|
|
46805
|
-
const j = job(
|
|
47338
|
+
const j = job(c5, je.key, je.keyNode, je.value, je.path);
|
|
46806
47339
|
if (j) wf.jobs.push(j);
|
|
46807
47340
|
}
|
|
46808
47341
|
break;
|
|
46809
47342
|
}
|
|
46810
47343
|
default:
|
|
46811
|
-
|
|
47344
|
+
c5.err(e.keyNode, e.path, UNSUPPORTED_TOP[e.key] ?? `unsupported top-level key "${e.key}" (supported: name, on, env, concurrency, permissions, defaults, jobs)`);
|
|
46812
47345
|
}
|
|
46813
47346
|
}
|
|
46814
|
-
if (!sawOn)
|
|
46815
|
-
if (!sawJobs)
|
|
46816
|
-
checkNeeds(
|
|
47347
|
+
if (!sawOn) c5.err(root, "on", "on is required");
|
|
47348
|
+
if (!sawJobs) c5.err(root, "jobs", "jobs is required");
|
|
47349
|
+
checkNeeds(c5, wf.jobs, jobKeyNodes);
|
|
46817
47350
|
const legs = wf.jobs.reduce((n, j) => n + (j.strategy.matrix ? Math.max(1, safeLegs(j.strategy.matrix)) : 1), 0);
|
|
46818
|
-
if (legs > LIMITS.maxJobs)
|
|
46819
|
-
|
|
46820
|
-
|
|
46821
|
-
return { workflow:
|
|
47351
|
+
if (legs > LIMITS.maxJobs) c5.err(root, "jobs", `the workflow expands to ${legs} jobs (limit ${LIMITS.maxJobs} per run)`);
|
|
47352
|
+
c5.issues.sort((a, b) => a.line - b.line || a.column - b.column);
|
|
47353
|
+
c5.issues = c5.issues.slice(0, MAX_ISSUES);
|
|
47354
|
+
return { workflow: c5.issues.length ? null : wf, issues: c5.issues };
|
|
46822
47355
|
}
|
|
46823
47356
|
function safeLegs(m) {
|
|
46824
47357
|
try {
|
|
@@ -46899,12 +47432,12 @@ function registerWorkflow(program2, rt) {
|
|
|
46899
47432
|
);
|
|
46900
47433
|
}
|
|
46901
47434
|
async function watchRun(ctx, runId, interval, timeout, logs) {
|
|
46902
|
-
const
|
|
47435
|
+
const c5 = ctx.client("user");
|
|
46903
47436
|
const deadline = Date.now() + timeout * 1e3;
|
|
46904
47437
|
const seen = /* @__PURE__ */ new Map();
|
|
46905
47438
|
const printed = /* @__PURE__ */ new Map();
|
|
46906
47439
|
for (; ; ) {
|
|
46907
|
-
const r = await
|
|
47440
|
+
const r = await c5.actions.runs.get(runId);
|
|
46908
47441
|
for (const j of r.jobs) {
|
|
46909
47442
|
const s = `${j.status}${j.conclusion ? `/${j.conclusion}` : ""}`;
|
|
46910
47443
|
if (seen.get(j.id) !== s) {
|
|
@@ -46913,7 +47446,7 @@ async function watchRun(ctx, runId, interval, timeout, logs) {
|
|
|
46913
47446
|
}
|
|
46914
47447
|
if (logs && j.status === "completed" && !printed.has(j.id)) {
|
|
46915
47448
|
printed.set(j.id, 1);
|
|
46916
|
-
const text2 = await
|
|
47449
|
+
const text2 = await c5.actions.jobs.logs(j.id).catch(() => "");
|
|
46917
47450
|
if (text2) ctx.info(`\u2500\u2500 ${j.name} \u2500\u2500
|
|
46918
47451
|
${text2.trimEnd()}`);
|
|
46919
47452
|
}
|
|
@@ -46933,10 +47466,10 @@ function registerRun(program2, rt) {
|
|
|
46933
47466
|
);
|
|
46934
47467
|
run3.command("view <run>").description("A run with its jobs; --log prints every job's log").option("--log", "print job logs").action(
|
|
46935
47468
|
act(rt, async (ctx, o, [id2]) => {
|
|
46936
|
-
const
|
|
46937
|
-
const r = await
|
|
47469
|
+
const c5 = ctx.client("user");
|
|
47470
|
+
const r = await c5.actions.runs.get(id2);
|
|
46938
47471
|
if (o.log) for (const j of r.jobs) ctx.info(`\u2500\u2500 ${j.name} (${j.status}${j.conclusion ? `/${j.conclusion}` : ""}) \u2500\u2500
|
|
46939
|
-
${(await
|
|
47472
|
+
${(await c5.actions.jobs.logs(j.id)).trimEnd()}`);
|
|
46940
47473
|
ctx.result(r, renderRun);
|
|
46941
47474
|
})
|
|
46942
47475
|
);
|
|
@@ -46949,16 +47482,16 @@ ${(await c4.actions.jobs.logs(j.id)).trimEnd()}`);
|
|
|
46949
47482
|
);
|
|
46950
47483
|
run3.command("logs <job>").description("Print a job's log (--follow streams it live)").option("--follow", "stream until the job completes").action(
|
|
46951
47484
|
act(rt, async (ctx, o, [job2]) => {
|
|
46952
|
-
const
|
|
47485
|
+
const c5 = ctx.client("user");
|
|
46953
47486
|
if (!o.follow) {
|
|
46954
|
-
const text2 = await
|
|
47487
|
+
const text2 = await c5.actions.jobs.logs(job2);
|
|
46955
47488
|
ctx.result({ job_id: job2, log: text2 }, text2);
|
|
46956
47489
|
return;
|
|
46957
47490
|
}
|
|
46958
47491
|
let after = 0;
|
|
46959
47492
|
let status = null;
|
|
46960
47493
|
while (status === null) {
|
|
46961
|
-
for await (const m of
|
|
47494
|
+
for await (const m of c5.actions.jobs.streamLogs(job2, { after })) {
|
|
46962
47495
|
if (m.kind === "log") {
|
|
46963
47496
|
ctx.deps.stderr.write(m.text);
|
|
46964
47497
|
after = m.seq;
|
|
@@ -47181,9 +47714,9 @@ function writeFresh(path3, data, owner, mode = 420) {
|
|
|
47181
47714
|
var shq = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
47182
47715
|
async function prepareCapture(spec, host, env) {
|
|
47183
47716
|
if (spec.vendor === "brnch" || spec.capture !== true || !host.capture) return null;
|
|
47184
|
-
const
|
|
47717
|
+
const c5 = host.capture;
|
|
47185
47718
|
const tool = CODING_AGENT_CAPTURE_TOOL[spec.vendor];
|
|
47186
|
-
if (!/\.m?js$/.test(
|
|
47719
|
+
if (!/\.m?js$/.test(c5.program) || !existsSync(c5.program)) {
|
|
47187
47720
|
host.log("##[warning]agent context capture is unavailable on this runner (its program cannot be run by the hooks); continuing without it");
|
|
47188
47721
|
return null;
|
|
47189
47722
|
}
|
|
@@ -47194,7 +47727,7 @@ async function prepareCapture(spec, host, env) {
|
|
|
47194
47727
|
mkdirSync(claudeHome);
|
|
47195
47728
|
if (!host.hosted) mkdirSync(home2, { recursive: true });
|
|
47196
47729
|
const program2 = join25(dir, `${BRAND.cli}.mjs`);
|
|
47197
|
-
writeFresh(program2, readFileSync3(
|
|
47730
|
+
writeFresh(program2, readFileSync3(c5.program, "utf8"), null);
|
|
47198
47731
|
const wrapper = join25(dir, BRAND.cli);
|
|
47199
47732
|
writeFresh(wrapper, `#!/bin/sh
|
|
47200
47733
|
exec ${shq(process.execPath)} ${shq(program2)} "$@"
|
|
@@ -47202,7 +47735,7 @@ exec ${shq(process.execPath)} ${shq(program2)} "$@"
|
|
|
47202
47735
|
for (const p of [program2, wrapper, claudeHome, dir, home2]) host.share(p);
|
|
47203
47736
|
const hookEnv = {
|
|
47204
47737
|
HOME: home2,
|
|
47205
|
-
[envName("URL")]:
|
|
47738
|
+
[envName("URL")]: c5.apiUrl,
|
|
47206
47739
|
[envName("NO_UPDATE_CHECK")]: "1",
|
|
47207
47740
|
BRNCH_CAPTURE_NO_FLUSH: "1"
|
|
47208
47741
|
};
|
|
@@ -47256,7 +47789,7 @@ function readEvents(file2) {
|
|
|
47256
47789
|
return out;
|
|
47257
47790
|
}
|
|
47258
47791
|
async function uploadCaptures(setup, host) {
|
|
47259
|
-
const
|
|
47792
|
+
const c5 = host.capture;
|
|
47260
47793
|
const spoolDir = capturePaths({ HOME: setup.home }).spool;
|
|
47261
47794
|
await settle2(spoolDir, Date.now() + 1e4);
|
|
47262
47795
|
const entries2 = (await listSpool({ HOME: setup.home })).filter((e) => e.meta.tool === setup.tool);
|
|
@@ -47274,7 +47807,7 @@ async function uploadCaptures(setup, host) {
|
|
|
47274
47807
|
const kept = events.slice(0, MAX_HOSTED_CAPTURE_EVENTS);
|
|
47275
47808
|
try {
|
|
47276
47809
|
for (let i = 0; i === 0 || i < kept.length; i += MAX_CAPTURE_EVENTS_PER_BATCH) {
|
|
47277
|
-
const res = await
|
|
47810
|
+
const res = await c5.upload({ client_key: e.meta.client_key, tool: setup.tool, model: e.meta.model, started_at: e.meta.started_at, events: kept.slice(i, i + MAX_CAPTURE_EVENTS_PER_BATCH) });
|
|
47278
47811
|
for (const r of res.results) {
|
|
47279
47812
|
if (r.status === "withheld") withheld++;
|
|
47280
47813
|
else if (r.status === "accepted") accepted++;
|
|
@@ -47424,8 +47957,8 @@ async function runAgentStep(spec, startOid, host) {
|
|
|
47424
47957
|
await git3(["add", "-A"]);
|
|
47425
47958
|
const status = await git3(["status", "--porcelain"]);
|
|
47426
47959
|
if (status.stdout.trim()) {
|
|
47427
|
-
const
|
|
47428
|
-
if (
|
|
47960
|
+
const c5 = await git3(["-c", `user.name=${spec.commit.author_name}`, "-c", `user.email=${spec.commit.author_email}`, "commit", "--no-verify", "-q", "-m", commitMessage.slice(0, 500)]);
|
|
47961
|
+
if (c5.code !== 0) {
|
|
47429
47962
|
host.log("##[error]could not commit the agent's changes");
|
|
47430
47963
|
return { outcome: "failure", outputs: reportOutputs(report3, "", version4) };
|
|
47431
47964
|
}
|
|
@@ -47971,9 +48504,9 @@ function claudePrompt(spec, diffFile, truncated) {
|
|
|
47971
48504
|
}
|
|
47972
48505
|
function command(spec, cli, o) {
|
|
47973
48506
|
if (spec.provider === "codex") {
|
|
47974
|
-
const
|
|
48507
|
+
const c5 = ['sandbox_mode="read-only"', 'approval_policy="never"', 'web_search="disabled"', 'shell_environment_policy.inherit="core"', "check_for_update_on_startup=false"];
|
|
47975
48508
|
return {
|
|
47976
|
-
argv: [...cli, "exec", "review", "--base", spec.base_branch, "--json", "--ephemeral", "--ignore-user-config", "--ignore-rules", ...
|
|
48509
|
+
argv: [...cli, "exec", "review", "--base", spec.base_branch, "--json", "--ephemeral", "--ignore-user-config", "--ignore-rules", ...c5.flatMap((x) => ["-c", x]), ...spec.model ? ["-m", spec.model] : []],
|
|
47977
48510
|
env: { CODEX_API_KEY: spec.api_key, CODEX_HOME: o.codexHome }
|
|
47978
48511
|
};
|
|
47979
48512
|
}
|
|
@@ -48069,8 +48602,8 @@ async function runCodeReviewStep(spec, host) {
|
|
|
48069
48602
|
const inputs = await prepareInputs(spec, host);
|
|
48070
48603
|
if (typeof inputs === "string") return fail("cli_failed", inputs, cli.version);
|
|
48071
48604
|
host.log(`##[brnch] ${name} reviews ${spec.head_branch} (${spec.head_oid.slice(0, 12)}) against ${spec.base_branch} (${spec.base_oid.slice(0, 12)}); the diff is sent to ${name}`);
|
|
48072
|
-
const
|
|
48073
|
-
const res = await host.run(
|
|
48605
|
+
const c5 = command(spec, cli.argv, inputs);
|
|
48606
|
+
const res = await host.run(c5.argv, { env: { ...host.env, ...c5.env, HOME: host.home, CI: "1", NO_COLOR: "1" }, timeoutMs: spec.timeout_minutes * 6e4, quiet: true });
|
|
48074
48607
|
if (host.cancelled() || res.code === null) return "cancelled";
|
|
48075
48608
|
const parsed = parse3(spec, res, host.workspace);
|
|
48076
48609
|
const counts2 = parsed.findings.reduce((acc, f) => ({ ...acc, [f.severity]: (acc[f.severity] ?? 0) + 1 }), {});
|
|
@@ -48921,13 +49454,13 @@ var RunnerAgent = class {
|
|
|
48921
49454
|
stepUser: this.opts.stepUser ?? null,
|
|
48922
49455
|
baseEnv: sanitizedEnv(process.env),
|
|
48923
49456
|
diag: this.opts.log,
|
|
48924
|
-
onRunnerCredential: (
|
|
49457
|
+
onRunnerCredential: (c5) => this.rotated(c5),
|
|
48925
49458
|
...this.opts.fetch ? { fetch: this.opts.fetch } : {}
|
|
48926
49459
|
});
|
|
48927
49460
|
this.opts.log(`job ${a.job_id} started: ${a.workflow.name} / ${a.job.name} (${a.repository.full_name}@${a.head_sha.slice(0, 12)})`);
|
|
48928
|
-
const done2 = exec.run().then((
|
|
48929
|
-
this.results.push({ job_id: a.job_id, conclusion:
|
|
48930
|
-
this.opts.log(`job ${a.job_id} finished: ${
|
|
49461
|
+
const done2 = exec.run().then((c5) => {
|
|
49462
|
+
this.results.push({ job_id: a.job_id, conclusion: c5 });
|
|
49463
|
+
this.opts.log(`job ${a.job_id} finished: ${c5}`);
|
|
48931
49464
|
}).catch((e) => {
|
|
48932
49465
|
this.results.push({ job_id: a.job_id, conclusion: "aborted" });
|
|
48933
49466
|
this.opts.log(`job ${a.job_id} failed to report: ${e.message}`);
|
|
@@ -49696,85 +50229,105 @@ function nodeDeps() {
|
|
|
49696
50229
|
}
|
|
49697
50230
|
|
|
49698
50231
|
// packages/cli/src/help.ts
|
|
49699
|
-
var
|
|
50232
|
+
var c4 = BRAND.cli;
|
|
49700
50233
|
var EXAMPLES = {
|
|
49701
50234
|
"": [
|
|
49702
|
-
`${
|
|
49703
|
-
`${
|
|
49704
|
-
`export ${envName("TOKEN")}=\u2026; ${
|
|
49705
|
-
`${
|
|
49706
|
-
`${
|
|
50235
|
+
`${c4} setup # first run: sign in, SSH and HTTPS for git, agents, this directory`,
|
|
50236
|
+
`${c4} auth login # browser sign-in (OAuth device code) for humans`,
|
|
50237
|
+
`export ${envName("TOKEN")}=\u2026; ${c4} --json auth status # CI/agents: token from the environment`,
|
|
50238
|
+
`${c4} repo clone acme/web`,
|
|
50239
|
+
`${c4} doctor # diagnose install, network and auth`
|
|
49707
50240
|
],
|
|
49708
|
-
"auth login": [`${
|
|
49709
|
-
"auth status": [`${
|
|
49710
|
-
"auth logout": [`${
|
|
49711
|
-
"auth switch": [`${
|
|
49712
|
-
"auth backup-codes": [`${
|
|
49713
|
-
"auth step-up": [`${
|
|
49714
|
-
"auth git-credential": [`git config --global credential.${BRAND.defaultUrl}.helper '!${
|
|
49715
|
-
"auth setup-git": [`${
|
|
49716
|
-
"repo clone": [`${
|
|
49717
|
-
"repo list": [`${
|
|
49718
|
-
"repo create": [`${
|
|
49719
|
-
"org create": [`${
|
|
49720
|
-
"org list": [`${
|
|
49721
|
-
"org switch": [`${
|
|
49722
|
-
"org invitations": [`${
|
|
49723
|
-
git: [`${
|
|
49724
|
-
"change create": [`${
|
|
49725
|
-
"change view": [`${
|
|
49726
|
-
"change readiness": [`${
|
|
49727
|
-
"code-review status": [`${
|
|
49728
|
-
"code-review wait": [`${
|
|
49729
|
-
"code-review request": [`${
|
|
49730
|
-
"merge request": [`${
|
|
49731
|
-
"evidence submit": [`${
|
|
49732
|
-
"session start": [`${
|
|
49733
|
-
"agent instructions": [`${
|
|
50241
|
+
"auth login": [`${c4} auth login # another account? log in again: both stay signed in`, `${c4} auth login --scopes repo:read,change:read --no-browser`, `echo "$PAT" | ${c4} auth login --with-token`, `${c4} --url https://brnch.example.com auth login`],
|
|
50242
|
+
"auth status": [`${c4} auth status # which account, why, and the others`, `${c4} --json auth status --agent`],
|
|
50243
|
+
"auth logout": [`${c4} auth logout`, `${c4} --account ada-work auth logout # one of several accounts`],
|
|
50244
|
+
"auth switch": [`${c4} auth switch # toggle between two accounts, or pick`, `${c4} auth switch ada-work`],
|
|
50245
|
+
"auth backup-codes": [`${c4} auth backup-codes`, `${c4} --json auth backup-codes`, `${c4} auth backup-codes --regenerate --code 123456`, `${c4} --yes auth backup-codes --regenerate --code - < code.txt`],
|
|
50246
|
+
"auth step-up": [`${c4} auth step-up # approve in the browser; admin actions work for 15 minutes`, `${c4} auth step-up --status`, `${c4} auth step-up --end`],
|
|
50247
|
+
"auth git-credential": [`git config --global credential.${BRAND.defaultUrl}.helper '!${c4} auth git-credential'`],
|
|
50248
|
+
"auth setup-git": [`${c4} auth setup-git # then plain git clone/fetch/push over HTTPS just work`, `${c4} --url https://brnch.example.com auth setup-git`],
|
|
50249
|
+
"repo clone": [`${c4} repo clone acme/web # SSH once \`${c4} ssh setup\` ran, else HTTPS`, `${c4} repo clone acme/web ./web --https`],
|
|
50250
|
+
"repo list": [`${c4} --org acme repo list # an organization`, `${c4} --org your-handle repo list # your personal account`, `${c4} --json --org acme repo list --limit 50`],
|
|
50251
|
+
"repo create": [`${c4} --org acme repo create web # in the organization acme`, `${c4} --org your-handle repo create notes # in your personal account`],
|
|
50252
|
+
"org create": [`${c4} org create acme --name "Acme Inc."`],
|
|
50253
|
+
"org list": [`${c4} org list # your personal account and organizations`],
|
|
50254
|
+
"org switch": [`${c4} org switch acme # commands default to acme`, `${c4} org switch --unset`, `${c4} --account ada-work org switch vigil # per account`],
|
|
50255
|
+
"org invitations": [`${c4} org invitations`, `${c4} org invitations accept inv_\u2026`],
|
|
50256
|
+
git: [`${c4} git push origin HEAD:refs/heads/topic`, `${c4} git fetch`],
|
|
50257
|
+
"change create": [`${c4} change create --title "Org-scoped API keys" --workspace ws_123`],
|
|
50258
|
+
"change view": [`${c4} change view 12 # change #12 of the selected repository`, `${c4} --repo acme/web change view '#12'`, `${c4} change view chg_123`],
|
|
50259
|
+
"change readiness": [`${c4} change readiness 12 || echo "blocked (exit $?)"`, `${c4} change readiness chg_123`],
|
|
50260
|
+
"code-review status": [`${c4} code-review status 12`, `${c4} --json code-review status 12 --all`],
|
|
50261
|
+
"code-review wait": [`${c4} code-review wait 12 # then fix each finding and \`${c4} review fix <thread> --change 12\``, `${c4} code-review wait 12 --timeout 600`],
|
|
50262
|
+
"code-review request": [`${c4} code-review request 12`, `${c4} code-review request 12 --provider codex`],
|
|
50263
|
+
"merge request": [`${c4} merge request 12 --wait --json`],
|
|
50264
|
+
"evidence submit": [`${c4} evidence submit --change 12 --check unit-tests --result passed --command "npm test" --exit-code 0`],
|
|
50265
|
+
"session start": [`${c4} --repo acme/web session start --agent agt_123 --scope repo:read,change:write --json`],
|
|
50266
|
+
"agent instructions": [`${c4} agent instructions --tool claude-code`, `${c4} agent instructions --tool codex --write # into AGENTS.md here, asks first`],
|
|
49734
50267
|
delegate: [
|
|
49735
|
-
`${
|
|
49736
|
-
`${
|
|
49737
|
-
`${
|
|
50268
|
+
`${c4} --repo acme/web delegate issue:12 --agent claude_code --prompt "Keep the public API unchanged" --wait`,
|
|
50269
|
+
`${c4} delegate chg_123 --agent brnch --auto-review --max-iterations 3`,
|
|
50270
|
+
`${c4} delegate task_123 --agent codex --prompt-file brief.md --json`
|
|
50271
|
+
],
|
|
50272
|
+
"agents status": [`${c4} agents status dlg_123`, `${c4} --repo acme/web agents status change:7`],
|
|
50273
|
+
"agents ask": [`${c4} agents ask dlg_123 --instructions "Add a test for the empty case" --wait`, `${c4} agents ask dlg_123 --thread thr_1,thr_2`],
|
|
50274
|
+
"agents take-over": [`${c4} agents take-over dlg_123 --reason "finishing by hand"`],
|
|
50275
|
+
"coding-agents set": [`pbpaste | ${c4} --org acme coding-agents set claude_code --key-stdin --enable`, `${c4} --org acme coding-agents set codex --ai-provider aip_123 --enable`],
|
|
50276
|
+
"events watch": [`${c4} --org acme events watch # new events from now on`, `${c4} --json --org acme events watch --after evt_123 # replay since, then follow`, `${c4} --json events watch --session ses_123`],
|
|
50277
|
+
inbox: [`${c4} inbox # unread, most urgent first`, `${c4} inbox list --view all`, `${c4} inbox done 3f9k2a 8c1d0e`, `${c4} inbox snooze 3f9k2a tomorrow`, `${c4} --json inbox watch | jq -c .`],
|
|
50278
|
+
"inbox list": [`${c4} inbox list --view snoozed`, `${c4} --json inbox list --view all --limit 50 | jq '.items[].title'`],
|
|
50279
|
+
"inbox count": [`${c4} inbox count # e.g. in a shell prompt`],
|
|
50280
|
+
"inbox read": [`${c4} inbox read 3f9k2a`, `${c4} inbox read --all`],
|
|
50281
|
+
"inbox done": [`${c4} inbox done 3f9k2a 8c1d0e`, `${c4} --yes inbox done --all`],
|
|
50282
|
+
"inbox snooze": [`${c4} inbox snooze 3f9k2a 2h`, `${c4} inbox snooze 3f9k2a next-week`, `${c4} inbox snooze 3f9k2a 2026-10-07`],
|
|
50283
|
+
"inbox mute": [`${c4} inbox mute 3f9k2a # no more notifications about that change`],
|
|
50284
|
+
"inbox open": [`${c4} inbox open 3f9k2a`],
|
|
50285
|
+
"inbox watch": [`${c4} inbox watch`, `${c4} --json inbox watch # one JSON object per line`],
|
|
50286
|
+
notifications: [`${c4} notifications`, `${c4} --org acme notifications get # what applies in acme`],
|
|
50287
|
+
"notifications set": [
|
|
50288
|
+
`${c4} notifications set mentioned push=off email=digest`,
|
|
50289
|
+
`${c4} notifications set all email=off`,
|
|
50290
|
+
`${c4} --org acme notifications set watching in_app=off # only in acme`,
|
|
50291
|
+
`${c4} --org acme notifications set --reset`,
|
|
50292
|
+
`${c4} notifications set --digest weekly --digest-hour 9 --tz Europe/Paris`,
|
|
50293
|
+
`${c4} notifications set --quiet-hours 22:00-07:00 --previews off`
|
|
49738
50294
|
],
|
|
49739
|
-
"
|
|
49740
|
-
"
|
|
49741
|
-
"agents take-over": [`${c3} agents take-over dlg_123 --reason "finishing by hand"`],
|
|
49742
|
-
"coding-agents set": [`pbpaste | ${c3} --org acme coding-agents set claude_code --key-stdin --enable`, `${c3} --org acme coding-agents set codex --ai-provider aip_123 --enable`],
|
|
49743
|
-
"events watch": [`${c3} --json events watch --session ses_123`],
|
|
50295
|
+
"notifications unmute": [`${c4} notifications unmute chg_123`],
|
|
50296
|
+
"notifications devices remove": [`${c4} --yes notifications devices remove push_123`],
|
|
49744
50297
|
"ssh setup": [
|
|
49745
|
-
`${
|
|
49746
|
-
`${
|
|
49747
|
-
`op read "op://Private/My SSH Key/public key" | ${
|
|
49748
|
-
`${
|
|
49749
|
-
`${
|
|
50298
|
+
`${c4} ssh setup # config, host key, pick + register a key, test, this clone`,
|
|
50299
|
+
`${c4} ssh setup --key ~/.ssh/id_ed25519.pub`,
|
|
50300
|
+
`op read "op://Private/My SSH Key/public key" | ${c4} ssh setup --key - # 1Password: only the public key`,
|
|
50301
|
+
`${c4} --yes ssh setup --remote # also switch this clone's origin to SSH without asking`,
|
|
50302
|
+
`${c4} --account ada-work ssh setup # a second account gets its own alias (brnch.io-ada-work)`
|
|
49750
50303
|
],
|
|
49751
|
-
"ssh test": [`${
|
|
49752
|
-
"ssh-key add": [`${
|
|
49753
|
-
setup: [`${
|
|
50304
|
+
"ssh test": [`${c4} ssh test`, `${c4} --json ssh test | jq .error.details.problem`],
|
|
50305
|
+
"ssh-key add": [`${c4} ssh-key add ~/.ssh/id_ed25519.pub --title laptop`, `op read "op://Private/My SSH Key/public key" | ${c4} ssh-key add - --title "My SSH Key"`, `${c4} ssh-key add ~/.ssh/id_ed25519.pub --usage auth+signing`],
|
|
50306
|
+
setup: [`${c4} setup`, `${c4} setup --dry-run`, `${c4} --yes setup --org acme --repo-name api --agents claude-code --no-ssh`],
|
|
49754
50307
|
"remotes adopt": [
|
|
49755
|
-
`${
|
|
49756
|
-
`${
|
|
49757
|
-
`${
|
|
49758
|
-
`${
|
|
50308
|
+
`${c4} remotes adopt ~/code --dry-run # show what would change`,
|
|
50309
|
+
`${c4} remotes adopt ~/code # switch clones of imported GitHub repositories to ${c4}`,
|
|
50310
|
+
`${c4} --yes remotes adopt . --push # also fill repositories too large to import`,
|
|
50311
|
+
`${c4} remotes adopt ~/code --undo # put origin back on GitHub`
|
|
49759
50312
|
],
|
|
49760
|
-
"hooks install": [`${
|
|
49761
|
-
"capture wrap": [`${
|
|
49762
|
-
decision: [`${
|
|
50313
|
+
"hooks install": [`${c4} hooks install`, `${c4} hooks install --agent claude-code --agent codex --git`, `${c4} hooks install --scope project --agent cursor`],
|
|
50314
|
+
"capture wrap": [`${c4} capture wrap --tool aider -- aider src/keys.ts`],
|
|
50315
|
+
decision: [`${c4} decision "Keep legacy keys valid" --reason "clients cannot rotate yet" --file src/keys.ts`],
|
|
49763
50316
|
"deploy setup": [
|
|
49764
|
-
`${
|
|
49765
|
-
`${
|
|
49766
|
-
`${
|
|
50317
|
+
`${c4} --repo acme/web deploy setup --dry-run # show what it would create`,
|
|
50318
|
+
`${c4} --repo acme/web deploy setup # the only connection, account and Wrangler config`,
|
|
50319
|
+
`${c4} deploy setup --config apps/api/wrangler.jsonc --env staging --name staging`
|
|
49767
50320
|
],
|
|
49768
|
-
"deploy run": [`${
|
|
49769
|
-
"deploy update": [`${
|
|
49770
|
-
"deploy rollback": [`${
|
|
49771
|
-
version: [`${
|
|
49772
|
-
upgrade: [`${
|
|
49773
|
-
doctor: [`${
|
|
50321
|
+
"deploy run": [`${c4} deploy run production --wait || echo "deploy failed (exit $?)"`, `${c4} deploy run dpt_123 --commit 0123456789abcdef0123456789abcdef01234567`],
|
|
50322
|
+
"deploy update": [`${c4} deploy update production --build "npm run build:prod"`, `${c4} deploy update production --disable`],
|
|
50323
|
+
"deploy rollback": [`${c4} deploy rollback production --to dpl_123`],
|
|
50324
|
+
version: [`${c4} version`, `${c4} version --json`],
|
|
50325
|
+
upgrade: [`${c4} upgrade --check`, `${c4} upgrade`, `${c4} upgrade --force`],
|
|
50326
|
+
doctor: [`${c4} doctor`, `${c4} doctor --json | jq '.checks[] | select(.status != "ok")'`],
|
|
49774
50327
|
completion: [
|
|
49775
|
-
`${
|
|
49776
|
-
`${
|
|
49777
|
-
`${
|
|
50328
|
+
`${c4} completion bash > ~/.local/share/bash-completion/completions/${c4}`,
|
|
50329
|
+
`${c4} completion zsh > "\${fpath[1]}/_${c4}"`,
|
|
50330
|
+
`${c4} completion fish > ~/.config/fish/completions/${c4}.fish`
|
|
49778
50331
|
]
|
|
49779
50332
|
};
|
|
49780
50333
|
function pathOf(cmd) {
|
|
@@ -49801,9 +50354,9 @@ var CHECK_TIMEOUT_MS = 1e3;
|
|
|
49801
50354
|
function updateCheckFile(env) {
|
|
49802
50355
|
return join32(dirname18(credentialsPath({ XDG_CONFIG_HOME: env.XDG_CONFIG_HOME, HOME: env.HOME }, BRAND.configDir)), "update-check.json");
|
|
49803
50356
|
}
|
|
49804
|
-
function updateCheckDisabled(deps,
|
|
50357
|
+
function updateCheckDisabled(deps, state2) {
|
|
49805
50358
|
const flag = deps.env[envName("NO_UPDATE_CHECK")];
|
|
49806
|
-
return !!flag && flag !== "0" || !!deps.env.CI ||
|
|
50359
|
+
return !!flag && flag !== "0" || !!deps.env.CI || state2.json || !!state2.noUpdateHint || !deps.stderrIsTTY || !state2.baseUrl;
|
|
49807
50360
|
}
|
|
49808
50361
|
async function readCache(deps, file2) {
|
|
49809
50362
|
try {
|
|
@@ -49813,10 +50366,10 @@ async function readCache(deps, file2) {
|
|
|
49813
50366
|
}
|
|
49814
50367
|
return { version: 1, hosts: {} };
|
|
49815
50368
|
}
|
|
49816
|
-
async function updateHint(deps,
|
|
50369
|
+
async function updateHint(deps, state2) {
|
|
49817
50370
|
try {
|
|
49818
|
-
if (updateCheckDisabled(deps,
|
|
49819
|
-
const baseUrl =
|
|
50371
|
+
if (updateCheckDisabled(deps, state2)) return;
|
|
50372
|
+
const baseUrl = state2.baseUrl;
|
|
49820
50373
|
const file2 = updateCheckFile(deps.env);
|
|
49821
50374
|
const cache = await readCache(deps, file2);
|
|
49822
50375
|
const key = hostKey(baseUrl);
|
|
@@ -49895,6 +50448,8 @@ function buildProgram(rt) {
|
|
|
49895
50448
|
registerIntegration(program2, rt);
|
|
49896
50449
|
registerTooling(program2, rt);
|
|
49897
50450
|
registerSocial(program2, rt);
|
|
50451
|
+
registerInbox(program2, rt);
|
|
50452
|
+
registerNotifications(program2, rt);
|
|
49898
50453
|
registerVerify(program2, rt);
|
|
49899
50454
|
registerStack(program2, rt);
|
|
49900
50455
|
registerOplog(program2, rt);
|
|
@@ -49941,33 +50496,33 @@ function errorPayload(e, secrets) {
|
|
|
49941
50496
|
if (e instanceof CliError) return { code: e.code, message: redact(e.message, secrets), details: e.details ?? null };
|
|
49942
50497
|
return { code: "UNEXPECTED", message: redact(e instanceof Error ? e.message : String(e), secrets) };
|
|
49943
50498
|
}
|
|
49944
|
-
function report2(e, deps,
|
|
50499
|
+
function report2(e, deps, state2) {
|
|
49945
50500
|
if (e instanceof CommanderError) {
|
|
49946
50501
|
if (e.exitCode === 0 || e.code === "commander.helpDisplayed" || e.code === "commander.version") return EXIT.OK;
|
|
49947
|
-
if (
|
|
50502
|
+
if (state2.json) deps.stdout.write(`${JSON.stringify({ error: { code: "USAGE", message: e.message, exit_code: EXIT.USAGE } }, null, 2)}
|
|
49948
50503
|
`);
|
|
49949
50504
|
return EXIT.USAGE;
|
|
49950
50505
|
}
|
|
49951
50506
|
const exitCode = exitCodeFor(e);
|
|
49952
|
-
const payload = errorPayload(e,
|
|
49953
|
-
if (
|
|
50507
|
+
const payload = errorPayload(e, state2.secrets);
|
|
50508
|
+
if (state2.json && !state2.wroteResult) deps.stdout.write(`${JSON.stringify({ error: { ...payload, exit_code: exitCode } }, null, 2)}
|
|
49954
50509
|
`);
|
|
49955
50510
|
const reqId = "request_id" in payload && payload.request_id ? ` (request ${payload.request_id})` : "";
|
|
49956
50511
|
deps.stderr.write(`error: ${payload.message} [${payload.code}]${reqId}
|
|
49957
50512
|
`);
|
|
49958
|
-
if (
|
|
49959
|
-
const s =
|
|
50513
|
+
if (state2.actingAs && isForgeApiError(e) && (e.code === "PERMISSION_DENIED" || e.code === "NOT_FOUND")) {
|
|
50514
|
+
const s = state2.actingAs;
|
|
49960
50515
|
const sponsor = s.sponsor_name ?? "your sponsor";
|
|
49961
50516
|
deps.stderr.write(
|
|
49962
50517
|
`This ran as agent ${s.agent_name} (session ${s.session_id}), which may only use its session scopes in ${s.repo} (${s.scopes.join(" ")}). Approving, merging and administration stay with people: hand this step to ${sponsor}. For a merge, finish pushing, then ask ${sponsor} to use Merge when ready on the change (or \`${BRAND.cli} change auto-merge <change>\` in their own terminal; \`${BRAND.cli} merge agent-changes\` does it once for all their agents' changes in the repository).
|
|
49963
50518
|
`
|
|
49964
50519
|
);
|
|
49965
50520
|
}
|
|
49966
|
-
if (
|
|
49967
|
-
deps.stderr.write(`This ran as ${
|
|
50521
|
+
if (state2.accounts && !state2.actingAs && isForgeApiError(e) && (e.code === "PERMISSION_DENIED" || e.code === "NOT_FOUND")) {
|
|
50522
|
+
deps.stderr.write(`This ran as ${state2.accounts.using}. You are also signed in as ${state2.accounts.others.join(", ")}: retry with --account ${state2.accounts.others[0]}, or \`${BRAND.cli} auth switch\`.
|
|
49968
50523
|
`);
|
|
49969
50524
|
}
|
|
49970
|
-
if (deps.env[envName("DEBUG")] && e instanceof Error && e.stack) deps.stderr.write(`${redact(e.stack,
|
|
50525
|
+
if (deps.env[envName("DEBUG")] && e instanceof Error && e.stack) deps.stderr.write(`${redact(e.stack, state2.secrets)}
|
|
49971
50526
|
`);
|
|
49972
50527
|
return exitCode;
|
|
49973
50528
|
}
|
|
@@ -49975,22 +50530,22 @@ async function run2(argv, overrides = {}) {
|
|
|
49975
50530
|
const merged = { ...nodeDeps(), ...overrides };
|
|
49976
50531
|
const deps = merged;
|
|
49977
50532
|
const split = splitGitArgs(argv);
|
|
49978
|
-
const
|
|
50533
|
+
const state2 = { exitCode: EXIT.OK, wroteResult: false, secrets: [], json: wantsJson(split.argv) };
|
|
49979
50534
|
const invoke2 = async (sub, o = {}) => {
|
|
49980
50535
|
const out = [];
|
|
49981
50536
|
const code2 = await run2(sub, o.capture ? { ...deps, stdout: { write: (s) => out.push(s) } } : deps);
|
|
49982
50537
|
return { code: code2, stdout: out.join("") };
|
|
49983
50538
|
};
|
|
49984
|
-
const program2 = buildProgram({ deps, state, gitArgs: split.gitArgs, invoke: invoke2 });
|
|
50539
|
+
const program2 = buildProgram({ deps, state: state2, gitArgs: split.gitArgs, invoke: invoke2 });
|
|
49985
50540
|
let code;
|
|
49986
50541
|
try {
|
|
49987
50542
|
await program2.parseAsync(split.argv, { from: "user" });
|
|
49988
|
-
code =
|
|
50543
|
+
code = state2.exitCode;
|
|
49989
50544
|
} catch (e) {
|
|
49990
|
-
code = report2(e, deps,
|
|
50545
|
+
code = report2(e, deps, state2);
|
|
49991
50546
|
}
|
|
49992
|
-
await saveBookmark(deps,
|
|
49993
|
-
await updateHint(deps,
|
|
50547
|
+
await saveBookmark(deps, state2);
|
|
50548
|
+
await updateHint(deps, state2);
|
|
49994
50549
|
return code;
|
|
49995
50550
|
}
|
|
49996
50551
|
|