@lesscap/baton-cli 0.9.6 → 0.9.8
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 +2 -2
- package/dist/baton.mjs +1208 -2048
- package/package.json +1 -1
package/dist/baton.mjs
CHANGED
|
@@ -5376,10 +5376,10 @@ var toJson = (data) => JSON.stringify(data, null, 2);
|
|
|
5376
5376
|
var fmtWorkspace = (w) => `${w.id} ${w.name}`;
|
|
5377
5377
|
var fmtWorkerTemplate = (t) => `${t.id} ${t.name} [${t.available ? "available" : "unavailable"}] ${t.agentKinds.join(", ")}`;
|
|
5378
5378
|
var fmtWorkerCreation = (c) => `${c.id} [${c.status}/${c.step ?? "pending"}] ${c.name} ${c.agentKind}${c.workerId === null ? "" : ` W-${c.workerId}`}${c.error ? ` ${c.error}` : ""}`;
|
|
5379
|
+
var fmtHost = (h) => `${h.id} ${h.name} [${h.online ? "online" : "offline"}] workspaces: ${h.workspaceIds.join(",") || "-"}`;
|
|
5380
|
+
var fmtHostCredential = ({ host: host2, token }) => `${host2.id} ${host2.name}
|
|
5381
|
+
token: ${token}`;
|
|
5379
5382
|
var fmtProject = (p) => `${p.id} ${p.name}`;
|
|
5380
|
-
var fmtRequirement = (r) => `${r.code} [${r.status}] ${r.title}`;
|
|
5381
|
-
var fmtTask = (t) => `${t.code} [${t.status}] ${t.title}`;
|
|
5382
|
-
var fmtComment = (c) => `${c.workerId !== void 0 ? `worker#${c.workerId}` : "you"} ${c.body}`;
|
|
5383
5383
|
var fmtSession = (s) => `${s.id} ${s.name} ${s.attached ? "[active]" : "[inactive]"} ${s.cwd ?? "(pending)"}`;
|
|
5384
5384
|
var fmtWorker = (w) => {
|
|
5385
5385
|
const offline = w.connected === false ? " [offline]" : "";
|
|
@@ -5509,6 +5509,15 @@ var filesClient = (baseUrl) => {
|
|
|
5509
5509
|
};
|
|
5510
5510
|
};
|
|
5511
5511
|
|
|
5512
|
+
// src/client/hosts.ts
|
|
5513
|
+
var hostsClient = (baseUrl) => ({
|
|
5514
|
+
create: (name) => request(`${baseUrl}/hosts`, { method: "POST", body: { name } }),
|
|
5515
|
+
list: () => request(`${baseUrl}/hosts`, { method: "GET" }),
|
|
5516
|
+
rotate: (id) => request(`${baseUrl}/hosts/${id}/token`, { method: "POST", body: {} }),
|
|
5517
|
+
assign: (id, workspaceId) => request(`${baseUrl}/hosts/${id}/workspaces/${workspaceId}`, { method: "PUT" }),
|
|
5518
|
+
unassign: (id, workspaceId) => request(`${baseUrl}/hosts/${id}/workspaces/${workspaceId}`, { method: "DELETE" })
|
|
5519
|
+
});
|
|
5520
|
+
|
|
5512
5521
|
// src/client/loops.ts
|
|
5513
5522
|
var loopsClient = (baseUrl) => {
|
|
5514
5523
|
const u = (p) => `${baseUrl}${p}`;
|
|
@@ -5535,30 +5544,6 @@ var projectClient = (baseUrl) => {
|
|
|
5535
5544
|
};
|
|
5536
5545
|
};
|
|
5537
5546
|
|
|
5538
|
-
// src/client/items.ts
|
|
5539
|
-
var fetchItemByCode = async (baseUrl, projectId, code, expectKind) => {
|
|
5540
|
-
const r = await request(
|
|
5541
|
-
`${baseUrl}/projects/${projectId}/items/${encodeURIComponent(code)}`,
|
|
5542
|
-
{ method: "GET" }
|
|
5543
|
-
);
|
|
5544
|
-
if (r.kind !== expectKind) throw new Error(`expected ${expectKind} but got ${r.kind} for ${code}`);
|
|
5545
|
-
return r.item;
|
|
5546
|
-
};
|
|
5547
|
-
|
|
5548
|
-
// src/client/requirements.ts
|
|
5549
|
-
var requirementClient = (baseUrl) => {
|
|
5550
|
-
const u = (p) => `${baseUrl}${p}`;
|
|
5551
|
-
return {
|
|
5552
|
-
create: (input) => request(u("/requirements"), { method: "POST", body: input }),
|
|
5553
|
-
listByProject: (projectId) => request(u(`/projects/${projectId}/requirements`), { method: "GET" }),
|
|
5554
|
-
get: (id) => request(u(`/requirements/${id}`), { method: "GET" }),
|
|
5555
|
-
getByCode: (projectId, code) => fetchItemByCode(baseUrl, projectId, code, "requirement"),
|
|
5556
|
-
update: (id, patch) => request(u(`/requirements/${id}`), { method: "PATCH", body: patch }),
|
|
5557
|
-
setStatus: (id, status) => request(u(`/requirements/${id}`), { method: "PATCH", body: { status } }),
|
|
5558
|
-
remove: (id) => request(u(`/requirements/${id}`), { method: "DELETE" })
|
|
5559
|
-
};
|
|
5560
|
-
};
|
|
5561
|
-
|
|
5562
5547
|
// src/client/services.ts
|
|
5563
5548
|
var servicesClient = (baseUrl) => {
|
|
5564
5549
|
const u = (path) => `${baseUrl}${path}`;
|
|
@@ -5693,24 +5678,9 @@ var sessionsClient = (baseUrl) => {
|
|
|
5693
5678
|
};
|
|
5694
5679
|
};
|
|
5695
5680
|
|
|
5696
|
-
// src/client/tasks.ts
|
|
5697
|
-
var taskClient = (baseUrl) => {
|
|
5698
|
-
const u = (p) => `${baseUrl}${p}`;
|
|
5699
|
-
return {
|
|
5700
|
-
create: (input) => request(u("/tasks"), { method: "POST", body: input }),
|
|
5701
|
-
listByRequirement: (requirementId) => request(u(`/requirements/${requirementId}/tasks`), { method: "GET" }),
|
|
5702
|
-
get: (id) => request(u(`/tasks/${id}`), { method: "GET" }),
|
|
5703
|
-
getByCode: (projectId, code) => fetchItemByCode(baseUrl, projectId, code, "task"),
|
|
5704
|
-
update: (id, patch) => request(u(`/tasks/${id}`), { method: "PATCH", body: patch }),
|
|
5705
|
-
setStatus: (id, status) => request(u(`/tasks/${id}`), { method: "PATCH", body: { status } }),
|
|
5706
|
-
remove: (id) => request(u(`/tasks/${id}`), { method: "DELETE" }),
|
|
5707
|
-
listComments: (id) => request(u(`/tasks/${id}/comments`), { method: "GET" }),
|
|
5708
|
-
addComment: (id, body, workerId) => request(u(`/tasks/${id}/comments`), { method: "POST", body: { body, workerId } })
|
|
5709
|
-
};
|
|
5710
|
-
};
|
|
5711
|
-
|
|
5712
5681
|
// src/client/worker-creations.ts
|
|
5713
5682
|
var workerCreationsClient = (baseUrl) => ({
|
|
5683
|
+
hosts: (projectId) => request(`${baseUrl}/projects/${projectId}/hosts`, { method: "GET" }),
|
|
5714
5684
|
templates: (projectId) => request(`${baseUrl}/projects/${projectId}/worker-templates`, { method: "GET" }),
|
|
5715
5685
|
create: (projectId, input) => request(`${baseUrl}/projects/${projectId}/worker-creations`, { method: "POST", body: input }),
|
|
5716
5686
|
listByProject: (projectId) => request(`${baseUrl}/projects/${projectId}/worker-creations`, { method: "GET" }),
|
|
@@ -5758,11 +5728,10 @@ var createClient = (baseUrl, opts) => {
|
|
|
5758
5728
|
};
|
|
5759
5729
|
var clientFromBase = (baseUrl) => ({
|
|
5760
5730
|
workerCreations: workerCreationsClient(baseUrl),
|
|
5731
|
+
hosts: hostsClient(baseUrl),
|
|
5761
5732
|
artifacts: artifactsClient(baseUrl),
|
|
5762
5733
|
workspaces: workspaceClient(baseUrl),
|
|
5763
5734
|
projects: projectClient(baseUrl),
|
|
5764
|
-
requirements: requirementClient(baseUrl),
|
|
5765
|
-
tasks: taskClient(baseUrl),
|
|
5766
5735
|
sessions: sessionsClient(baseUrl),
|
|
5767
5736
|
services: servicesClient(baseUrl),
|
|
5768
5737
|
files: filesClient(baseUrl),
|
|
@@ -5883,11 +5852,6 @@ var clientFor = (args) => {
|
|
|
5883
5852
|
const auth = resolveAuth(process.env, fileToken);
|
|
5884
5853
|
return createClient(baseUrl, auth && auth !== "cookie" ? auth : void 0);
|
|
5885
5854
|
};
|
|
5886
|
-
var resolveBearer = () => {
|
|
5887
|
-
const fileToken = loadProjectConfigOrNull(projectConfigPath())?.worker?.apiToken;
|
|
5888
|
-
const auth = resolveAuth(process.env, fileToken);
|
|
5889
|
-
return auth && auth !== "cookie" ? auth.bearer : void 0;
|
|
5890
|
-
};
|
|
5891
5855
|
var resolveProjectId = (args) => {
|
|
5892
5856
|
if (args.project !== void 0 && args.project !== "") return Number(args.project);
|
|
5893
5857
|
if (process.env.BATON_PROJECT_ID !== void 0)
|
|
@@ -5908,7 +5872,6 @@ var parseWorkerHandle = (handle) => {
|
|
|
5908
5872
|
const m = handle.trim().match(/^(?:[wW]-)?(\d+)$/);
|
|
5909
5873
|
return m ? Number(m[1]) : null;
|
|
5910
5874
|
};
|
|
5911
|
-
var splitCsv = (s) => s ? s.split(",").map((x) => x.trim()).filter(Boolean) : void 0;
|
|
5912
5875
|
var parseDuration = (s) => {
|
|
5913
5876
|
const m = s.trim().match(/^(\d+)\s*([smhd]?)$/);
|
|
5914
5877
|
if (!m) throw new Error(`bad interval "${s}" \u2014 use e.g. 90s, 30m, 2h, 1d`);
|
|
@@ -5990,758 +5953,412 @@ var artifact = defineCommand({
|
|
|
5990
5953
|
subCommands: { publish: publishCommand, ls: listCommand, rm: removeCommand }
|
|
5991
5954
|
});
|
|
5992
5955
|
|
|
5993
|
-
//
|
|
5994
|
-
var
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5956
|
+
// src/commands/host.ts
|
|
5957
|
+
var findHost = (hosts, handle) => {
|
|
5958
|
+
const host2 = hosts.find((item) => item.name === handle || String(item.id) === handle);
|
|
5959
|
+
if (!host2) throw new Error(`host not found: ${handle}`);
|
|
5960
|
+
return host2;
|
|
5998
5961
|
};
|
|
5999
|
-
var
|
|
6000
|
-
var
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
const input = pendingFragments.join("");
|
|
6028
|
-
pendingFragments.length = 0, pendingFragmentsLength = 0;
|
|
6029
|
-
const trailing = processLines(input);
|
|
6030
|
-
trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
|
|
6031
|
-
}
|
|
6032
|
-
function checkBufferSize() {
|
|
6033
|
-
maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = true, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = "", dataLines = 0, eventType = void 0, onError(
|
|
6034
|
-
new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
|
|
6035
|
-
type: "max-buffer-size-exceeded"
|
|
6036
|
-
})
|
|
6037
|
-
)));
|
|
6038
|
-
}
|
|
6039
|
-
function processLines(chunk) {
|
|
6040
|
-
let searchIndex = 0;
|
|
6041
|
-
if (chunk.indexOf("\r") === -1) {
|
|
6042
|
-
let lfIndex = chunk.indexOf(`
|
|
6043
|
-
`, searchIndex);
|
|
6044
|
-
for (; lfIndex !== -1; ) {
|
|
6045
|
-
if (searchIndex === lfIndex) {
|
|
6046
|
-
dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
6047
|
-
`, searchIndex);
|
|
6048
|
-
continue;
|
|
6049
|
-
}
|
|
6050
|
-
const firstCharCode = chunk.charCodeAt(searchIndex);
|
|
6051
|
-
if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
|
|
6052
|
-
const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
|
|
6053
|
-
if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
|
|
6054
|
-
onEvent({ id, event: eventType, data: value }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
|
|
6055
|
-
`, searchIndex);
|
|
6056
|
-
continue;
|
|
6057
|
-
}
|
|
6058
|
-
data = dataLines === 0 ? value : `${data}
|
|
6059
|
-
${value}`, dataLines++;
|
|
6060
|
-
} else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(
|
|
6061
|
-
chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,
|
|
6062
|
-
lfIndex
|
|
6063
|
-
) || void 0 : parseLine(chunk, searchIndex, lfIndex);
|
|
6064
|
-
searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
6065
|
-
`, searchIndex);
|
|
5962
|
+
var adminHost = async (c, handle) => findHost(await c.hosts.list(), handle);
|
|
5963
|
+
var positiveId = (raw) => {
|
|
5964
|
+
const id = Number(raw);
|
|
5965
|
+
if (!Number.isSafeInteger(id) || id <= 0) throw new Error("workspace must be a positive id");
|
|
5966
|
+
return id;
|
|
5967
|
+
};
|
|
5968
|
+
var hostArg = {
|
|
5969
|
+
host: { type: "positional", required: true, description: "host name or id" }
|
|
5970
|
+
};
|
|
5971
|
+
var workspaceArg = {
|
|
5972
|
+
workspace: { type: "string", required: true, description: "workspace id" }
|
|
5973
|
+
};
|
|
5974
|
+
var host = defineCommand({
|
|
5975
|
+
meta: { name: "host", description: "manage machines and which workspaces can use them (admin)" },
|
|
5976
|
+
subCommands: {
|
|
5977
|
+
add: defineCommand({
|
|
5978
|
+
meta: { name: "add", description: "add a host; prints its Provisioner token once" },
|
|
5979
|
+
args: {
|
|
5980
|
+
name: { type: "positional", required: true, description: "host name" },
|
|
5981
|
+
workspace: { type: "string", description: "also assign it to this workspace id" },
|
|
5982
|
+
...common
|
|
5983
|
+
},
|
|
5984
|
+
run: async ({ args }) => {
|
|
5985
|
+
const c = clientFor(args);
|
|
5986
|
+
const workspaceId = args.workspace === void 0 ? null : positiveId(args.workspace);
|
|
5987
|
+
const credential = await c.hosts.create(args.name);
|
|
5988
|
+
console.log(renderOne(credential, fmtHostCredential, Boolean(args.json)));
|
|
5989
|
+
if (workspaceId !== null) await c.hosts.assign(credential.host.id, workspaceId);
|
|
6066
5990
|
}
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
}
|
|
6077
|
-
return chunk.slice(searchIndex);
|
|
6078
|
-
}
|
|
6079
|
-
function parseLine(chunk, start, end) {
|
|
6080
|
-
if (start === end) {
|
|
6081
|
-
dispatchEvent();
|
|
6082
|
-
return;
|
|
6083
|
-
}
|
|
6084
|
-
const firstCharCode = chunk.charCodeAt(start);
|
|
6085
|
-
if (isDataPrefix(chunk, start, firstCharCode)) {
|
|
6086
|
-
const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
|
|
6087
|
-
data = dataLines === 0 ? value2 : `${data}
|
|
6088
|
-
${value2}`, dataLines++;
|
|
6089
|
-
return;
|
|
6090
|
-
}
|
|
6091
|
-
if (isEventPrefix(chunk, start, firstCharCode)) {
|
|
6092
|
-
eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
|
|
6093
|
-
return;
|
|
6094
|
-
}
|
|
6095
|
-
if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
|
|
6096
|
-
const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
|
|
6097
|
-
id = value2.includes("\0") ? void 0 : value2;
|
|
6098
|
-
return;
|
|
6099
|
-
}
|
|
6100
|
-
if (firstCharCode === 58) {
|
|
6101
|
-
if (onComment) {
|
|
6102
|
-
const line2 = chunk.slice(start, end);
|
|
6103
|
-
onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
|
|
5991
|
+
}),
|
|
5992
|
+
ls: defineCommand({
|
|
5993
|
+
meta: {
|
|
5994
|
+
name: "ls",
|
|
5995
|
+
description: "list hosts, whether they are online, and their workspaces"
|
|
5996
|
+
},
|
|
5997
|
+
args: { ...common },
|
|
5998
|
+
run: async ({ args }) => {
|
|
5999
|
+
console.log(renderList(await clientFor(args).hosts.list(), fmtHost, Boolean(args.json)));
|
|
6104
6000
|
}
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
id
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
);
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
new ParseError(
|
|
6139
|
-
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
|
|
6140
|
-
{ type: "unknown-field", field, value, line }
|
|
6141
|
-
)
|
|
6142
|
-
);
|
|
6143
|
-
break;
|
|
6144
|
-
}
|
|
6145
|
-
}
|
|
6146
|
-
function dispatchEvent() {
|
|
6147
|
-
dataLines > 0 && onEvent({
|
|
6148
|
-
id,
|
|
6149
|
-
event: eventType,
|
|
6150
|
-
data
|
|
6151
|
-
}), id = void 0, data = "", dataLines = 0, eventType = void 0;
|
|
6152
|
-
}
|
|
6153
|
-
function reset(options = {}) {
|
|
6154
|
-
if (options.consume && pendingFragments.length > 0) {
|
|
6155
|
-
const incompleteLine = pendingFragments.join("");
|
|
6156
|
-
parseLine(incompleteLine, 0, incompleteLine.length);
|
|
6157
|
-
}
|
|
6158
|
-
isFirstChunk = true, id = void 0, data = "", dataLines = 0, eventType = void 0, pendingFragments.length = 0, pendingFragmentsLength = 0, terminated = false;
|
|
6001
|
+
}),
|
|
6002
|
+
assign: defineCommand({
|
|
6003
|
+
meta: { name: "assign", description: "let a workspace create Workers on this host" },
|
|
6004
|
+
args: { ...hostArg, ...workspaceArg, ...common },
|
|
6005
|
+
run: async ({ args }) => {
|
|
6006
|
+
const c = clientFor(args);
|
|
6007
|
+
const { id, name } = await adminHost(c, args.host);
|
|
6008
|
+
await c.hosts.assign(id, positiveId(args.workspace));
|
|
6009
|
+
console.log(`assigned ${name} to workspace ${args.workspace}`);
|
|
6010
|
+
}
|
|
6011
|
+
}),
|
|
6012
|
+
unassign: defineCommand({
|
|
6013
|
+
meta: {
|
|
6014
|
+
name: "unassign",
|
|
6015
|
+
description: "stop new Workers on this host for a workspace; existing ones keep running"
|
|
6016
|
+
},
|
|
6017
|
+
args: { ...hostArg, ...workspaceArg, ...common },
|
|
6018
|
+
run: async ({ args }) => {
|
|
6019
|
+
const c = clientFor(args);
|
|
6020
|
+
const { id, name } = await adminHost(c, args.host);
|
|
6021
|
+
await c.hosts.unassign(id, positiveId(args.workspace));
|
|
6022
|
+
console.log(`unassigned ${name} from workspace ${args.workspace}`);
|
|
6023
|
+
}
|
|
6024
|
+
}),
|
|
6025
|
+
rotate: defineCommand({
|
|
6026
|
+
meta: { name: "rotate", description: "replace a host token; the old one stops working" },
|
|
6027
|
+
args: { ...hostArg, ...common },
|
|
6028
|
+
run: async ({ args }) => {
|
|
6029
|
+
const c = clientFor(args);
|
|
6030
|
+
const { id } = await adminHost(c, args.host);
|
|
6031
|
+
console.log(renderOne(await c.hosts.rotate(id), fmtHostCredential, Boolean(args.json)));
|
|
6032
|
+
}
|
|
6033
|
+
})
|
|
6159
6034
|
}
|
|
6160
|
-
|
|
6161
|
-
}
|
|
6162
|
-
function isDataPrefix(chunk, i, firstCharCode) {
|
|
6163
|
-
return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
|
|
6164
|
-
}
|
|
6165
|
-
function isEventPrefix(chunk, i, firstCharCode) {
|
|
6166
|
-
return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
|
|
6167
|
-
}
|
|
6035
|
+
});
|
|
6168
6036
|
|
|
6169
|
-
//
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6037
|
+
// src/commands/init.ts
|
|
6038
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
6039
|
+
import * as readline from "node:readline/promises";
|
|
6040
|
+
var promptPick = async (label, items) => {
|
|
6041
|
+
if (items.length === 0) throw new Error(`no ${label}s found on server`);
|
|
6042
|
+
console.log(`${label}s:`);
|
|
6043
|
+
items.forEach((it, i) => {
|
|
6044
|
+
console.log(` [${i + 1}] #${it.id} ${it.name}`);
|
|
6045
|
+
});
|
|
6046
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
6047
|
+
try {
|
|
6048
|
+
const ans = (await rl.question(`pick a ${label} (1-${items.length}): `)).trim();
|
|
6049
|
+
const idx = Number(ans) - 1;
|
|
6050
|
+
const picked = items[idx];
|
|
6051
|
+
if (!picked) throw new Error(`invalid choice: ${ans}`);
|
|
6052
|
+
return picked;
|
|
6053
|
+
} finally {
|
|
6054
|
+
rl.close();
|
|
6181
6055
|
}
|
|
6182
|
-
/**
|
|
6183
|
-
* Node.js "hides" the `message` and `code` properties of the `ErrorEvent` instance,
|
|
6184
|
-
* when it is `console.log`'ed. This makes it harder to debug errors. To ease debugging,
|
|
6185
|
-
* we explicitly include the properties in the `inspect` method.
|
|
6186
|
-
*
|
|
6187
|
-
* This is automatically called by Node.js when you `console.log` an instance of this class.
|
|
6188
|
-
*
|
|
6189
|
-
* @param _depth - The current depth
|
|
6190
|
-
* @param options - The options passed to `util.inspect`
|
|
6191
|
-
* @param inspect - The inspect function to use (prevents having to import it from `util`)
|
|
6192
|
-
* @returns A string representation of the error
|
|
6193
|
-
*/
|
|
6194
|
-
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")](_depth, options, inspect) {
|
|
6195
|
-
return inspect(inspectableError(this), options);
|
|
6196
|
-
}
|
|
6197
|
-
/**
|
|
6198
|
-
* Deno "hides" the `message` and `code` properties of the `ErrorEvent` instance,
|
|
6199
|
-
* when it is `console.log`'ed. This makes it harder to debug errors. To ease debugging,
|
|
6200
|
-
* we explicitly include the properties in the `inspect` method.
|
|
6201
|
-
*
|
|
6202
|
-
* This is automatically called by Deno when you `console.log` an instance of this class.
|
|
6203
|
-
*
|
|
6204
|
-
* @param inspect - The inspect function to use (prevents having to import it from `util`)
|
|
6205
|
-
* @param options - The options passed to `Deno.inspect`
|
|
6206
|
-
* @returns A string representation of the error
|
|
6207
|
-
*/
|
|
6208
|
-
[/* @__PURE__ */ Symbol.for("Deno.customInspect")](inspect, options) {
|
|
6209
|
-
return inspect(inspectableError(this), options);
|
|
6210
|
-
}
|
|
6211
|
-
};
|
|
6212
|
-
function syntaxError(message) {
|
|
6213
|
-
const DomException = globalThis.DOMException;
|
|
6214
|
-
return typeof DomException == "function" ? new DomException(message, "SyntaxError") : new SyntaxError(message);
|
|
6215
|
-
}
|
|
6216
|
-
function flattenError(err) {
|
|
6217
|
-
return err instanceof Error ? "errors" in err && Array.isArray(err.errors) ? err.errors.map(flattenError).join(", ") : "cause" in err && err.cause instanceof Error ? `${err}: ${flattenError(err.cause)}` : err.message : `${err}`;
|
|
6218
|
-
}
|
|
6219
|
-
function inspectableError(err) {
|
|
6220
|
-
return {
|
|
6221
|
-
type: err.type,
|
|
6222
|
-
message: err.message,
|
|
6223
|
-
code: err.code,
|
|
6224
|
-
defaultPrevented: err.defaultPrevented,
|
|
6225
|
-
cancelable: err.cancelable,
|
|
6226
|
-
timeStamp: err.timeStamp
|
|
6227
|
-
};
|
|
6228
|
-
}
|
|
6229
|
-
var __typeError = (msg) => {
|
|
6230
|
-
throw TypeError(msg);
|
|
6231
|
-
};
|
|
6232
|
-
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
6233
|
-
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6234
|
-
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
6235
|
-
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
|
|
6236
|
-
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
6237
|
-
var _readyState;
|
|
6238
|
-
var _url;
|
|
6239
|
-
var _redirectUrl;
|
|
6240
|
-
var _withCredentials;
|
|
6241
|
-
var _fetch;
|
|
6242
|
-
var _reconnectInterval;
|
|
6243
|
-
var _reconnectTimer;
|
|
6244
|
-
var _lastEventId;
|
|
6245
|
-
var _controller;
|
|
6246
|
-
var _parser;
|
|
6247
|
-
var _onError;
|
|
6248
|
-
var _onMessage;
|
|
6249
|
-
var _onOpen;
|
|
6250
|
-
var _EventSource_instances;
|
|
6251
|
-
var connect_fn;
|
|
6252
|
-
var _onFetchResponse;
|
|
6253
|
-
var _onFetchError;
|
|
6254
|
-
var getRequestOptions_fn;
|
|
6255
|
-
var _onEvent;
|
|
6256
|
-
var _onRetryChange;
|
|
6257
|
-
var failConnection_fn;
|
|
6258
|
-
var scheduleReconnect_fn;
|
|
6259
|
-
var _reconnect;
|
|
6260
|
-
var EventSource = class extends EventTarget {
|
|
6261
|
-
constructor(url, eventSourceInitDict) {
|
|
6262
|
-
var _a, _b;
|
|
6263
|
-
super(), __privateAdd(this, _EventSource_instances), this.CONNECTING = 0, this.OPEN = 1, this.CLOSED = 2, __privateAdd(this, _readyState), __privateAdd(this, _url), __privateAdd(this, _redirectUrl), __privateAdd(this, _withCredentials), __privateAdd(this, _fetch), __privateAdd(this, _reconnectInterval), __privateAdd(this, _reconnectTimer), __privateAdd(this, _lastEventId, null), __privateAdd(this, _controller), __privateAdd(this, _parser), __privateAdd(this, _onError, null), __privateAdd(this, _onMessage, null), __privateAdd(this, _onOpen, null), __privateAdd(this, _onFetchResponse, async (response) => {
|
|
6264
|
-
var _a2;
|
|
6265
|
-
__privateGet(this, _parser).reset();
|
|
6266
|
-
const { body, redirected, status, headers } = response;
|
|
6267
|
-
if (status === 204) {
|
|
6268
|
-
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Server sent HTTP 204, not reconnecting", 204), this.close();
|
|
6269
|
-
return;
|
|
6270
|
-
}
|
|
6271
|
-
if (redirected ? __privateSet(this, _redirectUrl, new URL(response.url)) : __privateSet(this, _redirectUrl, void 0), status !== 200) {
|
|
6272
|
-
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, `Non-200 status code (${status})`, status);
|
|
6273
|
-
return;
|
|
6274
|
-
}
|
|
6275
|
-
if (!(headers.get("content-type") || "").startsWith("text/event-stream")) {
|
|
6276
|
-
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, 'Invalid content type, expected "text/event-stream"', status);
|
|
6277
|
-
return;
|
|
6278
|
-
}
|
|
6279
|
-
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
6280
|
-
return;
|
|
6281
|
-
__privateSet(this, _readyState, this.OPEN);
|
|
6282
|
-
const openEvent = new Event("open");
|
|
6283
|
-
if ((_a2 = __privateGet(this, _onOpen)) == null || _a2.call(this, openEvent), this.dispatchEvent(openEvent), typeof body != "object" || !body || !("getReader" in body)) {
|
|
6284
|
-
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Invalid response body, expected a web ReadableStream", status), this.close();
|
|
6285
|
-
return;
|
|
6286
|
-
}
|
|
6287
|
-
const decoder = new TextDecoder(), reader = body.getReader();
|
|
6288
|
-
let open3 = true;
|
|
6289
|
-
do {
|
|
6290
|
-
const { done, value } = await reader.read();
|
|
6291
|
-
value && __privateGet(this, _parser).feed(decoder.decode(value, { stream: !done })), done && (open3 = false, __privateGet(this, _parser).reset(), __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this));
|
|
6292
|
-
} while (open3);
|
|
6293
|
-
}), __privateAdd(this, _onFetchError, (err) => {
|
|
6294
|
-
__privateSet(this, _controller, void 0), !(err.name === "AbortError" || err.type === "aborted") && __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this, flattenError(err));
|
|
6295
|
-
}), __privateAdd(this, _onEvent, (event) => {
|
|
6296
|
-
typeof event.id == "string" && __privateSet(this, _lastEventId, event.id);
|
|
6297
|
-
const messageEvent = new MessageEvent(event.event || "message", {
|
|
6298
|
-
data: event.data,
|
|
6299
|
-
origin: __privateGet(this, _redirectUrl) ? __privateGet(this, _redirectUrl).origin : __privateGet(this, _url).origin,
|
|
6300
|
-
lastEventId: event.id || ""
|
|
6301
|
-
});
|
|
6302
|
-
__privateGet(this, _onMessage) && (!event.event || event.event === "message") && __privateGet(this, _onMessage).call(this, messageEvent), this.dispatchEvent(messageEvent);
|
|
6303
|
-
}), __privateAdd(this, _onRetryChange, (value) => {
|
|
6304
|
-
__privateSet(this, _reconnectInterval, value);
|
|
6305
|
-
}), __privateAdd(this, _reconnect, () => {
|
|
6306
|
-
__privateSet(this, _reconnectTimer, void 0), __privateGet(this, _readyState) === this.CONNECTING && __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
6307
|
-
});
|
|
6308
|
-
try {
|
|
6309
|
-
if (url instanceof URL)
|
|
6310
|
-
__privateSet(this, _url, url);
|
|
6311
|
-
else if (typeof url == "string")
|
|
6312
|
-
__privateSet(this, _url, new URL(url, getBaseURL()));
|
|
6313
|
-
else
|
|
6314
|
-
throw new Error("Invalid URL");
|
|
6315
|
-
} catch {
|
|
6316
|
-
throw syntaxError("An invalid or illegal string was specified");
|
|
6317
|
-
}
|
|
6318
|
-
__privateSet(this, _parser, createParser({
|
|
6319
|
-
onEvent: __privateGet(this, _onEvent),
|
|
6320
|
-
onRetry: __privateGet(this, _onRetryChange)
|
|
6321
|
-
})), __privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _reconnectInterval, 3e3), __privateSet(this, _fetch, (_a = eventSourceInitDict == null ? void 0 : eventSourceInitDict.fetch) != null ? _a : globalThis.fetch), __privateSet(this, _withCredentials, (_b = eventSourceInitDict == null ? void 0 : eventSourceInitDict.withCredentials) != null ? _b : false), __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
6322
|
-
}
|
|
6323
|
-
/**
|
|
6324
|
-
* Returns the state of this EventSource object's connection. It can have the values described below.
|
|
6325
|
-
*
|
|
6326
|
-
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/readyState)
|
|
6327
|
-
*
|
|
6328
|
-
* Note: typed as `number` instead of `0 | 1 | 2` for compatibility with the `EventSource` interface,
|
|
6329
|
-
* defined in the TypeScript `dom` library.
|
|
6330
|
-
*
|
|
6331
|
-
* @public
|
|
6332
|
-
*/
|
|
6333
|
-
get readyState() {
|
|
6334
|
-
return __privateGet(this, _readyState);
|
|
6335
|
-
}
|
|
6336
|
-
/**
|
|
6337
|
-
* Returns the URL providing the event stream.
|
|
6338
|
-
*
|
|
6339
|
-
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/url)
|
|
6340
|
-
*
|
|
6341
|
-
* @public
|
|
6342
|
-
*/
|
|
6343
|
-
get url() {
|
|
6344
|
-
return __privateGet(this, _url).href;
|
|
6345
|
-
}
|
|
6346
|
-
/**
|
|
6347
|
-
* Returns true if the credentials mode for connection requests to the URL providing the event stream is set to "include", and false otherwise.
|
|
6348
|
-
*
|
|
6349
|
-
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/withCredentials)
|
|
6350
|
-
*/
|
|
6351
|
-
get withCredentials() {
|
|
6352
|
-
return __privateGet(this, _withCredentials);
|
|
6353
|
-
}
|
|
6354
|
-
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/error_event) */
|
|
6355
|
-
get onerror() {
|
|
6356
|
-
return __privateGet(this, _onError);
|
|
6357
|
-
}
|
|
6358
|
-
set onerror(value) {
|
|
6359
|
-
__privateSet(this, _onError, value);
|
|
6360
|
-
}
|
|
6361
|
-
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/message_event) */
|
|
6362
|
-
get onmessage() {
|
|
6363
|
-
return __privateGet(this, _onMessage);
|
|
6364
|
-
}
|
|
6365
|
-
set onmessage(value) {
|
|
6366
|
-
__privateSet(this, _onMessage, value);
|
|
6367
|
-
}
|
|
6368
|
-
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/open_event) */
|
|
6369
|
-
get onopen() {
|
|
6370
|
-
return __privateGet(this, _onOpen);
|
|
6371
|
-
}
|
|
6372
|
-
set onopen(value) {
|
|
6373
|
-
__privateSet(this, _onOpen, value);
|
|
6374
|
-
}
|
|
6375
|
-
addEventListener(type, listener, options) {
|
|
6376
|
-
const listen = listener;
|
|
6377
|
-
super.addEventListener(type, listen, options);
|
|
6378
|
-
}
|
|
6379
|
-
removeEventListener(type, listener, options) {
|
|
6380
|
-
const listen = listener;
|
|
6381
|
-
super.removeEventListener(type, listen, options);
|
|
6382
|
-
}
|
|
6383
|
-
/**
|
|
6384
|
-
* Aborts any instances of the fetch algorithm started for this EventSource object, and sets the readyState attribute to CLOSED.
|
|
6385
|
-
*
|
|
6386
|
-
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/close)
|
|
6387
|
-
*
|
|
6388
|
-
* @public
|
|
6389
|
-
*/
|
|
6390
|
-
close() {
|
|
6391
|
-
__privateGet(this, _reconnectTimer) && clearTimeout(__privateGet(this, _reconnectTimer)), __privateGet(this, _readyState) !== this.CLOSED && (__privateGet(this, _controller) && __privateGet(this, _controller).abort(), __privateSet(this, _readyState, this.CLOSED), __privateSet(this, _controller, void 0));
|
|
6392
|
-
}
|
|
6393
|
-
};
|
|
6394
|
-
_readyState = /* @__PURE__ */ new WeakMap(), _url = /* @__PURE__ */ new WeakMap(), _redirectUrl = /* @__PURE__ */ new WeakMap(), _withCredentials = /* @__PURE__ */ new WeakMap(), _fetch = /* @__PURE__ */ new WeakMap(), _reconnectInterval = /* @__PURE__ */ new WeakMap(), _reconnectTimer = /* @__PURE__ */ new WeakMap(), _lastEventId = /* @__PURE__ */ new WeakMap(), _controller = /* @__PURE__ */ new WeakMap(), _parser = /* @__PURE__ */ new WeakMap(), _onError = /* @__PURE__ */ new WeakMap(), _onMessage = /* @__PURE__ */ new WeakMap(), _onOpen = /* @__PURE__ */ new WeakMap(), _EventSource_instances = /* @__PURE__ */ new WeakSet(), /**
|
|
6395
|
-
* Connect to the given URL and start receiving events
|
|
6396
|
-
*
|
|
6397
|
-
* @internal
|
|
6398
|
-
*/
|
|
6399
|
-
connect_fn = function() {
|
|
6400
|
-
__privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _controller, new AbortController()), __privateGet(this, _fetch)(__privateGet(this, _url), __privateMethod(this, _EventSource_instances, getRequestOptions_fn).call(this)).then(__privateGet(this, _onFetchResponse)).catch(__privateGet(this, _onFetchError));
|
|
6401
|
-
}, _onFetchResponse = /* @__PURE__ */ new WeakMap(), _onFetchError = /* @__PURE__ */ new WeakMap(), /**
|
|
6402
|
-
* Get request options for the `fetch()` request
|
|
6403
|
-
*
|
|
6404
|
-
* @returns The request options
|
|
6405
|
-
* @internal
|
|
6406
|
-
*/
|
|
6407
|
-
getRequestOptions_fn = function() {
|
|
6408
|
-
var _a;
|
|
6409
|
-
const init2 = {
|
|
6410
|
-
// [spec] Let `corsAttributeState` be `Anonymous`…
|
|
6411
|
-
// [spec] …will have their mode set to "cors"…
|
|
6412
|
-
mode: "cors",
|
|
6413
|
-
redirect: "follow",
|
|
6414
|
-
headers: { Accept: "text/event-stream", ...__privateGet(this, _lastEventId) ? { "Last-Event-ID": __privateGet(this, _lastEventId) } : void 0 },
|
|
6415
|
-
cache: "no-store",
|
|
6416
|
-
signal: (_a = __privateGet(this, _controller)) == null ? void 0 : _a.signal
|
|
6417
|
-
};
|
|
6418
|
-
return "window" in globalThis && (init2.credentials = this.withCredentials ? "include" : "same-origin"), init2;
|
|
6419
|
-
}, _onEvent = /* @__PURE__ */ new WeakMap(), _onRetryChange = /* @__PURE__ */ new WeakMap(), /**
|
|
6420
|
-
* Handles the process referred to in the EventSource specification as "failing a connection".
|
|
6421
|
-
*
|
|
6422
|
-
* @param error - The error causing the connection to fail
|
|
6423
|
-
* @param code - The HTTP status code, if available
|
|
6424
|
-
* @internal
|
|
6425
|
-
*/
|
|
6426
|
-
failConnection_fn = function(message, code) {
|
|
6427
|
-
var _a;
|
|
6428
|
-
__privateGet(this, _readyState) !== this.CLOSED && __privateSet(this, _readyState, this.CLOSED);
|
|
6429
|
-
const errorEvent = new ErrorEvent("error", { code, message });
|
|
6430
|
-
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent);
|
|
6431
|
-
}, /**
|
|
6432
|
-
* Schedules a reconnection attempt against the EventSource endpoint.
|
|
6433
|
-
*
|
|
6434
|
-
* @param message - The error causing the connection to fail
|
|
6435
|
-
* @param code - The HTTP status code, if available
|
|
6436
|
-
* @internal
|
|
6437
|
-
*/
|
|
6438
|
-
scheduleReconnect_fn = function(message, code) {
|
|
6439
|
-
var _a;
|
|
6440
|
-
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
6441
|
-
return;
|
|
6442
|
-
__privateSet(this, _readyState, this.CONNECTING);
|
|
6443
|
-
const errorEvent = new ErrorEvent("error", { code, message });
|
|
6444
|
-
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent), __privateSet(this, _reconnectTimer, setTimeout(__privateGet(this, _reconnect), __privateGet(this, _reconnectInterval)));
|
|
6445
|
-
}, _reconnect = /* @__PURE__ */ new WeakMap(), /**
|
|
6446
|
-
* ReadyState representing an EventSource currently trying to connect
|
|
6447
|
-
*
|
|
6448
|
-
* @public
|
|
6449
|
-
*/
|
|
6450
|
-
EventSource.CONNECTING = 0, /**
|
|
6451
|
-
* ReadyState representing an EventSource connection that is open (eg connected)
|
|
6452
|
-
*
|
|
6453
|
-
* @public
|
|
6454
|
-
*/
|
|
6455
|
-
EventSource.OPEN = 1, /**
|
|
6456
|
-
* ReadyState representing an EventSource connection that is closed (eg disconnected)
|
|
6457
|
-
*
|
|
6458
|
-
* @public
|
|
6459
|
-
*/
|
|
6460
|
-
EventSource.CLOSED = 2;
|
|
6461
|
-
Object.defineProperty(EventSource, /* @__PURE__ */ Symbol.for("eventsource.supports-fetch-override"), {
|
|
6462
|
-
value: true,
|
|
6463
|
-
writable: false,
|
|
6464
|
-
configurable: false,
|
|
6465
|
-
enumerable: false
|
|
6466
|
-
});
|
|
6467
|
-
function getBaseURL() {
|
|
6468
|
-
const doc = "document" in globalThis ? globalThis.document : void 0;
|
|
6469
|
-
return doc && typeof doc == "object" && "baseURI" in doc && typeof doc.baseURI == "string" ? doc.baseURI : void 0;
|
|
6470
|
-
}
|
|
6471
|
-
|
|
6472
|
-
// src/client/channel.ts
|
|
6473
|
-
var channelClient = (baseUrl) => {
|
|
6474
|
-
const u = (p) => `${baseUrl}${p}`;
|
|
6475
|
-
const JSON_CT = { "content-type": "application/json" };
|
|
6476
|
-
const member = (channelId, name) => u(`/channels/${channelId}/members/${encodeURIComponent(name)}`);
|
|
6477
|
-
return {
|
|
6478
|
-
create: async (workspaceId, title, description, token) => {
|
|
6479
|
-
const res = await fetch(u(`/workspaces/${workspaceId}/channels`), {
|
|
6480
|
-
method: "POST",
|
|
6481
|
-
headers: { ...JSON_CT, ...token ? { authorization: `Bearer ${token}` } : {} },
|
|
6482
|
-
body: JSON.stringify({
|
|
6483
|
-
...title ? { title } : {},
|
|
6484
|
-
...description ? { description } : {}
|
|
6485
|
-
})
|
|
6486
|
-
});
|
|
6487
|
-
if (!res.ok)
|
|
6488
|
-
throw new Error(
|
|
6489
|
-
`POST /workspaces/${workspaceId}/channels \u2192 ${res.status}: ${await res.text()}`
|
|
6490
|
-
);
|
|
6491
|
-
return await res.json();
|
|
6492
|
-
},
|
|
6493
|
-
manifest: async (channelId) => {
|
|
6494
|
-
const res = await fetch(u(`/channels/${channelId}`));
|
|
6495
|
-
if (!res.ok) throw new Error(`GET channel \u2192 ${res.status}: ${await res.text()}`);
|
|
6496
|
-
return await res.json();
|
|
6497
|
-
},
|
|
6498
|
-
update: async (channelId, patch) => {
|
|
6499
|
-
const res = await fetch(u(`/channels/${channelId}`), {
|
|
6500
|
-
method: "PATCH",
|
|
6501
|
-
headers: JSON_CT,
|
|
6502
|
-
body: JSON.stringify(patch)
|
|
6503
|
-
});
|
|
6504
|
-
if (!res.ok) throw new Error(`PATCH channel \u2192 ${res.status}: ${await res.text()}`);
|
|
6505
|
-
return await res.json();
|
|
6506
|
-
},
|
|
6507
|
-
help: async () => {
|
|
6508
|
-
const res = await fetch(u("/channels/help"));
|
|
6509
|
-
if (!res.ok) throw new Error(`GET /channels/help \u2192 ${res.status}: ${await res.text()}`);
|
|
6510
|
-
return await res.text();
|
|
6511
|
-
},
|
|
6512
|
-
destroy: async (channelId) => {
|
|
6513
|
-
const res = await fetch(u(`/channels/${channelId}`), { method: "DELETE" });
|
|
6514
|
-
if (!res.ok) throw new Error(`DELETE channel \u2192 ${res.status}: ${await res.text()}`);
|
|
6515
|
-
},
|
|
6516
|
-
join: async (channelId, name, kind) => {
|
|
6517
|
-
const res = await fetch(member(channelId, name), {
|
|
6518
|
-
method: "PUT",
|
|
6519
|
-
headers: JSON_CT,
|
|
6520
|
-
body: JSON.stringify({ kind: kind ?? "agent" })
|
|
6521
|
-
});
|
|
6522
|
-
if (!res.ok) throw new Error(`join channel \u2192 ${res.status}: ${await res.text()}`);
|
|
6523
|
-
return (await res.json()).members;
|
|
6524
|
-
},
|
|
6525
|
-
leave: async (channelId, name) => {
|
|
6526
|
-
const res = await fetch(member(channelId, name), { method: "DELETE" });
|
|
6527
|
-
if (!res.ok) throw new Error(`leave channel \u2192 ${res.status}: ${await res.text()}`);
|
|
6528
|
-
},
|
|
6529
|
-
members: async (channelId) => {
|
|
6530
|
-
const res = await fetch(u(`/channels/${channelId}/members`));
|
|
6531
|
-
if (!res.ok) throw new Error(`GET members \u2192 ${res.status}: ${await res.text()}`);
|
|
6532
|
-
return (await res.json()).members;
|
|
6533
|
-
},
|
|
6534
|
-
send: async (channelId, msg) => {
|
|
6535
|
-
const res = await fetch(u(`/channels/${channelId}/messages`), {
|
|
6536
|
-
method: "POST",
|
|
6537
|
-
headers: JSON_CT,
|
|
6538
|
-
body: JSON.stringify(msg)
|
|
6539
|
-
});
|
|
6540
|
-
if (!res.ok) throw new Error(`POST channel message \u2192 ${res.status}: ${await res.text()}`);
|
|
6541
|
-
return await res.json();
|
|
6542
|
-
},
|
|
6543
|
-
uploadAttachment: async (channelId, input) => {
|
|
6544
|
-
const res = await fetch(
|
|
6545
|
-
u(`/channels/${channelId}/attachments?filename=${encodeURIComponent(input.filename)}`),
|
|
6546
|
-
{ method: "POST", headers: { "content-type": input.contentType }, body: input.body }
|
|
6547
|
-
);
|
|
6548
|
-
if (!res.ok) throw new Error(`upload attachment \u2192 ${res.status}: ${await res.text()}`);
|
|
6549
|
-
return await res.json();
|
|
6550
|
-
},
|
|
6551
|
-
downloadAttachment: async (channelId, attId) => {
|
|
6552
|
-
const res = await fetch(u(`/channels/${channelId}/attachments/${attId}`));
|
|
6553
|
-
if (!res.ok) throw new Error(`download attachment \u2192 ${res.status}: ${await res.text()}`);
|
|
6554
|
-
return res;
|
|
6555
|
-
},
|
|
6556
|
-
read: async (channelId, opts) => {
|
|
6557
|
-
const params = new URLSearchParams({ since: String(opts?.since ?? 0) });
|
|
6558
|
-
if (opts?.for) params.set("for", opts.for);
|
|
6559
|
-
const res = await fetch(u(`/channels/${channelId}/messages?${params}`));
|
|
6560
|
-
if (!res.ok) throw new Error(`GET messages \u2192 ${res.status}: ${await res.text()}`);
|
|
6561
|
-
return (await res.json()).messages;
|
|
6562
|
-
},
|
|
6563
|
-
listen: (channelId, opts) => {
|
|
6564
|
-
let cursor = opts.since ?? 0;
|
|
6565
|
-
const params = new URLSearchParams({ since: String(cursor) });
|
|
6566
|
-
if (opts.for) params.set("for", opts.for);
|
|
6567
|
-
if (opts.as) params.set("as", opts.as);
|
|
6568
|
-
const es = new EventSource(u(`/channels/${channelId}/stream?${params}`));
|
|
6569
|
-
es.onmessage = (e) => {
|
|
6570
|
-
try {
|
|
6571
|
-
const m = JSON.parse(e.data);
|
|
6572
|
-
if (m.seq <= cursor) return;
|
|
6573
|
-
cursor = m.seq;
|
|
6574
|
-
opts.onMessage(m);
|
|
6575
|
-
} catch (err) {
|
|
6576
|
-
opts.onError?.(err);
|
|
6577
|
-
}
|
|
6578
|
-
};
|
|
6579
|
-
es.onerror = (err) => opts.onError?.(err);
|
|
6580
|
-
return () => es.close();
|
|
6581
|
-
}
|
|
6582
|
-
};
|
|
6583
6056
|
};
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6057
|
+
var init = defineCommand({
|
|
6058
|
+
meta: {
|
|
6059
|
+
name: "init",
|
|
6060
|
+
description: `write ${PROJECT_CONFIG_NAME} in the current directory (local state, gitignored)`
|
|
6061
|
+
},
|
|
6588
6062
|
args: {
|
|
6589
|
-
|
|
6063
|
+
workspace: { type: "string", description: "workspace id (skip prompt)" },
|
|
6064
|
+
project: { type: "string", description: "project id (skip prompt)" },
|
|
6065
|
+
force: { type: "boolean", description: `overwrite existing ${PROJECT_CONFIG_NAME}` },
|
|
6590
6066
|
...common
|
|
6591
6067
|
},
|
|
6592
6068
|
run: async ({ args }) => {
|
|
6593
|
-
|
|
6594
|
-
|
|
6069
|
+
const server = resolveBaseUrl(args.url);
|
|
6070
|
+
const cfgPath = projectConfigPath();
|
|
6071
|
+
if (existsSync2(cfgPath) && !args.force)
|
|
6072
|
+
throw new Error(`${PROJECT_CONFIG_NAME} already exists. use --force to overwrite.`);
|
|
6073
|
+
const c = createClient(server);
|
|
6074
|
+
let project2;
|
|
6075
|
+
let workspace2;
|
|
6076
|
+
if (args.project) {
|
|
6077
|
+
project2 = await c.projects.get(Number(args.project));
|
|
6078
|
+
workspace2 = await c.workspaces.get(project2.workspaceId);
|
|
6079
|
+
} else {
|
|
6080
|
+
const wsList = await c.workspaces.list();
|
|
6081
|
+
workspace2 = args.workspace ? wsList.find((w) => w.id === Number(args.workspace)) ?? (() => {
|
|
6082
|
+
throw new Error(`workspace ${args.workspace} not found`);
|
|
6083
|
+
})() : await promptPick("workspace", wsList);
|
|
6084
|
+
const projects = await c.projects.listByWorkspace(workspace2.id);
|
|
6085
|
+
project2 = await promptPick("project", projects);
|
|
6086
|
+
}
|
|
6087
|
+
const cfg = {
|
|
6088
|
+
server,
|
|
6089
|
+
workspace: workspace2.id,
|
|
6090
|
+
project: project2.id,
|
|
6091
|
+
name: project2.name
|
|
6092
|
+
};
|
|
6093
|
+
saveProjectConfig(cfgPath, cfg);
|
|
6094
|
+
console.log(`wrote ${cfgPath}`);
|
|
6095
|
+
console.log(` server: ${server}`);
|
|
6096
|
+
console.log(` workspace: #${workspace2.id} ${workspace2.name}`);
|
|
6097
|
+
console.log(` project: #${project2.id} ${project2.name}`);
|
|
6595
6098
|
}
|
|
6596
6099
|
});
|
|
6597
6100
|
|
|
6598
|
-
// src/commands/
|
|
6599
|
-
var
|
|
6600
|
-
const
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
};
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
};
|
|
6609
|
-
var inviteBlock = (url, channelId) => {
|
|
6610
|
-
const web = webLink(url, channelId);
|
|
6611
|
-
return [
|
|
6612
|
-
"\u2500\u2500 Share this to invite anyone into the room \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
6613
|
-
...web ? [`Humans \u2014 open in a browser: ${web}`, ""] : [],
|
|
6614
|
-
"Agents \u2014 two curl steps:",
|
|
6615
|
-
` 1) see the room: curl -sS "${url}/channels/${channelId}"`,
|
|
6616
|
-
` 2) read protocol: curl -sS "${url}/channels/help" (then join / listen / send, pick your own NAME)`,
|
|
6617
|
-
"",
|
|
6618
|
-
`connection: url=${url} channel=${channelId}`,
|
|
6619
|
-
"\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
|
|
6620
|
-
].join("\n");
|
|
6101
|
+
// src/commands/session/shared.ts
|
|
6102
|
+
var resolveSession = async (client, projectId, handle) => {
|
|
6103
|
+
const asInt = Number(handle);
|
|
6104
|
+
if (Number.isInteger(asInt) && asInt > 0) {
|
|
6105
|
+
const byId = await client.sessions.get(asInt).catch(() => null);
|
|
6106
|
+
if (byId) return { id: byId.id, name: byId.name };
|
|
6107
|
+
}
|
|
6108
|
+
const byName = await client.sessions.findByName(projectId, handle);
|
|
6109
|
+
if (byName) return { id: byName.id, name: byName.name };
|
|
6110
|
+
throw new Error(`session "${handle}" not found in project ${projectId}`);
|
|
6621
6111
|
};
|
|
6622
6112
|
|
|
6623
|
-
// src/commands/
|
|
6624
|
-
var
|
|
6625
|
-
meta: {
|
|
6626
|
-
name: "create",
|
|
6627
|
-
description: "open a channel (chat room) in a workspace and print an invite"
|
|
6628
|
-
},
|
|
6113
|
+
// src/commands/loop/create.ts
|
|
6114
|
+
var loopCreateCommand = defineCommand({
|
|
6115
|
+
meta: { name: "create", description: "create a recurring scheduled message on a session" },
|
|
6629
6116
|
args: {
|
|
6630
|
-
|
|
6117
|
+
session: { type: "positional", required: true, description: "session int id or name" },
|
|
6118
|
+
message: {
|
|
6631
6119
|
type: "string",
|
|
6632
|
-
|
|
6120
|
+
required: true,
|
|
6121
|
+
description: "message sent to the session each beat"
|
|
6633
6122
|
},
|
|
6634
|
-
|
|
6635
|
-
desc: {
|
|
6123
|
+
every: {
|
|
6636
6124
|
type: "string",
|
|
6637
|
-
|
|
6125
|
+
required: true,
|
|
6126
|
+
description: "interval: 90s / 30m / 2h / 1d (min 30s)"
|
|
6638
6127
|
},
|
|
6128
|
+
name: { type: "string", description: "optional label" },
|
|
6129
|
+
off: { type: "boolean", description: "create paused (disabled)" },
|
|
6130
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
6639
6131
|
...common
|
|
6640
6132
|
},
|
|
6641
6133
|
run: async ({ args }) => {
|
|
6642
|
-
const
|
|
6643
|
-
const
|
|
6644
|
-
const
|
|
6645
|
-
|
|
6646
|
-
args.
|
|
6647
|
-
args.
|
|
6648
|
-
|
|
6649
|
-
);
|
|
6650
|
-
|
|
6651
|
-
console.log(toJson({ channelId, url, workspaceId, name: args.name, description: args.desc }));
|
|
6652
|
-
return;
|
|
6653
|
-
}
|
|
6654
|
-
console.log(`channel ${channelId} opened in workspace ${workspaceId}
|
|
6655
|
-
`);
|
|
6656
|
-
console.log(inviteBlock(url, channelId));
|
|
6134
|
+
const c = clientFor(args);
|
|
6135
|
+
const session2 = await resolveSession(c, resolveProjectId(args), args.session);
|
|
6136
|
+
const loop2 = await c.loops.create(session2.id, {
|
|
6137
|
+
message: args.message,
|
|
6138
|
+
intervalSec: parseDuration(args.every),
|
|
6139
|
+
name: args.name,
|
|
6140
|
+
enabled: !args.off
|
|
6141
|
+
});
|
|
6142
|
+
console.log(renderOne(loop2, fmtLoop, Boolean(args.json)));
|
|
6657
6143
|
}
|
|
6658
6144
|
});
|
|
6659
6145
|
|
|
6660
|
-
// src/commands/
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
meta: { name: "download", description: "download a channel attachment to a file" },
|
|
6146
|
+
// src/commands/loop/disable.ts
|
|
6147
|
+
var loopDisableCommand = defineCommand({
|
|
6148
|
+
meta: { name: "disable", description: "disable (pause) a loop" },
|
|
6664
6149
|
args: {
|
|
6665
|
-
|
|
6666
|
-
att: { type: "positional", required: true, description: "attachment id (from a message ref)" },
|
|
6667
|
-
out: { type: "string", alias: "o", description: "output file path (default: ./<attId>)" },
|
|
6150
|
+
loop: { type: "positional", required: true, description: "loop int id" },
|
|
6668
6151
|
...common
|
|
6669
6152
|
},
|
|
6670
6153
|
run: async ({ args }) => {
|
|
6671
|
-
const
|
|
6672
|
-
const
|
|
6673
|
-
|
|
6674
|
-
writeFileSync2(out, Buffer.from(await res.arrayBuffer()));
|
|
6675
|
-
console.log(`saved \u2192 ${out}`);
|
|
6154
|
+
const c = clientFor(args);
|
|
6155
|
+
const loop2 = await c.loops.update(Number(args.loop), { enabled: false });
|
|
6156
|
+
console.log(renderOne(loop2, fmtLoop, Boolean(args.json)));
|
|
6676
6157
|
}
|
|
6677
6158
|
});
|
|
6678
6159
|
|
|
6679
|
-
// src/commands/
|
|
6680
|
-
var
|
|
6681
|
-
meta: { name: "
|
|
6160
|
+
// src/commands/loop/enable.ts
|
|
6161
|
+
var loopEnableCommand = defineCommand({
|
|
6162
|
+
meta: { name: "enable", description: "enable (resume) a loop" },
|
|
6682
6163
|
args: {
|
|
6683
|
-
|
|
6164
|
+
loop: { type: "positional", required: true, description: "loop int id" },
|
|
6684
6165
|
...common
|
|
6685
6166
|
},
|
|
6686
6167
|
run: async ({ args }) => {
|
|
6687
|
-
const
|
|
6688
|
-
const
|
|
6689
|
-
|
|
6690
|
-
console.log(toJson(m));
|
|
6691
|
-
return;
|
|
6692
|
-
}
|
|
6693
|
-
console.log(`${m.title ?? "(untitled)"} [${m.id}]`);
|
|
6694
|
-
if (m.description) console.log(m.description);
|
|
6695
|
-
console.log(`
|
|
6696
|
-
online (${m.members.length}):
|
|
6697
|
-
${renderRoster(m.members)}`);
|
|
6698
|
-
console.log(`
|
|
6699
|
-
protocol: curl -sS "${url}${m.help}"`);
|
|
6168
|
+
const c = clientFor(args);
|
|
6169
|
+
const loop2 = await c.loops.update(Number(args.loop), { enabled: true });
|
|
6170
|
+
console.log(renderOne(loop2, fmtLoop, Boolean(args.json)));
|
|
6700
6171
|
}
|
|
6701
6172
|
});
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6173
|
+
|
|
6174
|
+
// src/commands/loop/get.ts
|
|
6175
|
+
var loopGetCommand = defineCommand({
|
|
6176
|
+
meta: { name: "get", description: "show one loop" },
|
|
6177
|
+
args: {
|
|
6178
|
+
loop: { type: "positional", required: true, description: "loop int id" },
|
|
6179
|
+
...common
|
|
6180
|
+
},
|
|
6705
6181
|
run: async ({ args }) => {
|
|
6706
|
-
|
|
6182
|
+
const c = clientFor(args);
|
|
6183
|
+
const loop2 = await c.loops.get(Number(args.loop));
|
|
6184
|
+
console.log(renderOne(loop2, fmtLoop, Boolean(args.json)));
|
|
6707
6185
|
}
|
|
6708
6186
|
});
|
|
6709
|
-
|
|
6710
|
-
|
|
6187
|
+
|
|
6188
|
+
// src/commands/loop/ls.ts
|
|
6189
|
+
var loopLsCommand = defineCommand({
|
|
6190
|
+
meta: { name: "ls", description: "list a session's loops" },
|
|
6711
6191
|
args: {
|
|
6712
|
-
|
|
6192
|
+
session: { type: "positional", required: true, description: "session int id or name" },
|
|
6193
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
6713
6194
|
...common
|
|
6714
6195
|
},
|
|
6715
6196
|
run: async ({ args }) => {
|
|
6716
|
-
const
|
|
6717
|
-
const
|
|
6718
|
-
|
|
6197
|
+
const c = clientFor(args);
|
|
6198
|
+
const session2 = await resolveSession(c, resolveProjectId(args), args.session);
|
|
6199
|
+
const loops = await c.loops.listBySession(session2.id);
|
|
6200
|
+
console.log(renderList(loops, fmtLoop, Boolean(args.json)));
|
|
6719
6201
|
}
|
|
6720
6202
|
});
|
|
6721
|
-
|
|
6722
|
-
|
|
6203
|
+
|
|
6204
|
+
// src/commands/loop/rm.ts
|
|
6205
|
+
var loopRmCommand = defineCommand({
|
|
6206
|
+
meta: { name: "rm", description: "delete a loop" },
|
|
6723
6207
|
args: {
|
|
6724
|
-
|
|
6725
|
-
title: { type: "string", description: "new title" },
|
|
6726
|
-
desc: { type: "string", description: "new description (purpose / topic / rules)" },
|
|
6208
|
+
loop: { type: "positional", required: true, description: "loop int id" },
|
|
6727
6209
|
...common
|
|
6728
6210
|
},
|
|
6729
6211
|
run: async ({ args }) => {
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6212
|
+
const c = clientFor(args);
|
|
6213
|
+
const id = Number(args.loop);
|
|
6214
|
+
await c.loops.remove(id);
|
|
6215
|
+
console.log(removed("loop", id, Boolean(args.json)));
|
|
6216
|
+
}
|
|
6217
|
+
});
|
|
6218
|
+
|
|
6219
|
+
// src/commands/loop/set.ts
|
|
6220
|
+
var loopSetCommand = defineCommand({
|
|
6221
|
+
meta: { name: "set", description: "update a loop (message / interval / name)" },
|
|
6222
|
+
args: {
|
|
6223
|
+
loop: { type: "positional", required: true, description: "loop int id" },
|
|
6224
|
+
message: { type: "string", description: "new message" },
|
|
6225
|
+
every: { type: "string", description: "new interval: 90s / 30m / 2h / 1d" },
|
|
6226
|
+
name: { type: "string", description: "new label" },
|
|
6227
|
+
...common
|
|
6228
|
+
},
|
|
6229
|
+
run: async ({ args }) => {
|
|
6230
|
+
const c = clientFor(args);
|
|
6231
|
+
const patch = {};
|
|
6232
|
+
if (args.message !== void 0) patch.message = args.message;
|
|
6233
|
+
if (args.every !== void 0 && args.every !== "") patch.intervalSec = parseDuration(args.every);
|
|
6234
|
+
if (args.name !== void 0) patch.name = args.name;
|
|
6235
|
+
const loop2 = await c.loops.update(Number(args.loop), patch);
|
|
6236
|
+
console.log(renderOne(loop2, fmtLoop, Boolean(args.json)));
|
|
6237
|
+
}
|
|
6238
|
+
});
|
|
6239
|
+
|
|
6240
|
+
// src/commands/loop.ts
|
|
6241
|
+
var loop = defineCommand({
|
|
6242
|
+
meta: { name: "loop", description: "recurring scheduled messages that wake a session" },
|
|
6243
|
+
subCommands: {
|
|
6244
|
+
create: loopCreateCommand,
|
|
6245
|
+
ls: loopLsCommand,
|
|
6246
|
+
get: loopGetCommand,
|
|
6247
|
+
set: loopSetCommand,
|
|
6248
|
+
enable: loopEnableCommand,
|
|
6249
|
+
disable: loopDisableCommand,
|
|
6250
|
+
rm: loopRmCommand
|
|
6251
|
+
}
|
|
6252
|
+
});
|
|
6253
|
+
|
|
6254
|
+
// src/commands/notify.ts
|
|
6255
|
+
var describe = (result) => {
|
|
6256
|
+
if (result.status === "sent") return `notified ${result.devices} device(s)`;
|
|
6257
|
+
if (result.status === "throttled")
|
|
6258
|
+
return `throttled: this session can notify again in ${result.retryAfterSec}s`;
|
|
6259
|
+
return "nobody to notify: no human has messaged this session, or they have not enabled notifications";
|
|
6260
|
+
};
|
|
6261
|
+
var notify = defineCommand({
|
|
6262
|
+
meta: {
|
|
6263
|
+
name: "notify",
|
|
6264
|
+
description: "Push a phone notification to the person working with this session. Use it only when a human needs to act now: something is wrong, a decision is needed, or the work is blocked. Do not use it for routine progress, and not to announce that a turn finished (that is already pushed). At most one notification per session every 10 minutes; text is cut at 200 characters."
|
|
6265
|
+
},
|
|
6266
|
+
args: {
|
|
6267
|
+
text: { type: "positional", required: true, description: "one short line for the lock screen" },
|
|
6268
|
+
...common
|
|
6269
|
+
},
|
|
6270
|
+
run: async ({ args }) => {
|
|
6271
|
+
const raw = process.env.BATON_SESSION_ID;
|
|
6272
|
+
if (raw === void 0)
|
|
6273
|
+
throw new Error("baton notify only works inside a baton session (BATON_SESSION_ID is unset)");
|
|
6274
|
+
const sessionId = Number(raw);
|
|
6275
|
+
if (!Number.isSafeInteger(sessionId) || sessionId <= 0)
|
|
6276
|
+
throw new Error("invalid BATON_SESSION_ID");
|
|
6277
|
+
const result = await clientFor(args).sessions.notify(sessionId, args.text);
|
|
6278
|
+
console.log(args.json ? toJson(result) : describe(result));
|
|
6279
|
+
}
|
|
6280
|
+
});
|
|
6281
|
+
|
|
6282
|
+
// src/commands/project.ts
|
|
6283
|
+
var createProject = (c, input, json) => c.projects.create(input).then((p) => renderOne(p, fmtProject, json));
|
|
6284
|
+
var listProjects = (c, workspaceId, json) => c.projects.listByWorkspace(workspaceId).then((ps) => renderList(ps, fmtProject, json));
|
|
6285
|
+
var getProject = (c, id, json) => c.projects.get(id).then((p) => renderOne(p, fmtProject, json));
|
|
6286
|
+
var updateProject = (c, id, patch, json) => c.projects.update(id, patch).then((p) => renderOne(p, fmtProject, json));
|
|
6287
|
+
var removeProject = (c, id, json) => c.projects.remove(id).then(() => removed("project", id, json));
|
|
6288
|
+
var project = defineCommand({
|
|
6289
|
+
meta: { name: "project", description: "manage projects" },
|
|
6290
|
+
subCommands: {
|
|
6291
|
+
create: defineCommand({
|
|
6292
|
+
meta: { name: "create", description: "create a project" },
|
|
6293
|
+
args: {
|
|
6294
|
+
name: { type: "positional", required: true },
|
|
6295
|
+
workspace: { type: "string", description: "workspace id (overrides .baton.json)" },
|
|
6296
|
+
desc: { type: "string", description: "description" },
|
|
6297
|
+
...common
|
|
6298
|
+
},
|
|
6299
|
+
run: async ({ args }) => {
|
|
6300
|
+
const out = await createProject(
|
|
6301
|
+
clientFor(args),
|
|
6302
|
+
{ workspaceId: resolveWorkspaceId(args), name: args.name, description: args.desc },
|
|
6303
|
+
Boolean(args.json)
|
|
6304
|
+
);
|
|
6305
|
+
console.log(out);
|
|
6306
|
+
}
|
|
6307
|
+
}),
|
|
6308
|
+
ls: defineCommand({
|
|
6309
|
+
meta: { name: "ls", description: "list projects in a workspace" },
|
|
6310
|
+
args: {
|
|
6311
|
+
workspace: { type: "string", description: "workspace id (overrides .baton.json)" },
|
|
6312
|
+
...common
|
|
6313
|
+
},
|
|
6314
|
+
run: async ({ args }) => {
|
|
6315
|
+
console.log(
|
|
6316
|
+
await listProjects(clientFor(args), resolveWorkspaceId(args), Boolean(args.json))
|
|
6317
|
+
);
|
|
6318
|
+
}
|
|
6319
|
+
}),
|
|
6320
|
+
get: defineCommand({
|
|
6321
|
+
meta: { name: "get", description: "get a project" },
|
|
6322
|
+
args: { id: { type: "positional", required: true }, ...common },
|
|
6323
|
+
run: async ({ args }) => {
|
|
6324
|
+
console.log(await getProject(clientFor(args), Number(args.id), Boolean(args.json)));
|
|
6325
|
+
}
|
|
6326
|
+
}),
|
|
6327
|
+
update: defineCommand({
|
|
6328
|
+
meta: { name: "update", description: "rename a project / set its description" },
|
|
6329
|
+
args: {
|
|
6330
|
+
id: { type: "positional", required: true },
|
|
6331
|
+
name: { type: "string", description: "new name" },
|
|
6332
|
+
desc: { type: "string", description: "new description" },
|
|
6333
|
+
...common
|
|
6334
|
+
},
|
|
6335
|
+
run: async ({ args }) => {
|
|
6336
|
+
const patch = {
|
|
6337
|
+
...args.name !== void 0 ? { name: args.name } : {},
|
|
6338
|
+
...args.desc !== void 0 ? { description: args.desc } : {}
|
|
6339
|
+
};
|
|
6340
|
+
if (Object.keys(patch).length === 0) throw new Error("pass --name and/or --desc");
|
|
6341
|
+
console.log(
|
|
6342
|
+
await updateProject(clientFor(args), Number(args.id), patch, Boolean(args.json))
|
|
6343
|
+
);
|
|
6344
|
+
}
|
|
6345
|
+
}),
|
|
6346
|
+
rm: defineCommand({
|
|
6347
|
+
meta: { name: "rm", description: "delete a project" },
|
|
6348
|
+
args: { id: { type: "positional", required: true }, ...common },
|
|
6349
|
+
run: async ({ args }) => {
|
|
6350
|
+
console.log(await removeProject(clientFor(args), Number(args.id), Boolean(args.json)));
|
|
6351
|
+
}
|
|
6352
|
+
})
|
|
6738
6353
|
}
|
|
6739
6354
|
});
|
|
6740
6355
|
|
|
6741
|
-
// src/
|
|
6742
|
-
import {
|
|
6743
|
-
import {
|
|
6744
|
-
import {
|
|
6356
|
+
// src/provisioner/config.ts
|
|
6357
|
+
import { execFile } from "node:child_process";
|
|
6358
|
+
import { constants } from "node:fs";
|
|
6359
|
+
import { access, readFile, stat as stat2 } from "node:fs/promises";
|
|
6360
|
+
import { isAbsolute } from "node:path";
|
|
6361
|
+
import { promisify } from "node:util";
|
|
6745
6362
|
|
|
6746
6363
|
// ../shared/src/domain/attachment.ts
|
|
6747
6364
|
var labelAttachments = (attachments) => {
|
|
@@ -6753,9 +6370,6 @@ var labelAttachments = (attachments) => {
|
|
|
6753
6370
|
});
|
|
6754
6371
|
};
|
|
6755
6372
|
|
|
6756
|
-
// ../shared/src/domain/channel.ts
|
|
6757
|
-
var isMessageFor = (msg, name) => !msg.to || msg.to.length === 0 || msg.to.includes(name);
|
|
6758
|
-
|
|
6759
6373
|
// ../shared/src/domain/file.ts
|
|
6760
6374
|
var FILE_TEXT_MAX_BYTES = 5 * 1024 * 1024;
|
|
6761
6375
|
var FILE_DIRECTORY_MAX_ENTRIES = 2e3;
|
|
@@ -6799,738 +6413,650 @@ var normalizeFilePath = (value, allowRoot = false) => {
|
|
|
6799
6413
|
var SENSITIVE_SEGMENTS = /* @__PURE__ */ new Set([".git", ".ssh", ".aws", ".kube", ".gnupg"]);
|
|
6800
6414
|
var SENSITIVE_NAMES = /* @__PURE__ */ new Set([
|
|
6801
6415
|
".baton.json",
|
|
6802
|
-
".envrc",
|
|
6803
|
-
".npmrc",
|
|
6804
|
-
".netrc",
|
|
6805
|
-
".pypirc",
|
|
6806
|
-
".git-credentials",
|
|
6807
|
-
".pgpass",
|
|
6808
|
-
".htpasswd",
|
|
6809
|
-
".credentials.json"
|
|
6810
|
-
]);
|
|
6811
|
-
var SENSITIVE_EXTENSIONS = [".pem", ".key", ".p12", ".pfx", ".jks", ".keystore"];
|
|
6812
|
-
var isSensitiveName = (name) => SENSITIVE_NAMES.has(name) || /^\.env(\..+)?$/.test(name) && !/\.(example|sample|template)$/.test(name) || /^id_(rsa|dsa|ecdsa|ed25519)$/.test(name) || SENSITIVE_EXTENSIONS.some((extension2) => name.endsWith(extension2));
|
|
6813
|
-
var isSensitiveFilePath = (path) => {
|
|
6814
|
-
const segments = path.toLowerCase().split("/");
|
|
6815
|
-
return segments.some((segment) => SENSITIVE_SEGMENTS.has(segment)) || isSensitiveName(segments.at(-1) ?? "");
|
|
6816
|
-
};
|
|
6817
|
-
var EXCLUDED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
6818
|
-
"node_modules",
|
|
6819
|
-
".pnpm-store",
|
|
6820
|
-
"dist",
|
|
6821
|
-
"build",
|
|
6822
|
-
"coverage",
|
|
6823
|
-
".next",
|
|
6824
|
-
".turbo",
|
|
6825
|
-
".cache",
|
|
6826
|
-
".venv",
|
|
6827
|
-
"__pycache__",
|
|
6828
|
-
"target"
|
|
6829
|
-
]);
|
|
6830
|
-
var isExcludedDirectoryName = (name) => EXCLUDED_DIRECTORIES.has(name);
|
|
6831
|
-
|
|
6832
|
-
// ../shared/src/domain/service.ts
|
|
6833
|
-
var SERVICE_PUBLIC_URL_MAX_LENGTH = 2048;
|
|
6834
|
-
var SERVICE_NOTE_MAX_LENGTH = 500;
|
|
6835
|
-
var isServicePublicUrl = (value) => {
|
|
6836
|
-
if (value.length === 0 || value.length > SERVICE_PUBLIC_URL_MAX_LENGTH) return false;
|
|
6837
|
-
try {
|
|
6838
|
-
const url = new URL(value);
|
|
6839
|
-
return url.protocol === "http:" || url.protocol === "https:";
|
|
6840
|
-
} catch {
|
|
6841
|
-
return false;
|
|
6842
|
-
}
|
|
6843
|
-
};
|
|
6844
|
-
var isServiceNote = (value) => value.length > 0 && value.length <= SERVICE_NOTE_MAX_LENGTH;
|
|
6845
|
-
|
|
6846
|
-
// ../shared/src/domain/session.ts
|
|
6847
|
-
var AGENT_KINDS = ["claude-code", "codex", "pi"];
|
|
6848
|
-
var isAgentKind = (v) => typeof v === "string" && AGENT_KINDS.includes(v);
|
|
6849
|
-
var EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"];
|
|
6850
|
-
var isAgentEffort = (v) => typeof v === "string" && EFFORTS.includes(v);
|
|
6851
|
-
|
|
6852
|
-
// ../shared/src/domain/session-event.ts
|
|
6853
|
-
var agentMessageText = (payload) => {
|
|
6854
|
-
if (typeof payload !== "object" || payload === null) return null;
|
|
6855
|
-
const event = payload;
|
|
6856
|
-
if (!["item.started", "item.updated", "item.completed"].includes(String(event.type))) return null;
|
|
6857
|
-
const item = event.item;
|
|
6858
|
-
if (typeof item !== "object" || item === null) return null;
|
|
6859
|
-
const { type, id, text } = item;
|
|
6860
|
-
if (type !== "agent_message" || typeof id !== "string" || typeof text !== "string") return null;
|
|
6861
|
-
const trimmed = text.trim();
|
|
6862
|
-
return trimmed ? { id, text: trimmed } : null;
|
|
6863
|
-
};
|
|
6864
|
-
|
|
6865
|
-
// ../shared/src/domain/worker-creation.ts
|
|
6866
|
-
var WORKER_TEMPLATES = [
|
|
6867
|
-
{ id: "mini-glm-codeplan", name: "GLM Code Plan", agentKinds: ["claude-code", "pi"] },
|
|
6868
|
-
{ id: "mini-dashscope-codeplan", name: "DashScope Code Plan", agentKinds: ["claude-code", "pi"] },
|
|
6869
|
-
{ id: "mini-codex", name: "\u672C\u673A Codex", agentKinds: ["codex"] }
|
|
6870
|
-
];
|
|
6871
|
-
var workerTemplateAgentKinds = (id) => id === "mini-local" ? AGENT_KINDS : WORKER_TEMPLATES.find((template) => template.id === id)?.agentKinds ?? [];
|
|
6872
|
-
var isWorkerTemplateId = (value) => typeof value === "string" && workerTemplateAgentKinds(value).length > 0;
|
|
6873
|
-
|
|
6874
|
-
// src/commands/channel/listen.ts
|
|
6875
|
-
var PREVIEW = 280;
|
|
6876
|
-
var describe = (e) => {
|
|
6877
|
-
const ev = e;
|
|
6878
|
-
return ev?.code ? `${ev.code}${ev.message ? ` ${ev.message}` : ""}` : String(e);
|
|
6879
|
-
};
|
|
6880
|
-
var runListen = async (o) => {
|
|
6881
|
-
const emit = (x) => {
|
|
6882
|
-
process.stdout.write(`${JSON.stringify(x)}
|
|
6883
|
-
`);
|
|
6884
|
-
};
|
|
6885
|
-
const spillDir = join2(tmpdir(), "channel", o.channel);
|
|
6886
|
-
mkdirSync(spillDir, { recursive: true });
|
|
6887
|
-
const surface = (m) => {
|
|
6888
|
-
const text = typeof m.text === "string" ? m.text : "";
|
|
6889
|
-
const file = join2(spillDir, `${m.seq}.txt`);
|
|
6890
|
-
writeFileSync3(file, text);
|
|
6891
|
-
const truncated = text.length > PREVIEW;
|
|
6892
|
-
emit({
|
|
6893
|
-
type: "channel.message",
|
|
6894
|
-
seq: m.seq,
|
|
6895
|
-
from: m.from,
|
|
6896
|
-
senderKind: m.senderKind,
|
|
6897
|
-
to: m.to,
|
|
6898
|
-
mine: o.from ? isMessageFor(m, o.from) : void 0,
|
|
6899
|
-
ts: m.ts,
|
|
6900
|
-
chars: text.length,
|
|
6901
|
-
truncated,
|
|
6902
|
-
preview: truncated ? `${text.slice(0, PREVIEW)} \u2026` : text,
|
|
6903
|
-
// BASE-prefixed urls so the subscribing agent can fetch directly.
|
|
6904
|
-
attachments: m.attachments?.length ? m.attachments.map((a) => ({
|
|
6905
|
-
filename: a.filename,
|
|
6906
|
-
contentType: a.contentType,
|
|
6907
|
-
size: a.size,
|
|
6908
|
-
url: `${o.url}${a.url}`
|
|
6909
|
-
})) : void 0,
|
|
6910
|
-
file
|
|
6911
|
-
});
|
|
6912
|
-
};
|
|
6913
|
-
const close = channelClient(o.url).listen(o.channel, {
|
|
6914
|
-
since: o.since,
|
|
6915
|
-
for: o.for,
|
|
6916
|
-
as: o.from,
|
|
6917
|
-
// Skip our own messages (they echo back over the same channel).
|
|
6918
|
-
onMessage: (m) => {
|
|
6919
|
-
if (m.from !== o.from) surface(m);
|
|
6920
|
-
},
|
|
6921
|
-
onError: (e) => emit({ type: "channel.error", error: describe(e) })
|
|
6922
|
-
});
|
|
6923
|
-
emit({ type: "channel.listening", channel: o.channel, from: o.from, url: o.url });
|
|
6924
|
-
await new Promise((resolve4) => {
|
|
6925
|
-
const stop = () => {
|
|
6926
|
-
close();
|
|
6927
|
-
resolve4();
|
|
6928
|
-
};
|
|
6929
|
-
process.on("SIGINT", stop);
|
|
6930
|
-
process.on("SIGTERM", stop);
|
|
6931
|
-
});
|
|
6932
|
-
};
|
|
6933
|
-
var listenCommand = defineCommand({
|
|
6934
|
-
meta: {
|
|
6935
|
-
name: "listen",
|
|
6936
|
-
description: "stream a channel: one JSON line per message (for a background subscriber)"
|
|
6937
|
-
},
|
|
6938
|
-
args: {
|
|
6939
|
-
channel: { type: "positional", required: true, description: "channel id" },
|
|
6940
|
-
from: {
|
|
6941
|
-
type: "string",
|
|
6942
|
-
description: "your name; your own messages skipped, presence kept fresh"
|
|
6943
|
-
},
|
|
6944
|
-
since: { type: "string", description: "replay messages after this seq (default 0 = full)" },
|
|
6945
|
-
for: { type: "string", description: "only broadcasts + messages addressed to this name" },
|
|
6946
|
-
...common
|
|
6947
|
-
},
|
|
6948
|
-
run: async ({ args }) => {
|
|
6949
|
-
await runListen({
|
|
6950
|
-
url: resolveBaseUrl(args.url),
|
|
6951
|
-
channel: args.channel,
|
|
6952
|
-
from: args.from ?? "",
|
|
6953
|
-
since: args.since ? Number(args.since) : 0,
|
|
6954
|
-
for: args.for
|
|
6955
|
-
});
|
|
6956
|
-
}
|
|
6957
|
-
});
|
|
6958
|
-
|
|
6959
|
-
// src/commands/channel/join.ts
|
|
6960
|
-
var joinCommand = defineCommand({
|
|
6961
|
-
meta: {
|
|
6962
|
-
name: "join",
|
|
6963
|
-
description: "join a channel (register presence); --listen to also stream"
|
|
6964
|
-
},
|
|
6965
|
-
args: {
|
|
6966
|
-
channel: { type: "positional", required: true, description: "channel id" },
|
|
6967
|
-
from: { type: "string", required: true, description: "your participant name" },
|
|
6968
|
-
kind: { type: "string", description: "your kind: agent (default) | human" },
|
|
6969
|
-
listen: {
|
|
6970
|
-
type: "boolean",
|
|
6971
|
-
description: "after joining, stream messages (background subscriber)"
|
|
6972
|
-
},
|
|
6973
|
-
since: { type: "string", description: "with --listen: replay after this seq (default 0)" },
|
|
6974
|
-
...common
|
|
6975
|
-
},
|
|
6976
|
-
run: async ({ args }) => {
|
|
6977
|
-
const url = resolveBaseUrl(args.url);
|
|
6978
|
-
const kind = args.kind === "human" ? "human" : "agent";
|
|
6979
|
-
const members = await channelClient(url).join(args.channel, args.from, kind);
|
|
6980
|
-
if (!args.listen) {
|
|
6981
|
-
if (args.json) console.log(toJson({ joined: args.from, members }));
|
|
6982
|
-
else
|
|
6983
|
-
console.log(`joined as ${args.from} (${members.length} online)
|
|
6984
|
-
${renderRoster(members)}`);
|
|
6985
|
-
return;
|
|
6986
|
-
}
|
|
6987
|
-
await runListen({
|
|
6988
|
-
url,
|
|
6989
|
-
channel: args.channel,
|
|
6990
|
-
from: args.from,
|
|
6991
|
-
since: args.since ? Number(args.since) : 0
|
|
6992
|
-
});
|
|
6993
|
-
}
|
|
6994
|
-
});
|
|
6995
|
-
|
|
6996
|
-
// src/commands/channel/read.ts
|
|
6997
|
-
var fmtMessage = (m, base) => {
|
|
6998
|
-
const head = `${m.seq} ${m.from} ${m.text}`;
|
|
6999
|
-
const atts = (m.attachments ?? []).map((a) => `
|
|
7000
|
-
\u{1F4CE} ${a.filename} \u2192 ${base}${a.url}`).join("");
|
|
7001
|
-
return head + atts;
|
|
7002
|
-
};
|
|
7003
|
-
var readCommand = defineCommand({
|
|
7004
|
-
meta: { name: "read", description: "poll channel messages once (curl-style, since a cursor)" },
|
|
7005
|
-
args: {
|
|
7006
|
-
channel: { type: "positional", required: true, description: "channel id" },
|
|
7007
|
-
since: { type: "string", description: "only messages after this seq (default 0)" },
|
|
7008
|
-
from: { type: "string", description: "skip messages from this name (no echo)" },
|
|
7009
|
-
for: { type: "string", description: "only broadcasts + messages addressed to this name" },
|
|
7010
|
-
...common
|
|
7011
|
-
},
|
|
7012
|
-
run: async ({ args }) => {
|
|
7013
|
-
const url = resolveBaseUrl(args.url);
|
|
7014
|
-
const msgs = await channelClient(url).read(args.channel, {
|
|
7015
|
-
since: args.since ? Number(args.since) : 0,
|
|
7016
|
-
for: args.for
|
|
7017
|
-
});
|
|
7018
|
-
const out = args.from ? msgs.filter((m) => m.from !== args.from) : msgs;
|
|
7019
|
-
if (args.json) console.log(toJson(out));
|
|
7020
|
-
else console.log(out.length ? out.map((m) => fmtMessage(m, url)).join("\n") : "(none)");
|
|
7021
|
-
}
|
|
7022
|
-
});
|
|
7023
|
-
|
|
7024
|
-
// src/commands/channel/send.ts
|
|
7025
|
-
import { openAsBlob as openAsBlob3, readFileSync as readFileSync2 } from "node:fs";
|
|
7026
|
-
import { basename as basename3 } from "node:path";
|
|
7027
|
-
|
|
7028
|
-
// src/commands/attach.ts
|
|
7029
|
-
import { openAsBlob as openAsBlob2 } from "node:fs";
|
|
7030
|
-
import { basename as basename2 } from "node:path";
|
|
7031
|
-
var attachPaths = (raw) => (raw === void 0 ? [] : Array.isArray(raw) ? raw : [raw]).flatMap((p) => p.split(",")).map((p) => p.trim()).filter(Boolean);
|
|
7032
|
-
var uploadAttachments = async (client, sessionId, paths) => {
|
|
7033
|
-
const out = [];
|
|
7034
|
-
for (const path of paths) {
|
|
7035
|
-
const body = await openAsBlob2(path, { type: contentTypeForPath(path) });
|
|
7036
|
-
out.push(
|
|
7037
|
-
await client.sessions.uploadAttachment(sessionId, {
|
|
7038
|
-
filename: basename2(path),
|
|
7039
|
-
contentType: contentTypeForPath(path),
|
|
7040
|
-
body
|
|
7041
|
-
})
|
|
7042
|
-
);
|
|
7043
|
-
}
|
|
7044
|
-
return out;
|
|
7045
|
-
};
|
|
7046
|
-
|
|
7047
|
-
// src/commands/channel/send.ts
|
|
7048
|
-
var sendCommand = defineCommand({
|
|
7049
|
-
meta: { name: "send", description: "post one message to a channel" },
|
|
7050
|
-
args: {
|
|
7051
|
-
channel: { type: "positional", required: true, description: "channel id" },
|
|
7052
|
-
text: { type: "positional", required: false, description: "message text (short one-liner)" },
|
|
7053
|
-
from: { type: "string", description: "your participant name (default: peer)" },
|
|
7054
|
-
to: {
|
|
7055
|
-
type: "string",
|
|
7056
|
-
description: "direct it at these names (comma-separated); omit = broadcast"
|
|
7057
|
-
},
|
|
7058
|
-
file: { type: "string", description: "read message body from this file (for large content)" },
|
|
7059
|
-
attach: {
|
|
7060
|
-
type: "string",
|
|
7061
|
-
description: "attach file(s) (comma-separated paths); uploaded + carried on the message"
|
|
7062
|
-
},
|
|
7063
|
-
...common
|
|
7064
|
-
},
|
|
7065
|
-
run: async ({ args }) => {
|
|
7066
|
-
const url = resolveBaseUrl(args.url);
|
|
7067
|
-
const client = channelClient(url);
|
|
7068
|
-
let text = args.text;
|
|
7069
|
-
if (text === void 0 && args.file) text = readFileSync2(args.file, "utf8");
|
|
7070
|
-
if (text === void 0 && !process.stdin.isTTY) text = await readStdin();
|
|
7071
|
-
const attachments = [];
|
|
7072
|
-
for (const path of attachPaths(args.attach)) {
|
|
7073
|
-
attachments.push(
|
|
7074
|
-
await client.uploadAttachment(args.channel, {
|
|
7075
|
-
filename: basename3(path),
|
|
7076
|
-
contentType: contentTypeForPath(path),
|
|
7077
|
-
body: await openAsBlob3(path, { type: contentTypeForPath(path) })
|
|
7078
|
-
})
|
|
7079
|
-
);
|
|
7080
|
-
}
|
|
7081
|
-
if (!text && attachments.length === 0)
|
|
7082
|
-
throw new Error(
|
|
7083
|
-
"nothing to send: provide text, --file <path>, --attach <file>, or pipe stdin"
|
|
7084
|
-
);
|
|
7085
|
-
const msg = await client.send(args.channel, {
|
|
7086
|
-
from: args.from ?? "peer",
|
|
7087
|
-
text: text ?? "",
|
|
7088
|
-
to: splitCsv(args.to),
|
|
7089
|
-
attachments: attachments.length ? attachments : void 0
|
|
7090
|
-
});
|
|
7091
|
-
if (args.json) console.log(toJson(msg));
|
|
7092
|
-
else console.log(`sent (seq ${msg.seq})`);
|
|
7093
|
-
}
|
|
7094
|
-
});
|
|
7095
|
-
|
|
7096
|
-
// src/commands/channel.ts
|
|
7097
|
-
var channel = defineCommand({
|
|
7098
|
-
meta: {
|
|
7099
|
-
name: "channel",
|
|
7100
|
-
description: "multi-agent chat room: create / about / update / help / join / members / send / read / listen / download / close"
|
|
7101
|
-
},
|
|
7102
|
-
subCommands: {
|
|
7103
|
-
create: createCommand,
|
|
7104
|
-
about: aboutCommand,
|
|
7105
|
-
update: updateCommand,
|
|
7106
|
-
help: helpCommand,
|
|
7107
|
-
join: joinCommand,
|
|
7108
|
-
members: membersCommand,
|
|
7109
|
-
send: sendCommand,
|
|
7110
|
-
read: readCommand,
|
|
7111
|
-
listen: listenCommand,
|
|
7112
|
-
download: downloadCommand,
|
|
7113
|
-
close: closeCommand
|
|
7114
|
-
}
|
|
7115
|
-
});
|
|
7116
|
-
|
|
7117
|
-
// src/commands/init.ts
|
|
7118
|
-
import { existsSync as existsSync2 } from "node:fs";
|
|
7119
|
-
import * as readline from "node:readline/promises";
|
|
7120
|
-
var promptPick = async (label, items) => {
|
|
7121
|
-
if (items.length === 0) throw new Error(`no ${label}s found on server`);
|
|
7122
|
-
console.log(`${label}s:`);
|
|
7123
|
-
items.forEach((it, i) => {
|
|
7124
|
-
console.log(` [${i + 1}] #${it.id} ${it.name}`);
|
|
7125
|
-
});
|
|
7126
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7127
|
-
try {
|
|
7128
|
-
const ans = (await rl.question(`pick a ${label} (1-${items.length}): `)).trim();
|
|
7129
|
-
const idx = Number(ans) - 1;
|
|
7130
|
-
const picked = items[idx];
|
|
7131
|
-
if (!picked) throw new Error(`invalid choice: ${ans}`);
|
|
7132
|
-
return picked;
|
|
7133
|
-
} finally {
|
|
7134
|
-
rl.close();
|
|
7135
|
-
}
|
|
7136
|
-
};
|
|
7137
|
-
var init = defineCommand({
|
|
7138
|
-
meta: {
|
|
7139
|
-
name: "init",
|
|
7140
|
-
description: `write ${PROJECT_CONFIG_NAME} in the current directory (local state, gitignored)`
|
|
7141
|
-
},
|
|
7142
|
-
args: {
|
|
7143
|
-
workspace: { type: "string", description: "workspace id (skip prompt)" },
|
|
7144
|
-
project: { type: "string", description: "project id (skip prompt)" },
|
|
7145
|
-
force: { type: "boolean", description: `overwrite existing ${PROJECT_CONFIG_NAME}` },
|
|
7146
|
-
...common
|
|
7147
|
-
},
|
|
7148
|
-
run: async ({ args }) => {
|
|
7149
|
-
const server = resolveBaseUrl(args.url);
|
|
7150
|
-
const cfgPath = projectConfigPath();
|
|
7151
|
-
if (existsSync2(cfgPath) && !args.force)
|
|
7152
|
-
throw new Error(`${PROJECT_CONFIG_NAME} already exists. use --force to overwrite.`);
|
|
7153
|
-
const c = createClient(server);
|
|
7154
|
-
let project2;
|
|
7155
|
-
let workspace2;
|
|
7156
|
-
if (args.project) {
|
|
7157
|
-
project2 = await c.projects.get(Number(args.project));
|
|
7158
|
-
workspace2 = await c.workspaces.get(project2.workspaceId);
|
|
7159
|
-
} else {
|
|
7160
|
-
const wsList = await c.workspaces.list();
|
|
7161
|
-
workspace2 = args.workspace ? wsList.find((w) => w.id === Number(args.workspace)) ?? (() => {
|
|
7162
|
-
throw new Error(`workspace ${args.workspace} not found`);
|
|
7163
|
-
})() : await promptPick("workspace", wsList);
|
|
7164
|
-
const projects = await c.projects.listByWorkspace(workspace2.id);
|
|
7165
|
-
project2 = await promptPick("project", projects);
|
|
7166
|
-
}
|
|
7167
|
-
const cfg = {
|
|
7168
|
-
server,
|
|
7169
|
-
workspace: workspace2.id,
|
|
7170
|
-
project: project2.id,
|
|
7171
|
-
name: project2.name
|
|
7172
|
-
};
|
|
7173
|
-
saveProjectConfig(cfgPath, cfg);
|
|
7174
|
-
console.log(`wrote ${cfgPath}`);
|
|
7175
|
-
console.log(` server: ${server}`);
|
|
7176
|
-
console.log(` workspace: #${workspace2.id} ${workspace2.name}`);
|
|
7177
|
-
console.log(` project: #${project2.id} ${project2.name}`);
|
|
7178
|
-
}
|
|
7179
|
-
});
|
|
7180
|
-
|
|
7181
|
-
// src/commands/session/shared.ts
|
|
7182
|
-
var resolveSession = async (client, projectId, handle) => {
|
|
7183
|
-
const asInt = Number(handle);
|
|
7184
|
-
if (Number.isInteger(asInt) && asInt > 0) {
|
|
7185
|
-
const byId = await client.sessions.get(asInt).catch(() => null);
|
|
7186
|
-
if (byId) return { id: byId.id, name: byId.name };
|
|
7187
|
-
}
|
|
7188
|
-
const byName = await client.sessions.findByName(projectId, handle);
|
|
7189
|
-
if (byName) return { id: byName.id, name: byName.name };
|
|
7190
|
-
throw new Error(`session "${handle}" not found in project ${projectId}`);
|
|
6416
|
+
".envrc",
|
|
6417
|
+
".npmrc",
|
|
6418
|
+
".netrc",
|
|
6419
|
+
".pypirc",
|
|
6420
|
+
".git-credentials",
|
|
6421
|
+
".pgpass",
|
|
6422
|
+
".htpasswd",
|
|
6423
|
+
".credentials.json"
|
|
6424
|
+
]);
|
|
6425
|
+
var SENSITIVE_EXTENSIONS = [".pem", ".key", ".p12", ".pfx", ".jks", ".keystore"];
|
|
6426
|
+
var isSensitiveName = (name) => SENSITIVE_NAMES.has(name) || /^\.env(\..+)?$/.test(name) && !/\.(example|sample|template)$/.test(name) || /^id_(rsa|dsa|ecdsa|ed25519)$/.test(name) || SENSITIVE_EXTENSIONS.some((extension2) => name.endsWith(extension2));
|
|
6427
|
+
var isSensitiveFilePath = (path) => {
|
|
6428
|
+
const segments = path.toLowerCase().split("/");
|
|
6429
|
+
return segments.some((segment) => SENSITIVE_SEGMENTS.has(segment)) || isSensitiveName(segments.at(-1) ?? "");
|
|
7191
6430
|
};
|
|
6431
|
+
var EXCLUDED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
6432
|
+
"node_modules",
|
|
6433
|
+
".pnpm-store",
|
|
6434
|
+
"dist",
|
|
6435
|
+
"build",
|
|
6436
|
+
"coverage",
|
|
6437
|
+
".next",
|
|
6438
|
+
".turbo",
|
|
6439
|
+
".cache",
|
|
6440
|
+
".venv",
|
|
6441
|
+
"__pycache__",
|
|
6442
|
+
"target"
|
|
6443
|
+
]);
|
|
6444
|
+
var isExcludedDirectoryName = (name) => EXCLUDED_DIRECTORIES.has(name);
|
|
7192
6445
|
|
|
7193
|
-
// src/
|
|
7194
|
-
var
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
every: {
|
|
7204
|
-
type: "string",
|
|
7205
|
-
required: true,
|
|
7206
|
-
description: "interval: 90s / 30m / 2h / 1d (min 30s)"
|
|
7207
|
-
},
|
|
7208
|
-
name: { type: "string", description: "optional label" },
|
|
7209
|
-
off: { type: "boolean", description: "create paused (disabled)" },
|
|
7210
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
7211
|
-
...common
|
|
7212
|
-
},
|
|
7213
|
-
run: async ({ args }) => {
|
|
7214
|
-
const c = clientFor(args);
|
|
7215
|
-
const session2 = await resolveSession(c, resolveProjectId(args), args.session);
|
|
7216
|
-
const loop2 = await c.loops.create(session2.id, {
|
|
7217
|
-
message: args.message,
|
|
7218
|
-
intervalSec: parseDuration(args.every),
|
|
7219
|
-
name: args.name,
|
|
7220
|
-
enabled: !args.off
|
|
7221
|
-
});
|
|
7222
|
-
console.log(renderOne(loop2, fmtLoop, Boolean(args.json)));
|
|
7223
|
-
}
|
|
7224
|
-
});
|
|
7225
|
-
|
|
7226
|
-
// src/commands/loop/disable.ts
|
|
7227
|
-
var loopDisableCommand = defineCommand({
|
|
7228
|
-
meta: { name: "disable", description: "disable (pause) a loop" },
|
|
7229
|
-
args: {
|
|
7230
|
-
loop: { type: "positional", required: true, description: "loop int id" },
|
|
7231
|
-
...common
|
|
7232
|
-
},
|
|
7233
|
-
run: async ({ args }) => {
|
|
7234
|
-
const c = clientFor(args);
|
|
7235
|
-
const loop2 = await c.loops.update(Number(args.loop), { enabled: false });
|
|
7236
|
-
console.log(renderOne(loop2, fmtLoop, Boolean(args.json)));
|
|
7237
|
-
}
|
|
7238
|
-
});
|
|
7239
|
-
|
|
7240
|
-
// src/commands/loop/enable.ts
|
|
7241
|
-
var loopEnableCommand = defineCommand({
|
|
7242
|
-
meta: { name: "enable", description: "enable (resume) a loop" },
|
|
7243
|
-
args: {
|
|
7244
|
-
loop: { type: "positional", required: true, description: "loop int id" },
|
|
7245
|
-
...common
|
|
7246
|
-
},
|
|
7247
|
-
run: async ({ args }) => {
|
|
7248
|
-
const c = clientFor(args);
|
|
7249
|
-
const loop2 = await c.loops.update(Number(args.loop), { enabled: true });
|
|
7250
|
-
console.log(renderOne(loop2, fmtLoop, Boolean(args.json)));
|
|
6446
|
+
// ../shared/src/domain/service.ts
|
|
6447
|
+
var SERVICE_PUBLIC_URL_MAX_LENGTH = 2048;
|
|
6448
|
+
var SERVICE_NOTE_MAX_LENGTH = 500;
|
|
6449
|
+
var isServicePublicUrl = (value) => {
|
|
6450
|
+
if (value.length === 0 || value.length > SERVICE_PUBLIC_URL_MAX_LENGTH) return false;
|
|
6451
|
+
try {
|
|
6452
|
+
const url = new URL(value);
|
|
6453
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
6454
|
+
} catch {
|
|
6455
|
+
return false;
|
|
7251
6456
|
}
|
|
7252
|
-
}
|
|
6457
|
+
};
|
|
6458
|
+
var isServiceNote = (value) => value.length > 0 && value.length <= SERVICE_NOTE_MAX_LENGTH;
|
|
7253
6459
|
|
|
7254
|
-
// src/
|
|
7255
|
-
var
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
...common
|
|
7260
|
-
},
|
|
7261
|
-
run: async ({ args }) => {
|
|
7262
|
-
const c = clientFor(args);
|
|
7263
|
-
const loop2 = await c.loops.get(Number(args.loop));
|
|
7264
|
-
console.log(renderOne(loop2, fmtLoop, Boolean(args.json)));
|
|
7265
|
-
}
|
|
7266
|
-
});
|
|
6460
|
+
// ../shared/src/domain/session.ts
|
|
6461
|
+
var AGENT_KINDS = ["claude-code", "codex", "pi"];
|
|
6462
|
+
var isAgentKind = (v) => typeof v === "string" && AGENT_KINDS.includes(v);
|
|
6463
|
+
var EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"];
|
|
6464
|
+
var isAgentEffort = (v) => typeof v === "string" && EFFORTS.includes(v);
|
|
7267
6465
|
|
|
7268
|
-
// src/
|
|
7269
|
-
var
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
}
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
console.log(renderList(loops, fmtLoop, Boolean(args.json)));
|
|
7281
|
-
}
|
|
7282
|
-
});
|
|
6466
|
+
// ../shared/src/domain/session-event.ts
|
|
6467
|
+
var agentMessageText = (payload) => {
|
|
6468
|
+
if (typeof payload !== "object" || payload === null) return null;
|
|
6469
|
+
const event = payload;
|
|
6470
|
+
if (!["item.started", "item.updated", "item.completed"].includes(String(event.type))) return null;
|
|
6471
|
+
const item = event.item;
|
|
6472
|
+
if (typeof item !== "object" || item === null) return null;
|
|
6473
|
+
const { type, id, text } = item;
|
|
6474
|
+
if (type !== "agent_message" || typeof id !== "string" || typeof text !== "string") return null;
|
|
6475
|
+
const trimmed = text.trim();
|
|
6476
|
+
return trimmed ? { id, text: trimmed } : null;
|
|
6477
|
+
};
|
|
7283
6478
|
|
|
7284
|
-
// src/
|
|
7285
|
-
var
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
const c = clientFor(args);
|
|
7293
|
-
const id = Number(args.loop);
|
|
7294
|
-
await c.loops.remove(id);
|
|
7295
|
-
console.log(removed("loop", id, Boolean(args.json)));
|
|
7296
|
-
}
|
|
7297
|
-
});
|
|
6479
|
+
// ../shared/src/domain/worker-creation.ts
|
|
6480
|
+
var WORKER_TEMPLATES = [
|
|
6481
|
+
{ id: "mini-glm-codeplan", name: "GLM Code Plan", agentKinds: ["claude-code", "pi"] },
|
|
6482
|
+
{ id: "mini-dashscope-codeplan", name: "DashScope Code Plan", agentKinds: ["claude-code", "pi"] },
|
|
6483
|
+
{ id: "mini-codex", name: "\u672C\u673A Codex", agentKinds: ["codex"] }
|
|
6484
|
+
];
|
|
6485
|
+
var workerTemplateAgentKinds = (id) => id === "mini-local" ? AGENT_KINDS : WORKER_TEMPLATES.find((template) => template.id === id)?.agentKinds ?? [];
|
|
6486
|
+
var isWorkerTemplateId = (value) => typeof value === "string" && workerTemplateAgentKinds(value).length > 0;
|
|
7298
6487
|
|
|
7299
|
-
// src/
|
|
7300
|
-
var
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
|
|
6488
|
+
// src/provisioner/config.ts
|
|
6489
|
+
var forbiddenEnv = /* @__PURE__ */ new Set([
|
|
6490
|
+
"BATON_PROVISIONER_TOKEN",
|
|
6491
|
+
"BATON_TOKEN",
|
|
6492
|
+
"BATON_WORKER_TOKEN",
|
|
6493
|
+
"BATON_USER",
|
|
6494
|
+
"BATON_PASS",
|
|
6495
|
+
"HOME",
|
|
6496
|
+
"XDG_DATA_HOME"
|
|
6497
|
+
]);
|
|
6498
|
+
var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6499
|
+
var absolutePath = (value, field) => {
|
|
6500
|
+
if (typeof value !== "string" || !isAbsolute(value) || value.includes("\0"))
|
|
6501
|
+
throw new Error(`${field} must be an absolute path`);
|
|
6502
|
+
return value;
|
|
6503
|
+
};
|
|
6504
|
+
var environment = (value) => {
|
|
6505
|
+
if (!object(value)) throw new Error("workerEnv must be an object");
|
|
6506
|
+
return Object.fromEntries(
|
|
6507
|
+
Object.entries(value).map(([key, entry]) => {
|
|
6508
|
+
if (forbiddenEnv.has(key) || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) || typeof entry !== "string" || entry.includes("\0"))
|
|
6509
|
+
throw new Error(`invalid worker environment key: ${key}`);
|
|
6510
|
+
return [key, entry];
|
|
6511
|
+
})
|
|
6512
|
+
);
|
|
6513
|
+
};
|
|
6514
|
+
var templates = (value) => {
|
|
6515
|
+
if (!object(value)) throw new Error("templates must be an object");
|
|
6516
|
+
return Object.fromEntries(
|
|
6517
|
+
WORKER_TEMPLATES.filter((template) => value[template.id] !== void 0).map((template) => {
|
|
6518
|
+
const raw = value[template.id];
|
|
6519
|
+
if (!object(raw)) throw new Error(`template ${template.id} must be an object`);
|
|
6520
|
+
const workerEnv2 = environment(raw.workerEnv);
|
|
6521
|
+
if (template.id === "mini-codex") {
|
|
6522
|
+
if (raw.pi !== void 0) throw new Error("mini-codex does not support pi");
|
|
6523
|
+
return [template.id, { workerEnv: workerEnv2 }];
|
|
6524
|
+
}
|
|
6525
|
+
const provider = template.id === "mini-glm-codeplan" ? "zai-coding-cn" : "qwen-token-plan-cn";
|
|
6526
|
+
const apiKey = template.id === "mini-glm-codeplan" ? "ZAI_CODING_CN_API_KEY" : "QWEN_TOKEN_PLAN_CN_API_KEY";
|
|
6527
|
+
if (!workerEnv2.ANTHROPIC_BASE_URL || !(workerEnv2.ANTHROPIC_AUTH_TOKEN || workerEnv2.ANTHROPIC_API_KEY) || !workerEnv2[apiKey])
|
|
6528
|
+
throw new Error(`template ${template.id} requires Claude and Pi credentials`);
|
|
6529
|
+
if (!object(raw.pi) || raw.pi.provider !== provider || typeof raw.pi.model !== "string" || !raw.pi.model.trim())
|
|
6530
|
+
throw new Error(`template ${template.id} requires its Pi provider and model`);
|
|
6531
|
+
return [template.id, { workerEnv: workerEnv2, pi: { provider, model: raw.pi.model.trim() } }];
|
|
6532
|
+
})
|
|
6533
|
+
);
|
|
6534
|
+
};
|
|
6535
|
+
var commandEnvironment = (config) => ({
|
|
6536
|
+
...process.env,
|
|
6537
|
+
PATH: config.workerEnv.PATH ?? process.env.PATH ?? "/usr/bin:/bin"
|
|
7318
6538
|
});
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7328
|
-
|
|
7329
|
-
|
|
7330
|
-
rm: loopRmCommand
|
|
6539
|
+
var loadProvisionerConfig = async (path) => {
|
|
6540
|
+
if (process.platform !== "darwin") throw new Error("provisioner requires macOS");
|
|
6541
|
+
absolutePath(path, "config");
|
|
6542
|
+
if ((await stat2(path)).mode & 63) throw new Error("config must be private: chmod 600 <config>");
|
|
6543
|
+
const text = await readFile(path, "utf8");
|
|
6544
|
+
let raw;
|
|
6545
|
+
try {
|
|
6546
|
+
raw = JSON.parse(text);
|
|
6547
|
+
} catch (error) {
|
|
6548
|
+
if (!(error instanceof SyntaxError)) throw error;
|
|
6549
|
+
throw new Error("invalid provisioner JSON config");
|
|
7331
6550
|
}
|
|
7332
|
-
|
|
6551
|
+
if (!object(raw) || typeof raw.server !== "string" || typeof raw.token !== "string")
|
|
6552
|
+
throw new Error("server and token required");
|
|
6553
|
+
let server;
|
|
6554
|
+
try {
|
|
6555
|
+
server = new URL(raw.server);
|
|
6556
|
+
} catch (error) {
|
|
6557
|
+
if (!(error instanceof TypeError)) throw error;
|
|
6558
|
+
throw new Error("server must be a valid HTTP(S) URL");
|
|
6559
|
+
}
|
|
6560
|
+
if (!["http:", "https:"].includes(server.protocol) || server.username || server.password || server.search || server.hash)
|
|
6561
|
+
throw new Error("server must be an HTTP(S) URL without credentials, query, or fragment");
|
|
6562
|
+
if (!raw.token.trim() || /[\r\n]/.test(raw.token))
|
|
6563
|
+
throw new Error("valid provisioner token required");
|
|
6564
|
+
const config = {
|
|
6565
|
+
server: server.toString().replace(/\/$/, ""),
|
|
6566
|
+
token: raw.token.trim(),
|
|
6567
|
+
projectsRoot: absolutePath(raw.projectsRoot, "projectsRoot"),
|
|
6568
|
+
cliPath: absolutePath(raw.cliPath, "cliPath"),
|
|
6569
|
+
nodePath: absolutePath(raw.nodePath ?? process.execPath, "nodePath"),
|
|
6570
|
+
workerEnv: environment(raw.workerEnv),
|
|
6571
|
+
templates: templates(raw.templates)
|
|
6572
|
+
};
|
|
6573
|
+
await access(config.cliPath, constants.R_OK);
|
|
6574
|
+
await access(config.nodePath ?? process.execPath, constants.X_OK);
|
|
6575
|
+
const env = commandEnvironment(config);
|
|
6576
|
+
await promisify(execFile)("git", ["--version"], { env, timeout: 1e4 });
|
|
6577
|
+
await promisify(execFile)("launchctl", ["help"], { env, timeout: 1e4 });
|
|
6578
|
+
await promisify(execFile)("/usr/bin/plutil", ["-help"], { timeout: 1e4 });
|
|
6579
|
+
return config;
|
|
6580
|
+
};
|
|
7333
6581
|
|
|
7334
|
-
//
|
|
7335
|
-
var
|
|
7336
|
-
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
return "nobody to notify: no human has messaged this session, or they have not enabled notifications";
|
|
6582
|
+
// ../../node_modules/.pnpm/eventsource-parser@3.1.0/node_modules/eventsource-parser/dist/index.js
|
|
6583
|
+
var ParseError = class extends Error {
|
|
6584
|
+
constructor(message, options) {
|
|
6585
|
+
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
|
|
6586
|
+
}
|
|
7340
6587
|
};
|
|
7341
|
-
var
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
6588
|
+
var LF = 10;
|
|
6589
|
+
var CR = 13;
|
|
6590
|
+
var SPACE = 32;
|
|
6591
|
+
function noop(_arg) {
|
|
6592
|
+
}
|
|
6593
|
+
function createParser(config) {
|
|
6594
|
+
if (typeof config == "function")
|
|
6595
|
+
throw new TypeError(
|
|
6596
|
+
"`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?"
|
|
6597
|
+
);
|
|
6598
|
+
const { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config, pendingFragments = [];
|
|
6599
|
+
let pendingFragmentsLength = 0, isFirstChunk = true, id, data = "", dataLines = 0, eventType, terminated = false;
|
|
6600
|
+
function feed(chunk) {
|
|
6601
|
+
if (terminated)
|
|
6602
|
+
throw new Error(
|
|
6603
|
+
"Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing."
|
|
6604
|
+
);
|
|
6605
|
+
if (isFirstChunk && (isFirstChunk = false, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
|
|
6606
|
+
const trailing2 = processLines(chunk);
|
|
6607
|
+
trailing2 !== "" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();
|
|
6608
|
+
return;
|
|
6609
|
+
}
|
|
6610
|
+
if (chunk.indexOf(`
|
|
6611
|
+
`) === -1 && chunk.indexOf("\r") === -1) {
|
|
6612
|
+
pendingFragments.push(chunk), pendingFragmentsLength += chunk.length, checkBufferSize();
|
|
6613
|
+
return;
|
|
6614
|
+
}
|
|
6615
|
+
pendingFragments.push(chunk);
|
|
6616
|
+
const input = pendingFragments.join("");
|
|
6617
|
+
pendingFragments.length = 0, pendingFragmentsLength = 0;
|
|
6618
|
+
const trailing = processLines(input);
|
|
6619
|
+
trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
|
|
7359
6620
|
}
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
run: async ({ args }) => {
|
|
7395
|
-
console.log(
|
|
7396
|
-
await listProjects(clientFor(args), resolveWorkspaceId(args), Boolean(args.json))
|
|
7397
|
-
);
|
|
6621
|
+
function checkBufferSize() {
|
|
6622
|
+
maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = true, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = "", dataLines = 0, eventType = void 0, onError(
|
|
6623
|
+
new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
|
|
6624
|
+
type: "max-buffer-size-exceeded"
|
|
6625
|
+
})
|
|
6626
|
+
)));
|
|
6627
|
+
}
|
|
6628
|
+
function processLines(chunk) {
|
|
6629
|
+
let searchIndex = 0;
|
|
6630
|
+
if (chunk.indexOf("\r") === -1) {
|
|
6631
|
+
let lfIndex = chunk.indexOf(`
|
|
6632
|
+
`, searchIndex);
|
|
6633
|
+
for (; lfIndex !== -1; ) {
|
|
6634
|
+
if (searchIndex === lfIndex) {
|
|
6635
|
+
dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
6636
|
+
`, searchIndex);
|
|
6637
|
+
continue;
|
|
6638
|
+
}
|
|
6639
|
+
const firstCharCode = chunk.charCodeAt(searchIndex);
|
|
6640
|
+
if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
|
|
6641
|
+
const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
|
|
6642
|
+
if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
|
|
6643
|
+
onEvent({ id, event: eventType, data: value }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
|
|
6644
|
+
`, searchIndex);
|
|
6645
|
+
continue;
|
|
6646
|
+
}
|
|
6647
|
+
data = dataLines === 0 ? value : `${data}
|
|
6648
|
+
${value}`, dataLines++;
|
|
6649
|
+
} else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(
|
|
6650
|
+
chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,
|
|
6651
|
+
lfIndex
|
|
6652
|
+
) || void 0 : parseLine(chunk, searchIndex, lfIndex);
|
|
6653
|
+
searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
6654
|
+
`, searchIndex);
|
|
7398
6655
|
}
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
6656
|
+
return chunk.slice(searchIndex);
|
|
6657
|
+
}
|
|
6658
|
+
for (; searchIndex < chunk.length; ) {
|
|
6659
|
+
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
|
|
6660
|
+
`, searchIndex);
|
|
6661
|
+
let lineEnd = -1;
|
|
6662
|
+
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = crIndex < lfIndex ? crIndex : lfIndex : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1)
|
|
6663
|
+
break;
|
|
6664
|
+
parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;
|
|
6665
|
+
}
|
|
6666
|
+
return chunk.slice(searchIndex);
|
|
6667
|
+
}
|
|
6668
|
+
function parseLine(chunk, start, end) {
|
|
6669
|
+
if (start === end) {
|
|
6670
|
+
dispatchEvent();
|
|
6671
|
+
return;
|
|
6672
|
+
}
|
|
6673
|
+
const firstCharCode = chunk.charCodeAt(start);
|
|
6674
|
+
if (isDataPrefix(chunk, start, firstCharCode)) {
|
|
6675
|
+
const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
|
|
6676
|
+
data = dataLines === 0 ? value2 : `${data}
|
|
6677
|
+
${value2}`, dataLines++;
|
|
6678
|
+
return;
|
|
6679
|
+
}
|
|
6680
|
+
if (isEventPrefix(chunk, start, firstCharCode)) {
|
|
6681
|
+
eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
|
|
6682
|
+
return;
|
|
6683
|
+
}
|
|
6684
|
+
if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
|
|
6685
|
+
const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
|
|
6686
|
+
id = value2.includes("\0") ? void 0 : value2;
|
|
6687
|
+
return;
|
|
6688
|
+
}
|
|
6689
|
+
if (firstCharCode === 58) {
|
|
6690
|
+
if (onComment) {
|
|
6691
|
+
const line2 = chunk.slice(start, end);
|
|
6692
|
+
onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
|
|
7405
6693
|
}
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
6694
|
+
return;
|
|
6695
|
+
}
|
|
6696
|
+
const line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(":");
|
|
6697
|
+
if (fieldSeparatorIndex === -1) {
|
|
6698
|
+
processField(line, "", line);
|
|
6699
|
+
return;
|
|
6700
|
+
}
|
|
6701
|
+
const field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
6702
|
+
processField(field, value, line);
|
|
6703
|
+
}
|
|
6704
|
+
function processField(field, value, line) {
|
|
6705
|
+
switch (field) {
|
|
6706
|
+
case "event":
|
|
6707
|
+
eventType = value || void 0;
|
|
6708
|
+
break;
|
|
6709
|
+
case "data":
|
|
6710
|
+
data = dataLines === 0 ? value : `${data}
|
|
6711
|
+
${value}`, dataLines++;
|
|
6712
|
+
break;
|
|
6713
|
+
case "id":
|
|
6714
|
+
id = value.includes("\0") ? void 0 : value;
|
|
6715
|
+
break;
|
|
6716
|
+
case "retry":
|
|
6717
|
+
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
|
|
6718
|
+
new ParseError(`Invalid \`retry\` value: "${value}"`, {
|
|
6719
|
+
type: "invalid-retry",
|
|
6720
|
+
value,
|
|
6721
|
+
line
|
|
6722
|
+
})
|
|
6723
|
+
);
|
|
6724
|
+
break;
|
|
6725
|
+
default:
|
|
6726
|
+
onError(
|
|
6727
|
+
new ParseError(
|
|
6728
|
+
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
|
|
6729
|
+
{ type: "unknown-field", field, value, line }
|
|
6730
|
+
)
|
|
7423
6731
|
);
|
|
7424
|
-
|
|
7425
|
-
}
|
|
7426
|
-
rm: defineCommand({
|
|
7427
|
-
meta: { name: "rm", description: "delete a project" },
|
|
7428
|
-
args: { id: { type: "positional", required: true }, ...common },
|
|
7429
|
-
run: async ({ args }) => {
|
|
7430
|
-
console.log(await removeProject(clientFor(args), Number(args.id), Boolean(args.json)));
|
|
7431
|
-
}
|
|
7432
|
-
})
|
|
6732
|
+
break;
|
|
6733
|
+
}
|
|
7433
6734
|
}
|
|
7434
|
-
|
|
6735
|
+
function dispatchEvent() {
|
|
6736
|
+
dataLines > 0 && onEvent({
|
|
6737
|
+
id,
|
|
6738
|
+
event: eventType,
|
|
6739
|
+
data
|
|
6740
|
+
}), id = void 0, data = "", dataLines = 0, eventType = void 0;
|
|
6741
|
+
}
|
|
6742
|
+
function reset(options = {}) {
|
|
6743
|
+
if (options.consume && pendingFragments.length > 0) {
|
|
6744
|
+
const incompleteLine = pendingFragments.join("");
|
|
6745
|
+
parseLine(incompleteLine, 0, incompleteLine.length);
|
|
6746
|
+
}
|
|
6747
|
+
isFirstChunk = true, id = void 0, data = "", dataLines = 0, eventType = void 0, pendingFragments.length = 0, pendingFragmentsLength = 0, terminated = false;
|
|
6748
|
+
}
|
|
6749
|
+
return { feed, reset };
|
|
6750
|
+
}
|
|
6751
|
+
function isDataPrefix(chunk, i, firstCharCode) {
|
|
6752
|
+
return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
|
|
6753
|
+
}
|
|
6754
|
+
function isEventPrefix(chunk, i, firstCharCode) {
|
|
6755
|
+
return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
|
|
6756
|
+
}
|
|
7435
6757
|
|
|
7436
|
-
//
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
6758
|
+
// ../../node_modules/.pnpm/eventsource@4.1.0/node_modules/eventsource/dist/index.js
|
|
6759
|
+
var ErrorEvent = class extends Event {
|
|
6760
|
+
/**
|
|
6761
|
+
* Constructs a new `ErrorEvent` instance. This is typically not called directly,
|
|
6762
|
+
* but rather emitted by the `EventSource` object when an error occurs.
|
|
6763
|
+
*
|
|
6764
|
+
* @param type - The type of the event (should be "error")
|
|
6765
|
+
* @param errorEventInitDict - Optional properties to include in the error event
|
|
6766
|
+
*/
|
|
6767
|
+
constructor(type, errorEventInitDict) {
|
|
6768
|
+
var _a, _b;
|
|
6769
|
+
super(type), this.code = (_a = errorEventInitDict == null ? void 0 : errorEventInitDict.code) != null ? _a : void 0, this.message = (_b = errorEventInitDict == null ? void 0 : errorEventInitDict.message) != null ? _b : void 0;
|
|
6770
|
+
}
|
|
6771
|
+
/**
|
|
6772
|
+
* Node.js "hides" the `message` and `code` properties of the `ErrorEvent` instance,
|
|
6773
|
+
* when it is `console.log`'ed. This makes it harder to debug errors. To ease debugging,
|
|
6774
|
+
* we explicitly include the properties in the `inspect` method.
|
|
6775
|
+
*
|
|
6776
|
+
* This is automatically called by Node.js when you `console.log` an instance of this class.
|
|
6777
|
+
*
|
|
6778
|
+
* @param _depth - The current depth
|
|
6779
|
+
* @param options - The options passed to `util.inspect`
|
|
6780
|
+
* @param inspect - The inspect function to use (prevents having to import it from `util`)
|
|
6781
|
+
* @returns A string representation of the error
|
|
6782
|
+
*/
|
|
6783
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")](_depth, options, inspect) {
|
|
6784
|
+
return inspect(inspectableError(this), options);
|
|
6785
|
+
}
|
|
6786
|
+
/**
|
|
6787
|
+
* Deno "hides" the `message` and `code` properties of the `ErrorEvent` instance,
|
|
6788
|
+
* when it is `console.log`'ed. This makes it harder to debug errors. To ease debugging,
|
|
6789
|
+
* we explicitly include the properties in the `inspect` method.
|
|
6790
|
+
*
|
|
6791
|
+
* This is automatically called by Deno when you `console.log` an instance of this class.
|
|
6792
|
+
*
|
|
6793
|
+
* @param inspect - The inspect function to use (prevents having to import it from `util`)
|
|
6794
|
+
* @param options - The options passed to `Deno.inspect`
|
|
6795
|
+
* @returns A string representation of the error
|
|
6796
|
+
*/
|
|
6797
|
+
[/* @__PURE__ */ Symbol.for("Deno.customInspect")](inspect, options) {
|
|
6798
|
+
return inspect(inspectableError(this), options);
|
|
6799
|
+
}
|
|
7456
6800
|
};
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
return
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
6801
|
+
function syntaxError(message) {
|
|
6802
|
+
const DomException = globalThis.DOMException;
|
|
6803
|
+
return typeof DomException == "function" ? new DomException(message, "SyntaxError") : new SyntaxError(message);
|
|
6804
|
+
}
|
|
6805
|
+
function flattenError(err) {
|
|
6806
|
+
return err instanceof Error ? "errors" in err && Array.isArray(err.errors) ? err.errors.map(flattenError).join(", ") : "cause" in err && err.cause instanceof Error ? `${err}: ${flattenError(err.cause)}` : err.message : `${err}`;
|
|
6807
|
+
}
|
|
6808
|
+
function inspectableError(err) {
|
|
6809
|
+
return {
|
|
6810
|
+
type: err.type,
|
|
6811
|
+
message: err.message,
|
|
6812
|
+
code: err.code,
|
|
6813
|
+
defaultPrevented: err.defaultPrevented,
|
|
6814
|
+
cancelable: err.cancelable,
|
|
6815
|
+
timeStamp: err.timeStamp
|
|
6816
|
+
};
|
|
6817
|
+
}
|
|
6818
|
+
var __typeError = (msg) => {
|
|
6819
|
+
throw TypeError(msg);
|
|
7466
6820
|
};
|
|
7467
|
-
var
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
6821
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
6822
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6823
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
6824
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
|
|
6825
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
6826
|
+
var _readyState;
|
|
6827
|
+
var _url;
|
|
6828
|
+
var _redirectUrl;
|
|
6829
|
+
var _withCredentials;
|
|
6830
|
+
var _fetch;
|
|
6831
|
+
var _reconnectInterval;
|
|
6832
|
+
var _reconnectTimer;
|
|
6833
|
+
var _lastEventId;
|
|
6834
|
+
var _controller;
|
|
6835
|
+
var _parser;
|
|
6836
|
+
var _onError;
|
|
6837
|
+
var _onMessage;
|
|
6838
|
+
var _onOpen;
|
|
6839
|
+
var _EventSource_instances;
|
|
6840
|
+
var connect_fn;
|
|
6841
|
+
var _onFetchResponse;
|
|
6842
|
+
var _onFetchError;
|
|
6843
|
+
var getRequestOptions_fn;
|
|
6844
|
+
var _onEvent;
|
|
6845
|
+
var _onRetryChange;
|
|
6846
|
+
var failConnection_fn;
|
|
6847
|
+
var scheduleReconnect_fn;
|
|
6848
|
+
var _reconnect;
|
|
6849
|
+
var EventSource = class extends EventTarget {
|
|
6850
|
+
constructor(url, eventSourceInitDict) {
|
|
6851
|
+
var _a, _b;
|
|
6852
|
+
super(), __privateAdd(this, _EventSource_instances), this.CONNECTING = 0, this.OPEN = 1, this.CLOSED = 2, __privateAdd(this, _readyState), __privateAdd(this, _url), __privateAdd(this, _redirectUrl), __privateAdd(this, _withCredentials), __privateAdd(this, _fetch), __privateAdd(this, _reconnectInterval), __privateAdd(this, _reconnectTimer), __privateAdd(this, _lastEventId, null), __privateAdd(this, _controller), __privateAdd(this, _parser), __privateAdd(this, _onError, null), __privateAdd(this, _onMessage, null), __privateAdd(this, _onOpen, null), __privateAdd(this, _onFetchResponse, async (response) => {
|
|
6853
|
+
var _a2;
|
|
6854
|
+
__privateGet(this, _parser).reset();
|
|
6855
|
+
const { body, redirected, status, headers } = response;
|
|
6856
|
+
if (status === 204) {
|
|
6857
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Server sent HTTP 204, not reconnecting", 204), this.close();
|
|
6858
|
+
return;
|
|
7477
6859
|
}
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
if (!
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
6860
|
+
if (redirected ? __privateSet(this, _redirectUrl, new URL(response.url)) : __privateSet(this, _redirectUrl, void 0), status !== 200) {
|
|
6861
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, `Non-200 status code (${status})`, status);
|
|
6862
|
+
return;
|
|
6863
|
+
}
|
|
6864
|
+
if (!(headers.get("content-type") || "").startsWith("text/event-stream")) {
|
|
6865
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, 'Invalid content type, expected "text/event-stream"', status);
|
|
6866
|
+
return;
|
|
6867
|
+
}
|
|
6868
|
+
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
6869
|
+
return;
|
|
6870
|
+
__privateSet(this, _readyState, this.OPEN);
|
|
6871
|
+
const openEvent = new Event("open");
|
|
6872
|
+
if ((_a2 = __privateGet(this, _onOpen)) == null || _a2.call(this, openEvent), this.dispatchEvent(openEvent), typeof body != "object" || !body || !("getReader" in body)) {
|
|
6873
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Invalid response body, expected a web ReadableStream", status), this.close();
|
|
6874
|
+
return;
|
|
6875
|
+
}
|
|
6876
|
+
const decoder = new TextDecoder(), reader = body.getReader();
|
|
6877
|
+
let open3 = true;
|
|
6878
|
+
do {
|
|
6879
|
+
const { done, value } = await reader.read();
|
|
6880
|
+
value && __privateGet(this, _parser).feed(decoder.decode(value, { stream: !done })), done && (open3 = false, __privateGet(this, _parser).reset(), __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this));
|
|
6881
|
+
} while (open3);
|
|
6882
|
+
}), __privateAdd(this, _onFetchError, (err) => {
|
|
6883
|
+
__privateSet(this, _controller, void 0), !(err.name === "AbortError" || err.type === "aborted") && __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this, flattenError(err));
|
|
6884
|
+
}), __privateAdd(this, _onEvent, (event) => {
|
|
6885
|
+
typeof event.id == "string" && __privateSet(this, _lastEventId, event.id);
|
|
6886
|
+
const messageEvent = new MessageEvent(event.event || "message", {
|
|
6887
|
+
data: event.data,
|
|
6888
|
+
origin: __privateGet(this, _redirectUrl) ? __privateGet(this, _redirectUrl).origin : __privateGet(this, _url).origin,
|
|
6889
|
+
lastEventId: event.id || ""
|
|
6890
|
+
});
|
|
6891
|
+
__privateGet(this, _onMessage) && (!event.event || event.event === "message") && __privateGet(this, _onMessage).call(this, messageEvent), this.dispatchEvent(messageEvent);
|
|
6892
|
+
}), __privateAdd(this, _onRetryChange, (value) => {
|
|
6893
|
+
__privateSet(this, _reconnectInterval, value);
|
|
6894
|
+
}), __privateAdd(this, _reconnect, () => {
|
|
6895
|
+
__privateSet(this, _reconnectTimer, void 0), __privateGet(this, _readyState) === this.CONNECTING && __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
6896
|
+
});
|
|
6897
|
+
try {
|
|
6898
|
+
if (url instanceof URL)
|
|
6899
|
+
__privateSet(this, _url, url);
|
|
6900
|
+
else if (typeof url == "string")
|
|
6901
|
+
__privateSet(this, _url, new URL(url, getBaseURL()));
|
|
6902
|
+
else
|
|
6903
|
+
throw new Error("Invalid URL");
|
|
6904
|
+
} catch {
|
|
6905
|
+
throw syntaxError("An invalid or illegal string was specified");
|
|
6906
|
+
}
|
|
6907
|
+
__privateSet(this, _parser, createParser({
|
|
6908
|
+
onEvent: __privateGet(this, _onEvent),
|
|
6909
|
+
onRetry: __privateGet(this, _onRetryChange)
|
|
6910
|
+
})), __privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _reconnectInterval, 3e3), __privateSet(this, _fetch, (_a = eventSourceInitDict == null ? void 0 : eventSourceInitDict.fetch) != null ? _a : globalThis.fetch), __privateSet(this, _withCredentials, (_b = eventSourceInitDict == null ? void 0 : eventSourceInitDict.withCredentials) != null ? _b : false), __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
6911
|
+
}
|
|
6912
|
+
/**
|
|
6913
|
+
* Returns the state of this EventSource object's connection. It can have the values described below.
|
|
6914
|
+
*
|
|
6915
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/readyState)
|
|
6916
|
+
*
|
|
6917
|
+
* Note: typed as `number` instead of `0 | 1 | 2` for compatibility with the `EventSource` interface,
|
|
6918
|
+
* defined in the TypeScript `dom` library.
|
|
6919
|
+
*
|
|
6920
|
+
* @public
|
|
6921
|
+
*/
|
|
6922
|
+
get readyState() {
|
|
6923
|
+
return __privateGet(this, _readyState);
|
|
7503
6924
|
}
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
6925
|
+
/**
|
|
6926
|
+
* Returns the URL providing the event stream.
|
|
6927
|
+
*
|
|
6928
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/url)
|
|
6929
|
+
*
|
|
6930
|
+
* @public
|
|
6931
|
+
*/
|
|
6932
|
+
get url() {
|
|
6933
|
+
return __privateGet(this, _url).href;
|
|
6934
|
+
}
|
|
6935
|
+
/**
|
|
6936
|
+
* Returns true if the credentials mode for connection requests to the URL providing the event stream is set to "include", and false otherwise.
|
|
6937
|
+
*
|
|
6938
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/withCredentials)
|
|
6939
|
+
*/
|
|
6940
|
+
get withCredentials() {
|
|
6941
|
+
return __privateGet(this, _withCredentials);
|
|
6942
|
+
}
|
|
6943
|
+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/error_event) */
|
|
6944
|
+
get onerror() {
|
|
6945
|
+
return __privateGet(this, _onError);
|
|
6946
|
+
}
|
|
6947
|
+
set onerror(value) {
|
|
6948
|
+
__privateSet(this, _onError, value);
|
|
6949
|
+
}
|
|
6950
|
+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/message_event) */
|
|
6951
|
+
get onmessage() {
|
|
6952
|
+
return __privateGet(this, _onMessage);
|
|
6953
|
+
}
|
|
6954
|
+
set onmessage(value) {
|
|
6955
|
+
__privateSet(this, _onMessage, value);
|
|
6956
|
+
}
|
|
6957
|
+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/open_event) */
|
|
6958
|
+
get onopen() {
|
|
6959
|
+
return __privateGet(this, _onOpen);
|
|
6960
|
+
}
|
|
6961
|
+
set onopen(value) {
|
|
6962
|
+
__privateSet(this, _onOpen, value);
|
|
6963
|
+
}
|
|
6964
|
+
addEventListener(type, listener, options) {
|
|
6965
|
+
const listen = listener;
|
|
6966
|
+
super.addEventListener(type, listen, options);
|
|
6967
|
+
}
|
|
6968
|
+
removeEventListener(type, listener, options) {
|
|
6969
|
+
const listen = listener;
|
|
6970
|
+
super.removeEventListener(type, listen, options);
|
|
6971
|
+
}
|
|
6972
|
+
/**
|
|
6973
|
+
* Aborts any instances of the fetch algorithm started for this EventSource object, and sets the readyState attribute to CLOSED.
|
|
6974
|
+
*
|
|
6975
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/close)
|
|
6976
|
+
*
|
|
6977
|
+
* @public
|
|
6978
|
+
*/
|
|
6979
|
+
close() {
|
|
6980
|
+
__privateGet(this, _reconnectTimer) && clearTimeout(__privateGet(this, _reconnectTimer)), __privateGet(this, _readyState) !== this.CLOSED && (__privateGet(this, _controller) && __privateGet(this, _controller).abort(), __privateSet(this, _readyState, this.CLOSED), __privateSet(this, _controller, void 0));
|
|
7512
6981
|
}
|
|
7513
|
-
if (!["http:", "https:"].includes(server.protocol) || server.username || server.password || server.search || server.hash)
|
|
7514
|
-
throw new Error("server must be an HTTP(S) URL without credentials, query, or fragment");
|
|
7515
|
-
if (!raw.token.trim() || /[\r\n]/.test(raw.token))
|
|
7516
|
-
throw new Error("valid provisioner token required");
|
|
7517
|
-
const config = {
|
|
7518
|
-
server: server.toString().replace(/\/$/, ""),
|
|
7519
|
-
token: raw.token.trim(),
|
|
7520
|
-
projectsRoot: absolutePath(raw.projectsRoot, "projectsRoot"),
|
|
7521
|
-
cliPath: absolutePath(raw.cliPath, "cliPath"),
|
|
7522
|
-
nodePath: absolutePath(raw.nodePath ?? process.execPath, "nodePath"),
|
|
7523
|
-
workerEnv: environment(raw.workerEnv),
|
|
7524
|
-
templates: templates(raw.templates)
|
|
7525
|
-
};
|
|
7526
|
-
await access(config.cliPath, constants.R_OK);
|
|
7527
|
-
await access(config.nodePath ?? process.execPath, constants.X_OK);
|
|
7528
|
-
const env = commandEnvironment(config);
|
|
7529
|
-
await promisify(execFile)("git", ["--version"], { env, timeout: 1e4 });
|
|
7530
|
-
await promisify(execFile)("launchctl", ["help"], { env, timeout: 1e4 });
|
|
7531
|
-
await promisify(execFile)("/usr/bin/plutil", ["-help"], { timeout: 1e4 });
|
|
7532
|
-
return config;
|
|
7533
6982
|
};
|
|
6983
|
+
_readyState = /* @__PURE__ */ new WeakMap(), _url = /* @__PURE__ */ new WeakMap(), _redirectUrl = /* @__PURE__ */ new WeakMap(), _withCredentials = /* @__PURE__ */ new WeakMap(), _fetch = /* @__PURE__ */ new WeakMap(), _reconnectInterval = /* @__PURE__ */ new WeakMap(), _reconnectTimer = /* @__PURE__ */ new WeakMap(), _lastEventId = /* @__PURE__ */ new WeakMap(), _controller = /* @__PURE__ */ new WeakMap(), _parser = /* @__PURE__ */ new WeakMap(), _onError = /* @__PURE__ */ new WeakMap(), _onMessage = /* @__PURE__ */ new WeakMap(), _onOpen = /* @__PURE__ */ new WeakMap(), _EventSource_instances = /* @__PURE__ */ new WeakSet(), /**
|
|
6984
|
+
* Connect to the given URL and start receiving events
|
|
6985
|
+
*
|
|
6986
|
+
* @internal
|
|
6987
|
+
*/
|
|
6988
|
+
connect_fn = function() {
|
|
6989
|
+
__privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _controller, new AbortController()), __privateGet(this, _fetch)(__privateGet(this, _url), __privateMethod(this, _EventSource_instances, getRequestOptions_fn).call(this)).then(__privateGet(this, _onFetchResponse)).catch(__privateGet(this, _onFetchError));
|
|
6990
|
+
}, _onFetchResponse = /* @__PURE__ */ new WeakMap(), _onFetchError = /* @__PURE__ */ new WeakMap(), /**
|
|
6991
|
+
* Get request options for the `fetch()` request
|
|
6992
|
+
*
|
|
6993
|
+
* @returns The request options
|
|
6994
|
+
* @internal
|
|
6995
|
+
*/
|
|
6996
|
+
getRequestOptions_fn = function() {
|
|
6997
|
+
var _a;
|
|
6998
|
+
const init2 = {
|
|
6999
|
+
// [spec] Let `corsAttributeState` be `Anonymous`…
|
|
7000
|
+
// [spec] …will have their mode set to "cors"…
|
|
7001
|
+
mode: "cors",
|
|
7002
|
+
redirect: "follow",
|
|
7003
|
+
headers: { Accept: "text/event-stream", ...__privateGet(this, _lastEventId) ? { "Last-Event-ID": __privateGet(this, _lastEventId) } : void 0 },
|
|
7004
|
+
cache: "no-store",
|
|
7005
|
+
signal: (_a = __privateGet(this, _controller)) == null ? void 0 : _a.signal
|
|
7006
|
+
};
|
|
7007
|
+
return "window" in globalThis && (init2.credentials = this.withCredentials ? "include" : "same-origin"), init2;
|
|
7008
|
+
}, _onEvent = /* @__PURE__ */ new WeakMap(), _onRetryChange = /* @__PURE__ */ new WeakMap(), /**
|
|
7009
|
+
* Handles the process referred to in the EventSource specification as "failing a connection".
|
|
7010
|
+
*
|
|
7011
|
+
* @param error - The error causing the connection to fail
|
|
7012
|
+
* @param code - The HTTP status code, if available
|
|
7013
|
+
* @internal
|
|
7014
|
+
*/
|
|
7015
|
+
failConnection_fn = function(message, code) {
|
|
7016
|
+
var _a;
|
|
7017
|
+
__privateGet(this, _readyState) !== this.CLOSED && __privateSet(this, _readyState, this.CLOSED);
|
|
7018
|
+
const errorEvent = new ErrorEvent("error", { code, message });
|
|
7019
|
+
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent);
|
|
7020
|
+
}, /**
|
|
7021
|
+
* Schedules a reconnection attempt against the EventSource endpoint.
|
|
7022
|
+
*
|
|
7023
|
+
* @param message - The error causing the connection to fail
|
|
7024
|
+
* @param code - The HTTP status code, if available
|
|
7025
|
+
* @internal
|
|
7026
|
+
*/
|
|
7027
|
+
scheduleReconnect_fn = function(message, code) {
|
|
7028
|
+
var _a;
|
|
7029
|
+
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
7030
|
+
return;
|
|
7031
|
+
__privateSet(this, _readyState, this.CONNECTING);
|
|
7032
|
+
const errorEvent = new ErrorEvent("error", { code, message });
|
|
7033
|
+
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent), __privateSet(this, _reconnectTimer, setTimeout(__privateGet(this, _reconnect), __privateGet(this, _reconnectInterval)));
|
|
7034
|
+
}, _reconnect = /* @__PURE__ */ new WeakMap(), /**
|
|
7035
|
+
* ReadyState representing an EventSource currently trying to connect
|
|
7036
|
+
*
|
|
7037
|
+
* @public
|
|
7038
|
+
*/
|
|
7039
|
+
EventSource.CONNECTING = 0, /**
|
|
7040
|
+
* ReadyState representing an EventSource connection that is open (eg connected)
|
|
7041
|
+
*
|
|
7042
|
+
* @public
|
|
7043
|
+
*/
|
|
7044
|
+
EventSource.OPEN = 1, /**
|
|
7045
|
+
* ReadyState representing an EventSource connection that is closed (eg disconnected)
|
|
7046
|
+
*
|
|
7047
|
+
* @public
|
|
7048
|
+
*/
|
|
7049
|
+
EventSource.CLOSED = 2;
|
|
7050
|
+
Object.defineProperty(EventSource, /* @__PURE__ */ Symbol.for("eventsource.supports-fetch-override"), {
|
|
7051
|
+
value: true,
|
|
7052
|
+
writable: false,
|
|
7053
|
+
configurable: false,
|
|
7054
|
+
enumerable: false
|
|
7055
|
+
});
|
|
7056
|
+
function getBaseURL() {
|
|
7057
|
+
const doc = "document" in globalThis ? globalThis.document : void 0;
|
|
7058
|
+
return doc && typeof doc == "object" && "baseURI" in doc && typeof doc.baseURI == "string" ? doc.baseURI : void 0;
|
|
7059
|
+
}
|
|
7534
7060
|
|
|
7535
7061
|
// src/provisioner/client.ts
|
|
7536
7062
|
var createProvisionerClient = (config) => {
|
|
@@ -7563,7 +7089,7 @@ var createProvisionerClient = (config) => {
|
|
|
7563
7089
|
import { execFile as execFile3 } from "node:child_process";
|
|
7564
7090
|
import { lstat, mkdir as mkdir3, realpath, writeFile as writeFile2 } from "node:fs/promises";
|
|
7565
7091
|
import { hostname } from "node:os";
|
|
7566
|
-
import { dirname as dirname2, join as
|
|
7092
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
7567
7093
|
import { setTimeout as setTimeout2 } from "node:timers/promises";
|
|
7568
7094
|
import { promisify as promisify3 } from "node:util";
|
|
7569
7095
|
|
|
@@ -7571,18 +7097,18 @@ import { promisify as promisify3 } from "node:util";
|
|
|
7571
7097
|
import { execFile as execFile2 } from "node:child_process";
|
|
7572
7098
|
import { mkdir, open } from "node:fs/promises";
|
|
7573
7099
|
import { homedir } from "node:os";
|
|
7574
|
-
import { dirname, join as
|
|
7100
|
+
import { dirname, join as join2 } from "node:path";
|
|
7575
7101
|
import { promisify as promisify2 } from "node:util";
|
|
7576
|
-
var workerStatePath = (config, creation) =>
|
|
7102
|
+
var workerStatePath = (config, creation) => join2(
|
|
7577
7103
|
config.projectsRoot,
|
|
7578
7104
|
".worker-state",
|
|
7579
7105
|
`project-${creation.projectId}`,
|
|
7580
7106
|
`creation-${creation.id}`
|
|
7581
7107
|
);
|
|
7582
|
-
var workerLogPath = (creation) =>
|
|
7108
|
+
var workerLogPath = (creation) => join2(homedir(), "Library/Logs", `baton-worker-creation-${creation.id}.log`);
|
|
7583
7109
|
var startAgent = async (config, agent, signal) => {
|
|
7584
7110
|
signal?.throwIfAborted();
|
|
7585
|
-
const plist =
|
|
7111
|
+
const plist = join2(homedir(), "Library/LaunchAgents", `${agent.label}.plist`);
|
|
7586
7112
|
await mkdir(dirname(plist), { recursive: true });
|
|
7587
7113
|
await mkdir(dirname(agent.log), { recursive: true });
|
|
7588
7114
|
const domain = `gui/${process.getuid?.()}`;
|
|
@@ -7668,24 +7194,29 @@ var installProvisionerAgent = async (config, configPath) => startAgent(config, {
|
|
|
7668
7194
|
],
|
|
7669
7195
|
cwd: dirname(configPath),
|
|
7670
7196
|
env: { HOME: homedir(), PATH: config.workerEnv.PATH ?? process.env.PATH ?? "/usr/bin:/bin" },
|
|
7671
|
-
log:
|
|
7197
|
+
log: join2(homedir(), "Library/Logs/baton-provisioner.log")
|
|
7672
7198
|
});
|
|
7673
7199
|
|
|
7674
7200
|
// src/provisioner/worker-template.ts
|
|
7675
7201
|
import { mkdir as mkdir2, writeFile } from "node:fs/promises";
|
|
7676
|
-
import { join as
|
|
7677
|
-
var
|
|
7202
|
+
import { join as join3 } from "node:path";
|
|
7203
|
+
var requireWorkerTemplate = (config, creation) => {
|
|
7678
7204
|
if (!workerTemplateAgentKinds(creation.templateId).includes(creation.agentKind))
|
|
7679
7205
|
throw new Error("agentKind is not supported by this template");
|
|
7680
|
-
if (creation.templateId === "mini-local") return
|
|
7206
|
+
if (creation.templateId === "mini-local") return null;
|
|
7681
7207
|
const profile = config.templates[creation.templateId];
|
|
7682
|
-
if (!profile) throw new Error(`template ${creation.templateId} is not configured`);
|
|
7208
|
+
if (!profile) throw new Error(`template ${creation.templateId} is not configured on this host`);
|
|
7209
|
+
return profile;
|
|
7210
|
+
};
|
|
7211
|
+
var workerTemplateEnvironment = async (config, creation, state) => {
|
|
7212
|
+
const profile = requireWorkerTemplate(config, creation);
|
|
7213
|
+
if (!profile) return config.workerEnv;
|
|
7683
7214
|
if (creation.agentKind !== "pi") return profile.workerEnv;
|
|
7684
7215
|
if (!profile.pi) throw new Error("Pi provider and model are not configured");
|
|
7685
|
-
const agentDir =
|
|
7216
|
+
const agentDir = join3(state, "pi");
|
|
7686
7217
|
await mkdir2(agentDir, { mode: 448 });
|
|
7687
7218
|
await writeFile(
|
|
7688
|
-
|
|
7219
|
+
join3(agentDir, "settings.json"),
|
|
7689
7220
|
JSON.stringify({
|
|
7690
7221
|
defaultProvider: profile.pi.provider,
|
|
7691
7222
|
defaultModel: profile.pi.model
|
|
@@ -7723,13 +7254,13 @@ var initRepository = async (config, creation, repoPath, progress, signal) => {
|
|
|
7723
7254
|
signal.throwIfAborted();
|
|
7724
7255
|
await mkdir3(config.projectsRoot, { recursive: true, mode: 448 });
|
|
7725
7256
|
const root = await realpath(config.projectsRoot);
|
|
7726
|
-
await directory(
|
|
7727
|
-
await mkdir3(
|
|
7257
|
+
await directory(join4(root, `project-${creation.projectId}`));
|
|
7258
|
+
await mkdir3(join4(root, `project-${creation.projectId}`, `creation-${creation.id}`), {
|
|
7728
7259
|
mode: 448
|
|
7729
7260
|
});
|
|
7730
7261
|
await progress("git");
|
|
7731
7262
|
await gitIn(config, repoPath, ["init", "-b", "main"], signal);
|
|
7732
|
-
await writeFile2(
|
|
7263
|
+
await writeFile2(join4(repoPath, ".git/info/exclude"), "\n.baton.json\n", { flag: "a" });
|
|
7733
7264
|
await gitIn(
|
|
7734
7265
|
config,
|
|
7735
7266
|
repoPath,
|
|
@@ -7750,7 +7281,7 @@ var adoptRepository = async (config, creation, repoPath, progress, signal) => {
|
|
|
7750
7281
|
await progress("directory");
|
|
7751
7282
|
signal.throwIfAborted();
|
|
7752
7283
|
const real = await realpath(repoPath);
|
|
7753
|
-
const project2 =
|
|
7284
|
+
const project2 = join4(await realpath(config.projectsRoot), `project-${creation.projectId}`);
|
|
7754
7285
|
if (dirname2(real) !== project2 || !(await lstat(real)).isDirectory())
|
|
7755
7286
|
throw new Error(`unsafe directory: ${repoPath}`);
|
|
7756
7287
|
await progress("git");
|
|
@@ -7765,19 +7296,20 @@ var adoptRepository = async (config, creation, repoPath, progress, signal) => {
|
|
|
7765
7296
|
throw new Error(`not the root of a Git work tree: ${repoPath}`);
|
|
7766
7297
|
};
|
|
7767
7298
|
var provisionWorker = async (config, creation, client, signal) => {
|
|
7299
|
+
requireWorkerTemplate(config, creation);
|
|
7768
7300
|
const shared = creation.repoPath !== null;
|
|
7769
|
-
const repoPath = creation.repoPath ??
|
|
7301
|
+
const repoPath = creation.repoPath ?? join4(config.projectsRoot, `project-${creation.projectId}`, `creation-${creation.id}`);
|
|
7770
7302
|
const progress = (step) => client.report(creation.id, { status: "running", step, repoPath }, signal);
|
|
7771
7303
|
await (shared ? adoptRepository : initRepository)(config, creation, repoPath, progress, signal);
|
|
7772
7304
|
await progress("register");
|
|
7773
7305
|
const result = await client.register(creation.id, hostname(), signal);
|
|
7774
7306
|
const state = workerStatePath(config, creation);
|
|
7775
7307
|
const root = await realpath(config.projectsRoot);
|
|
7776
|
-
await directory(
|
|
7777
|
-
await directory(
|
|
7308
|
+
await directory(join4(root, ".worker-state"));
|
|
7309
|
+
await directory(join4(root, ".worker-state", `project-${creation.projectId}`));
|
|
7778
7310
|
await mkdir3(state, { mode: 448 });
|
|
7779
|
-
await mkdir3(
|
|
7780
|
-
await writeFile2(
|
|
7311
|
+
await mkdir3(join4(state, "baton"), { mode: 448 });
|
|
7312
|
+
await writeFile2(join4(state, "baton/machine-id"), `${creation.machineId}
|
|
7781
7313
|
`, {
|
|
7782
7314
|
flag: "wx",
|
|
7783
7315
|
mode: 384
|
|
@@ -7791,7 +7323,7 @@ var provisionWorker = async (config, creation, client, signal) => {
|
|
|
7791
7323
|
machineId: result.worker.machineId,
|
|
7792
7324
|
apiToken: result.apiToken
|
|
7793
7325
|
});
|
|
7794
|
-
const configPath = shared ?
|
|
7326
|
+
const configPath = shared ? join4(state, "worker.json") : join4(repoPath, ".baton.json");
|
|
7795
7327
|
await writeFile2(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
7796
7328
|
`, { flag: "wx", mode: 384 });
|
|
7797
7329
|
await progress("start");
|
|
@@ -7916,346 +7448,57 @@ var runProvisioner = async (config, signal) => {
|
|
|
7916
7448
|
console.error(`[provisioner] stream disconnected (${event.code ?? "network"}); reconnecting`);
|
|
7917
7449
|
};
|
|
7918
7450
|
signal.addEventListener("abort", stop, { once: true });
|
|
7919
|
-
if (signal.aborted) stop();
|
|
7920
|
-
console.log("[provisioner] waiting for worker creation requests");
|
|
7921
|
-
try {
|
|
7922
|
-
await ended;
|
|
7923
|
-
await tail;
|
|
7924
|
-
} finally {
|
|
7925
|
-
stop();
|
|
7926
|
-
signal.removeEventListener("abort", stop);
|
|
7927
|
-
}
|
|
7928
|
-
if (fatal !== void 0) throw new Error(taskError(fatal, config));
|
|
7929
|
-
};
|
|
7930
|
-
|
|
7931
|
-
// src/commands/provisioner.ts
|
|
7932
|
-
var configArg = {
|
|
7933
|
-
config: {
|
|
7934
|
-
type: "string",
|
|
7935
|
-
required: true,
|
|
7936
|
-
description: "absolute path to private provisioner JSON config"
|
|
7937
|
-
}
|
|
7938
|
-
};
|
|
7939
|
-
var provisioner = defineCommand({
|
|
7940
|
-
meta: {
|
|
7941
|
-
name: "provisioner",
|
|
7942
|
-
description: "prepare local repositories and launch workers on macOS"
|
|
7943
|
-
},
|
|
7944
|
-
subCommands: {
|
|
7945
|
-
run: defineCommand({
|
|
7946
|
-
args: configArg,
|
|
7947
|
-
run: async ({ args }) => {
|
|
7948
|
-
const config = await loadProvisionerConfig(args.config);
|
|
7949
|
-
const abort = new AbortController();
|
|
7950
|
-
const stop = () => abort.abort();
|
|
7951
|
-
process.on("SIGINT", stop);
|
|
7952
|
-
process.on("SIGTERM", stop);
|
|
7953
|
-
try {
|
|
7954
|
-
await runProvisioner(config, abort.signal);
|
|
7955
|
-
} finally {
|
|
7956
|
-
process.off("SIGINT", stop);
|
|
7957
|
-
process.off("SIGTERM", stop);
|
|
7958
|
-
}
|
|
7959
|
-
}
|
|
7960
|
-
}),
|
|
7961
|
-
install: defineCommand({
|
|
7962
|
-
args: configArg,
|
|
7963
|
-
run: async ({ args }) => {
|
|
7964
|
-
const config = await loadProvisionerConfig(args.config);
|
|
7965
|
-
await installProvisionerAgent(config, args.config);
|
|
7966
|
-
console.log(
|
|
7967
|
-
"installed dev.fmap.baton-provisioner; inspect ~/Library/Logs/baton-provisioner.log"
|
|
7968
|
-
);
|
|
7969
|
-
}
|
|
7970
|
-
})
|
|
7971
|
-
}
|
|
7972
|
-
});
|
|
7973
|
-
|
|
7974
|
-
// src/commands/relay.ts
|
|
7975
|
-
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
7976
|
-
import { tmpdir as tmpdir2 } from "node:os";
|
|
7977
|
-
import { join as join6 } from "node:path";
|
|
7978
|
-
|
|
7979
|
-
// src/client/relay.ts
|
|
7980
|
-
var relayClient = (baseUrl) => {
|
|
7981
|
-
const u = (p) => `${baseUrl}${p}`;
|
|
7982
|
-
const authed = (token) => ({ authorization: `Bearer ${token}` });
|
|
7983
|
-
return {
|
|
7984
|
-
create: async () => {
|
|
7985
|
-
const res = await fetch(u("/relay/channels"), { method: "POST" });
|
|
7986
|
-
if (!res.ok) throw new Error(`POST /relay/channels \u2192 ${res.status}: ${await res.text()}`);
|
|
7987
|
-
return await res.json();
|
|
7988
|
-
},
|
|
7989
|
-
send: async (channelId, token, msg) => {
|
|
7990
|
-
const res = await fetch(u(`/relay/channels/${channelId}/messages`), {
|
|
7991
|
-
method: "POST",
|
|
7992
|
-
headers: { "content-type": "application/json", ...authed(token) },
|
|
7993
|
-
body: JSON.stringify(msg)
|
|
7994
|
-
});
|
|
7995
|
-
if (!res.ok) throw new Error(`POST relay message \u2192 ${res.status}: ${await res.text()}`);
|
|
7996
|
-
return await res.json();
|
|
7997
|
-
},
|
|
7998
|
-
listen: (channelId, token, opts) => {
|
|
7999
|
-
let cursor = opts.since ?? 0;
|
|
8000
|
-
const es = new EventSource(u(`/relay/channels/${channelId}/stream?since=${cursor}`), {
|
|
8001
|
-
fetch: (url, init2) => fetch(url, {
|
|
8002
|
-
...init2,
|
|
8003
|
-
headers: { ...init2?.headers, ...authed(token) }
|
|
8004
|
-
})
|
|
8005
|
-
});
|
|
8006
|
-
es.onmessage = (e) => {
|
|
8007
|
-
try {
|
|
8008
|
-
const m = JSON.parse(e.data);
|
|
8009
|
-
if (m.seq <= cursor) return;
|
|
8010
|
-
cursor = m.seq;
|
|
8011
|
-
opts.onMessage(m);
|
|
8012
|
-
} catch (err) {
|
|
8013
|
-
opts.onError?.(err);
|
|
8014
|
-
}
|
|
8015
|
-
};
|
|
8016
|
-
es.onerror = (err) => opts.onError?.(err);
|
|
8017
|
-
return () => es.close();
|
|
8018
|
-
}
|
|
8019
|
-
};
|
|
8020
|
-
};
|
|
8021
|
-
|
|
8022
|
-
// src/commands/relay.ts
|
|
8023
|
-
var PREVIEW2 = 280;
|
|
8024
|
-
var readStdin2 = async () => {
|
|
8025
|
-
const chunks = [];
|
|
8026
|
-
for await (const c of process.stdin) chunks.push(c);
|
|
8027
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
8028
|
-
};
|
|
8029
|
-
var inviteBlock2 = (url, channelId, token) => [
|
|
8030
|
-
"\u2500\u2500 Copy everything below to your peer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
8031
|
-
"You're invited to a live Claude\u2194Claude channel. Use the `hotline` skill in",
|
|
8032
|
-
"join mode, or run these two commands directly (pick your own NAME):",
|
|
8033
|
-
"",
|
|
8034
|
-
` baton relay listen ${channelId} --token ${token} --from NAME --url ${url}`,
|
|
8035
|
-
` baton relay send ${channelId} --token ${token} --from NAME --text "..." --url ${url}`,
|
|
8036
|
-
"",
|
|
8037
|
-
`connection: url=${url} channel=${channelId} token=${token}`,
|
|
8038
|
-
"\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
|
|
8039
|
-
].join("\n");
|
|
8040
|
-
var hostCommand = defineCommand({
|
|
8041
|
-
meta: { name: "host", description: "open a relay channel and print an invite for a peer" },
|
|
8042
|
-
args: {
|
|
8043
|
-
name: { type: "string", description: "your participant name (default: host)" },
|
|
8044
|
-
...common
|
|
8045
|
-
},
|
|
8046
|
-
run: async ({ args }) => {
|
|
8047
|
-
const url = resolveBaseUrl(args.url);
|
|
8048
|
-
const { channelId, token } = await relayClient(url).create();
|
|
8049
|
-
if (args.json) {
|
|
8050
|
-
console.log(toJson({ channelId, token, url, host: args.name ?? "host" }));
|
|
8051
|
-
return;
|
|
8052
|
-
}
|
|
8053
|
-
console.log(`channel ${channelId} opened
|
|
8054
|
-
`);
|
|
8055
|
-
console.log(inviteBlock2(url, channelId, token));
|
|
7451
|
+
if (signal.aborted) stop();
|
|
7452
|
+
console.log("[provisioner] waiting for worker creation requests");
|
|
7453
|
+
try {
|
|
7454
|
+
await ended;
|
|
7455
|
+
await tail;
|
|
7456
|
+
} finally {
|
|
7457
|
+
stop();
|
|
7458
|
+
signal.removeEventListener("abort", stop);
|
|
8056
7459
|
}
|
|
8057
|
-
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
...common
|
|
8067
|
-
},
|
|
8068
|
-
run: async ({ args }) => {
|
|
8069
|
-
const url = resolveBaseUrl(args.url);
|
|
8070
|
-
let text = args.text;
|
|
8071
|
-
if (text === void 0 && args.file) text = readFileSync3(args.file, "utf8");
|
|
8072
|
-
if (text === void 0 && !process.stdin.isTTY) text = await readStdin2();
|
|
8073
|
-
if (text === void 0 || text === "")
|
|
8074
|
-
throw new Error("nothing to send: provide text, --file <path>, or pipe stdin");
|
|
8075
|
-
const msg = await relayClient(url).send(args.channel, args.token, {
|
|
8076
|
-
from: args.from ?? "peer",
|
|
8077
|
-
text
|
|
8078
|
-
});
|
|
8079
|
-
if (args.json) console.log(toJson(msg));
|
|
8080
|
-
else console.log(`sent (seq ${msg.seq})`);
|
|
7460
|
+
if (fatal !== void 0) throw new Error(taskError(fatal, config));
|
|
7461
|
+
};
|
|
7462
|
+
|
|
7463
|
+
// src/commands/provisioner.ts
|
|
7464
|
+
var configArg = {
|
|
7465
|
+
config: {
|
|
7466
|
+
type: "string",
|
|
7467
|
+
required: true,
|
|
7468
|
+
description: "absolute path to private provisioner JSON config"
|
|
8081
7469
|
}
|
|
8082
|
-
}
|
|
8083
|
-
var
|
|
7470
|
+
};
|
|
7471
|
+
var provisioner = defineCommand({
|
|
8084
7472
|
meta: {
|
|
8085
|
-
name: "
|
|
8086
|
-
description: "
|
|
8087
|
-
},
|
|
8088
|
-
args: {
|
|
8089
|
-
channel: { type: "positional", required: true, description: "channel id" },
|
|
8090
|
-
token: { type: "string", required: true, description: "channel token" },
|
|
8091
|
-
from: {
|
|
8092
|
-
type: "string",
|
|
8093
|
-
description: "your name; messages from this name are skipped (no echo)"
|
|
8094
|
-
},
|
|
8095
|
-
since: { type: "string", description: "replay messages after this seq (default 0 = full)" },
|
|
8096
|
-
...common
|
|
7473
|
+
name: "provisioner",
|
|
7474
|
+
description: "prepare local repositories and launch workers on macOS"
|
|
8097
7475
|
},
|
|
8098
|
-
run: async ({ args }) => {
|
|
8099
|
-
const url = resolveBaseUrl(args.url);
|
|
8100
|
-
const me = args.from ?? "";
|
|
8101
|
-
const emit = (o) => {
|
|
8102
|
-
process.stdout.write(`${JSON.stringify(o)}
|
|
8103
|
-
`);
|
|
8104
|
-
};
|
|
8105
|
-
const spillDir = join6(tmpdir2(), "hotline", args.channel);
|
|
8106
|
-
mkdirSync2(spillDir, { recursive: true });
|
|
8107
|
-
const surface = (m) => {
|
|
8108
|
-
const text = typeof m.text === "string" ? m.text : "";
|
|
8109
|
-
const file = join6(spillDir, `${m.seq}.txt`);
|
|
8110
|
-
writeFileSync4(file, text);
|
|
8111
|
-
const truncated = text.length > PREVIEW2;
|
|
8112
|
-
emit({
|
|
8113
|
-
type: "relay.message",
|
|
8114
|
-
seq: m.seq,
|
|
8115
|
-
from: m.from,
|
|
8116
|
-
ts: m.ts,
|
|
8117
|
-
chars: text.length,
|
|
8118
|
-
truncated,
|
|
8119
|
-
preview: truncated ? `${text.slice(0, PREVIEW2)} \u2026` : text,
|
|
8120
|
-
file
|
|
8121
|
-
});
|
|
8122
|
-
};
|
|
8123
|
-
const describe3 = (e) => {
|
|
8124
|
-
const ev = e;
|
|
8125
|
-
return ev?.code ? `${ev.code}${ev.message ? ` ${ev.message}` : ""}` : String(e);
|
|
8126
|
-
};
|
|
8127
|
-
const close = relayClient(url).listen(args.channel, args.token, {
|
|
8128
|
-
since: args.since ? Number(args.since) : 0,
|
|
8129
|
-
// Skip our own messages (they come back over the same channel).
|
|
8130
|
-
onMessage: (m) => {
|
|
8131
|
-
if (m.from !== me) surface(m);
|
|
8132
|
-
},
|
|
8133
|
-
onError: (e) => emit({ type: "relay.error", error: describe3(e) })
|
|
8134
|
-
});
|
|
8135
|
-
emit({ type: "relay.listening", channel: args.channel, from: me, url });
|
|
8136
|
-
await new Promise((resolve4) => {
|
|
8137
|
-
const stop = () => {
|
|
8138
|
-
close();
|
|
8139
|
-
resolve4();
|
|
8140
|
-
};
|
|
8141
|
-
process.on("SIGINT", stop);
|
|
8142
|
-
process.on("SIGTERM", stop);
|
|
8143
|
-
});
|
|
8144
|
-
}
|
|
8145
|
-
});
|
|
8146
|
-
var relay = defineCommand({
|
|
8147
|
-
meta: { name: "relay", description: "Claude\u2194Claude live channel: host / listen / send" },
|
|
8148
|
-
subCommands: { host: hostCommand, listen: listenCommand2, send: sendCommand2 }
|
|
8149
|
-
});
|
|
8150
|
-
|
|
8151
|
-
// src/commands/requirement.ts
|
|
8152
|
-
var createRequirement = (c, input, json) => c.requirements.create(input).then((r) => renderOne(r, fmtRequirement, json));
|
|
8153
|
-
var updateRequirement = (c, id, patch, json) => c.requirements.update(id, patch).then((r) => renderOne(r, fmtRequirement, json));
|
|
8154
|
-
var listRequirements = (c, projectId, json) => c.requirements.listByProject(projectId).then((rs) => renderList(rs, fmtRequirement, json));
|
|
8155
|
-
var getRequirement = (c, id, json) => c.requirements.get(id).then((r) => renderOne(r, fmtRequirement, json));
|
|
8156
|
-
var setRequirementStatus = (c, id, status, json) => c.requirements.setStatus(id, status).then((r) => renderOne(r, fmtRequirement, json));
|
|
8157
|
-
var removeRequirement = (c, id, label, json) => c.requirements.remove(id).then(() => removed("requirement", label, json));
|
|
8158
|
-
var resolveByCode = async (c, projectId, code) => (await c.requirements.getByCode(projectId, code)).id;
|
|
8159
|
-
var requirement = defineCommand({
|
|
8160
|
-
meta: { name: "requirement", description: "manage requirements" },
|
|
8161
7476
|
subCommands: {
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
args: {
|
|
8165
|
-
title: { type: "positional", required: true },
|
|
8166
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
8167
|
-
desc: { type: "string", description: "description" },
|
|
8168
|
-
body: { type: "string", description: "requirement body (markdown)" },
|
|
8169
|
-
...common
|
|
8170
|
-
},
|
|
8171
|
-
run: async ({ args }) => {
|
|
8172
|
-
console.log(
|
|
8173
|
-
await createRequirement(
|
|
8174
|
-
clientFor(args),
|
|
8175
|
-
{
|
|
8176
|
-
projectId: resolveProjectId(args),
|
|
8177
|
-
title: args.title,
|
|
8178
|
-
description: args.desc,
|
|
8179
|
-
body: args.body
|
|
8180
|
-
},
|
|
8181
|
-
Boolean(args.json)
|
|
8182
|
-
)
|
|
8183
|
-
);
|
|
8184
|
-
}
|
|
8185
|
-
}),
|
|
8186
|
-
update: defineCommand({
|
|
8187
|
-
meta: { name: "update", description: "update a requirement title / body" },
|
|
8188
|
-
args: {
|
|
8189
|
-
code: { type: "positional", required: true, description: "requirement code (R-N)" },
|
|
8190
|
-
title: { type: "string", description: "new title" },
|
|
8191
|
-
body: { type: "string", description: "new body (markdown)" },
|
|
8192
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
8193
|
-
...common
|
|
8194
|
-
},
|
|
8195
|
-
run: async ({ args }) => {
|
|
8196
|
-
const patch = {
|
|
8197
|
-
...args.title !== void 0 ? { title: args.title } : {},
|
|
8198
|
-
...args.body !== void 0 ? { body: args.body } : {}
|
|
8199
|
-
};
|
|
8200
|
-
if (Object.keys(patch).length === 0) throw new Error("pass --title and/or --body");
|
|
8201
|
-
const c = clientFor(args);
|
|
8202
|
-
const id = await resolveByCode(c, resolveProjectId(args), args.code);
|
|
8203
|
-
console.log(await updateRequirement(c, id, patch, Boolean(args.json)));
|
|
8204
|
-
}
|
|
8205
|
-
}),
|
|
8206
|
-
ls: defineCommand({
|
|
8207
|
-
meta: { name: "ls", description: "list requirements in a project" },
|
|
8208
|
-
args: {
|
|
8209
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
8210
|
-
...common
|
|
8211
|
-
},
|
|
8212
|
-
run: async ({ args }) => {
|
|
8213
|
-
console.log(
|
|
8214
|
-
await listRequirements(clientFor(args), resolveProjectId(args), Boolean(args.json))
|
|
8215
|
-
);
|
|
8216
|
-
}
|
|
8217
|
-
}),
|
|
8218
|
-
get: defineCommand({
|
|
8219
|
-
meta: { name: "get", description: "get a requirement by code (R-N)" },
|
|
8220
|
-
args: {
|
|
8221
|
-
code: { type: "positional", required: true, description: "requirement code, e.g. R-1" },
|
|
8222
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
8223
|
-
...common
|
|
8224
|
-
},
|
|
7477
|
+
run: defineCommand({
|
|
7478
|
+
args: configArg,
|
|
8225
7479
|
run: async ({ args }) => {
|
|
8226
|
-
const
|
|
8227
|
-
const
|
|
8228
|
-
|
|
7480
|
+
const config = await loadProvisionerConfig(args.config);
|
|
7481
|
+
const abort = new AbortController();
|
|
7482
|
+
const stop = () => abort.abort();
|
|
7483
|
+
process.on("SIGINT", stop);
|
|
7484
|
+
process.on("SIGTERM", stop);
|
|
7485
|
+
try {
|
|
7486
|
+
await runProvisioner(config, abort.signal);
|
|
7487
|
+
} finally {
|
|
7488
|
+
process.off("SIGINT", stop);
|
|
7489
|
+
process.off("SIGTERM", stop);
|
|
7490
|
+
}
|
|
8229
7491
|
}
|
|
8230
7492
|
}),
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
args: {
|
|
8234
|
-
code: { type: "positional", required: true, description: "requirement code (R-N)" },
|
|
8235
|
-
status: { type: "positional", required: true },
|
|
8236
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
8237
|
-
...common
|
|
8238
|
-
},
|
|
7493
|
+
install: defineCommand({
|
|
7494
|
+
args: configArg,
|
|
8239
7495
|
run: async ({ args }) => {
|
|
8240
|
-
const
|
|
8241
|
-
|
|
7496
|
+
const config = await loadProvisionerConfig(args.config);
|
|
7497
|
+
await installProvisionerAgent(config, args.config);
|
|
8242
7498
|
console.log(
|
|
8243
|
-
|
|
7499
|
+
"installed dev.fmap.baton-provisioner; inspect ~/Library/Logs/baton-provisioner.log"
|
|
8244
7500
|
);
|
|
8245
7501
|
}
|
|
8246
|
-
}),
|
|
8247
|
-
rm: defineCommand({
|
|
8248
|
-
meta: { name: "rm", description: "delete a requirement by code" },
|
|
8249
|
-
args: {
|
|
8250
|
-
code: { type: "positional", required: true },
|
|
8251
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
8252
|
-
...common
|
|
8253
|
-
},
|
|
8254
|
-
run: async ({ args }) => {
|
|
8255
|
-
const c = clientFor(args);
|
|
8256
|
-
const id = await resolveByCode(c, resolveProjectId(args), args.code);
|
|
8257
|
-
console.log(await removeRequirement(c, id, args.code, Boolean(args.json)));
|
|
8258
|
-
}
|
|
8259
7502
|
})
|
|
8260
7503
|
}
|
|
8261
7504
|
});
|
|
@@ -8579,14 +7822,14 @@ import { randomUUID } from "node:crypto";
|
|
|
8579
7822
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
8580
7823
|
|
|
8581
7824
|
// src/session/runner/transcript.ts
|
|
8582
|
-
import { readdirSync, readFileSync as
|
|
7825
|
+
import { readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
8583
7826
|
import { homedir as homedir2 } from "node:os";
|
|
8584
|
-
import { join as
|
|
7827
|
+
import { join as join5 } from "node:path";
|
|
8585
7828
|
var findTranscriptPath = (agentSessionId) => {
|
|
8586
|
-
const root =
|
|
7829
|
+
const root = join5(homedir2(), ".claude", "projects");
|
|
8587
7830
|
try {
|
|
8588
7831
|
for (const dir of readdirSync(root)) {
|
|
8589
|
-
const candidate =
|
|
7832
|
+
const candidate = join5(root, dir, `${agentSessionId}.jsonl`);
|
|
8590
7833
|
try {
|
|
8591
7834
|
if (statSync(candidate).isFile()) return candidate;
|
|
8592
7835
|
} catch {
|
|
@@ -8657,7 +7900,7 @@ var readFirstExchange = (agentSessionId) => {
|
|
|
8657
7900
|
const path = findTranscriptPath(agentSessionId);
|
|
8658
7901
|
if (!path) return null;
|
|
8659
7902
|
try {
|
|
8660
|
-
return parseFirstExchange(
|
|
7903
|
+
return parseFirstExchange(readFileSync2(path, "utf8"));
|
|
8661
7904
|
} catch {
|
|
8662
7905
|
return null;
|
|
8663
7906
|
}
|
|
@@ -8665,12 +7908,12 @@ var readFirstExchange = (agentSessionId) => {
|
|
|
8665
7908
|
|
|
8666
7909
|
// src/session/runner/turn.ts
|
|
8667
7910
|
import { mkdir as mkdir5, writeFile as writeFile3 } from "node:fs/promises";
|
|
8668
|
-
import { join as
|
|
7911
|
+
import { join as join10 } from "node:path";
|
|
8669
7912
|
|
|
8670
7913
|
// src/session/runner/attachments.ts
|
|
8671
7914
|
import { createWriteStream } from "node:fs";
|
|
8672
7915
|
import { mkdir as mkdir4 } from "node:fs/promises";
|
|
8673
|
-
import { join as
|
|
7916
|
+
import { join as join6 } from "node:path";
|
|
8674
7917
|
import { Readable } from "node:stream";
|
|
8675
7918
|
import { pipeline } from "node:stream/promises";
|
|
8676
7919
|
var dedupe = (name, taken) => {
|
|
@@ -8700,8 +7943,8 @@ var materializeAttachments = async (opts) => {
|
|
|
8700
7943
|
const name = dedupe(att.filename, taken);
|
|
8701
7944
|
const res = await fetchImpl(`${opts.serverBase}${att.url}`);
|
|
8702
7945
|
if (!res.ok || !res.body) throw new Error(`attachment ${att.id} \u2192 ${res.status}`);
|
|
8703
|
-
await pipeline(Readable.fromWeb(res.body), createWriteStream(
|
|
8704
|
-
paths.push(
|
|
7946
|
+
await pipeline(Readable.fromWeb(res.body), createWriteStream(join6(dir, name)));
|
|
7947
|
+
paths.push(join6(dir, name));
|
|
8705
7948
|
}
|
|
8706
7949
|
return paths;
|
|
8707
7950
|
};
|
|
@@ -8717,7 +7960,7 @@ ${text}` : header;
|
|
|
8717
7960
|
};
|
|
8718
7961
|
|
|
8719
7962
|
// src/session/runner/codex.ts
|
|
8720
|
-
import { join as
|
|
7963
|
+
import { join as join7 } from "node:path";
|
|
8721
7964
|
import { Codex } from "@openai/codex-sdk";
|
|
8722
7965
|
|
|
8723
7966
|
// src/session/runner/sdk-env.ts
|
|
@@ -8879,7 +8122,7 @@ async function* startCodexEvents(config, input, worker2, opts) {
|
|
|
8879
8122
|
const env = compactEnv(buildSdkEnv(opts.envOverlay));
|
|
8880
8123
|
const codex = new Codex(env ? { env } : void 0);
|
|
8881
8124
|
const resuming = !config.agentSessionId.startsWith("pending:");
|
|
8882
|
-
const addDirs = additionalDirs([
|
|
8125
|
+
const addDirs = additionalDirs([join7(config.runtimeDir, "attachments")]);
|
|
8883
8126
|
const sandboxMode = codexSandboxMode(opts.planMode ?? false);
|
|
8884
8127
|
const approvalPolicy = codexApprovalPolicy();
|
|
8885
8128
|
const networkAccessEnabled = codexNetworkAccess();
|
|
@@ -8920,7 +8163,7 @@ async function* startCodexEvents(config, input, worker2, opts) {
|
|
|
8920
8163
|
// src/session/runner/pi.ts
|
|
8921
8164
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
8922
8165
|
import { homedir as homedir3 } from "node:os";
|
|
8923
|
-
import { join as
|
|
8166
|
+
import { join as join8 } from "node:path";
|
|
8924
8167
|
var newPiTurnState = (startedAt = Date.now()) => ({
|
|
8925
8168
|
startedAt,
|
|
8926
8169
|
usage: {},
|
|
@@ -9065,7 +8308,7 @@ async function* startPiEvents(config, input, opts) {
|
|
|
9065
8308
|
agentDir,
|
|
9066
8309
|
// pi discovers .pi/ and .agents/ skills natively; Baton workers deploy theirs
|
|
9067
8310
|
// under .claude/skills (project and user level).
|
|
9068
|
-
additionalSkillPaths: [
|
|
8311
|
+
additionalSkillPaths: [join8(config.cwd, ".claude/skills"), join8(homedir3(), ".claude/skills")]
|
|
9069
8312
|
});
|
|
9070
8313
|
await resourceLoader.reload();
|
|
9071
8314
|
const existing = pi.SessionManager.findById(config.cwd, config.agentSessionId);
|
|
@@ -9140,11 +8383,11 @@ async function* startPiEvents(config, input, opts) {
|
|
|
9140
8383
|
}
|
|
9141
8384
|
|
|
9142
8385
|
// src/session/runner/query.ts
|
|
9143
|
-
import { join as
|
|
8386
|
+
import { join as join9 } from "node:path";
|
|
9144
8387
|
var startQuery = (config, text, resuming, queryFn, abortController, log, { envOverlay, planMode = false, model, effort } = {}) => {
|
|
9145
8388
|
const env = buildSdkEnv(envOverlay);
|
|
9146
8389
|
const exe = claudeExecutable();
|
|
9147
|
-
const addDirs = additionalDirs([
|
|
8390
|
+
const addDirs = additionalDirs([join9(config.runtimeDir, "attachments")]);
|
|
9148
8391
|
const level = claudeEffort(effort);
|
|
9149
8392
|
if (addDirs) log(`[add-dir] ${addDirs.join(", ")}`);
|
|
9150
8393
|
if (planMode) log("[plan] read-only planning turn");
|
|
@@ -9395,7 +8638,7 @@ var UnsettledExecution = class extends Error {
|
|
|
9395
8638
|
var materializeImages = async (config, execution) => {
|
|
9396
8639
|
const images = execution.message.payload.images ?? [];
|
|
9397
8640
|
if (!images.length) return [];
|
|
9398
|
-
const directory2 =
|
|
8641
|
+
const directory2 = join10(
|
|
9399
8642
|
config.runtimeDir,
|
|
9400
8643
|
"attachments",
|
|
9401
8644
|
`message-${execution.message.id}`,
|
|
@@ -9406,7 +8649,7 @@ var materializeImages = async (config, execution) => {
|
|
|
9406
8649
|
images.map(async (image, index) => {
|
|
9407
8650
|
const match = /^data:image\/(png|jpeg|webp|gif);base64,([A-Za-z0-9+/=\r\n]+)$/.exec(image);
|
|
9408
8651
|
if (!match) throw new Error("unsupported pasted image");
|
|
9409
|
-
const path =
|
|
8652
|
+
const path = join10(directory2, `pasted-${index + 1}.${match[1]}`);
|
|
9410
8653
|
await writeFile3(path, Buffer.from(match[2] ?? "", "base64"));
|
|
9411
8654
|
return path;
|
|
9412
8655
|
})
|
|
@@ -9415,7 +8658,7 @@ var materializeImages = async (config, execution) => {
|
|
|
9415
8658
|
var buildPrompt = async (config, execution, fetchImpl) => {
|
|
9416
8659
|
const { text: rawText, attachments = [] } = execution.message.payload;
|
|
9417
8660
|
const paths = attachments.length ? await materializeAttachments({
|
|
9418
|
-
directory:
|
|
8661
|
+
directory: join10(
|
|
9419
8662
|
config.runtimeDir,
|
|
9420
8663
|
"attachments",
|
|
9421
8664
|
`message-${execution.message.id}`,
|
|
@@ -9672,15 +8915,15 @@ var runDaemon = async (config, deps, signal) => {
|
|
|
9672
8915
|
// src/worker/runtime-paths.ts
|
|
9673
8916
|
import { createHash } from "node:crypto";
|
|
9674
8917
|
import { homedir as homedir4 } from "node:os";
|
|
9675
|
-
import { join as
|
|
9676
|
-
var workerRuntimeDir = (owner, env = process.env) =>
|
|
9677
|
-
env.XDG_DATA_HOME ??
|
|
8918
|
+
import { join as join11 } from "node:path";
|
|
8919
|
+
var workerRuntimeDir = (owner, env = process.env) => join11(
|
|
8920
|
+
env.XDG_DATA_HOME ?? join11(env.HOME ?? homedir4(), ".local/share"),
|
|
9678
8921
|
"baton",
|
|
9679
8922
|
"runtime",
|
|
9680
8923
|
createHash("sha256").update(owner.server).digest("hex"),
|
|
9681
8924
|
`worker-${owner.workerId}`
|
|
9682
8925
|
);
|
|
9683
|
-
var sessionRuntimeDir = (owner, sessionId, env = process.env) =>
|
|
8926
|
+
var sessionRuntimeDir = (owner, sessionId, env = process.env) => join11(workerRuntimeDir(owner, env), "sessions", String(sessionId));
|
|
9684
8927
|
|
|
9685
8928
|
// src/commands/session/run.ts
|
|
9686
8929
|
var bearerFetch = (token) => (input, init2) => fetch(input, {
|
|
@@ -9775,6 +9018,25 @@ var sessionRunCommand = defineCommand({
|
|
|
9775
9018
|
}
|
|
9776
9019
|
});
|
|
9777
9020
|
|
|
9021
|
+
// src/commands/attach.ts
|
|
9022
|
+
import { openAsBlob as openAsBlob2 } from "node:fs";
|
|
9023
|
+
import { basename as basename2 } from "node:path";
|
|
9024
|
+
var attachPaths = (raw) => (raw === void 0 ? [] : Array.isArray(raw) ? raw : [raw]).flatMap((p) => p.split(",")).map((p) => p.trim()).filter(Boolean);
|
|
9025
|
+
var uploadAttachments = async (client, sessionId, paths) => {
|
|
9026
|
+
const out = [];
|
|
9027
|
+
for (const path of paths) {
|
|
9028
|
+
const body = await openAsBlob2(path, { type: contentTypeForPath(path) });
|
|
9029
|
+
out.push(
|
|
9030
|
+
await client.sessions.uploadAttachment(sessionId, {
|
|
9031
|
+
filename: basename2(path),
|
|
9032
|
+
contentType: contentTypeForPath(path),
|
|
9033
|
+
body
|
|
9034
|
+
})
|
|
9035
|
+
);
|
|
9036
|
+
}
|
|
9037
|
+
return out;
|
|
9038
|
+
};
|
|
9039
|
+
|
|
9778
9040
|
// src/commands/session/send.ts
|
|
9779
9041
|
var sessionSendCommand = defineCommand({
|
|
9780
9042
|
meta: { name: "send", description: "post a chat message into a session (no streaming reply)" },
|
|
@@ -9822,6 +9084,60 @@ var sessionStopCommand = defineCommand({
|
|
|
9822
9084
|
}
|
|
9823
9085
|
});
|
|
9824
9086
|
|
|
9087
|
+
// src/commands/session/tell.ts
|
|
9088
|
+
var TELL_LOOP_LIMIT = 10;
|
|
9089
|
+
var TELL_HEADER = /^\[Message from baton session #\d+ /gm;
|
|
9090
|
+
var renderTell = (from, body) => [
|
|
9091
|
+
`[Message from baton session #${from.id} ${JSON.stringify(from.name)}]`,
|
|
9092
|
+
`To reply, run: baton session tell ${from.id} "<your reply>"`,
|
|
9093
|
+
"Reply only if a response is actually needed.",
|
|
9094
|
+
"",
|
|
9095
|
+
body
|
|
9096
|
+
].join("\n");
|
|
9097
|
+
var headerCount = (event) => {
|
|
9098
|
+
const text = event.payload?.text ?? "";
|
|
9099
|
+
return text.match(TELL_HEADER)?.length ?? 0;
|
|
9100
|
+
};
|
|
9101
|
+
var countConsecutiveTells = (events) => {
|
|
9102
|
+
const newestFirst = events.filter((event) => event.type === "user_message").map(headerCount).reverse();
|
|
9103
|
+
const end = newestFirst.indexOf(0);
|
|
9104
|
+
return (end < 0 ? newestFirst : newestFirst.slice(0, end)).reduce((sum, n) => sum + n, 0);
|
|
9105
|
+
};
|
|
9106
|
+
var sendTell = async (c, { fromId, toId, body }) => {
|
|
9107
|
+
if (body.trim() === "") throw new Error("nothing to send: message text is empty");
|
|
9108
|
+
if (toId === fromId) throw new Error("cannot tell your own session");
|
|
9109
|
+
const [from, events] = await Promise.all([c.sessions.get(fromId), c.sessions.listEvents(fromId)]);
|
|
9110
|
+
const received = countConsecutiveTells(events);
|
|
9111
|
+
if (received >= TELL_LOOP_LIMIT)
|
|
9112
|
+
throw new Error(
|
|
9113
|
+
`not sent: this session received ${received} agent messages in a row. Stop and ask a human; a message from them resets the count.`
|
|
9114
|
+
);
|
|
9115
|
+
return c.sessions.sendMessage(toId, renderTell(from, body));
|
|
9116
|
+
};
|
|
9117
|
+
var parseId = (raw) => raw !== void 0 && /^[1-9]\d*$/.test(raw) ? Number(raw) : null;
|
|
9118
|
+
var sessionTellCommand = defineCommand({
|
|
9119
|
+
meta: {
|
|
9120
|
+
name: "tell",
|
|
9121
|
+
description: "Send a message to another agent session in this workspace. It includes who sent it and how to reply, and wakes the target if needed. Delivery is fire-and-forget: end your turn, and any reply arrives as a new message. You cannot read another session; ask it instead."
|
|
9122
|
+
},
|
|
9123
|
+
args: {
|
|
9124
|
+
session: { type: "positional", required: true, description: "target session int id" },
|
|
9125
|
+
text: { type: "positional", required: true, description: "message text" },
|
|
9126
|
+
...common
|
|
9127
|
+
},
|
|
9128
|
+
run: async ({ args }) => {
|
|
9129
|
+
const fromId = parseId(process.env.BATON_SESSION_ID);
|
|
9130
|
+
const bearer = process.env.BATON_WORKER_TOKEN;
|
|
9131
|
+
if (fromId === null || !bearer)
|
|
9132
|
+
throw new Error("baton session tell only works inside a baton session");
|
|
9133
|
+
const toId = parseId(args.session);
|
|
9134
|
+
if (toId === null) throw new Error(`invalid session "${args.session}": pass the session id`);
|
|
9135
|
+
const client = createClient(resolveBaseUrl(args.url), { bearer });
|
|
9136
|
+
const result = await sendTell(client, { fromId, toId, body: args.text });
|
|
9137
|
+
console.log(args.json ? toJson(result) : `told session #${toId} (input ${result.input.id})`);
|
|
9138
|
+
}
|
|
9139
|
+
});
|
|
9140
|
+
|
|
9825
9141
|
// src/commands/session/terminal.ts
|
|
9826
9142
|
var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
9827
9143
|
var sessionTerminalCommand = defineCommand({
|
|
@@ -9870,6 +9186,7 @@ var session = defineCommand({
|
|
|
9870
9186
|
rename: sessionRenameCommand,
|
|
9871
9187
|
rm: sessionRmCommand,
|
|
9872
9188
|
send: sessionSendCommand,
|
|
9189
|
+
tell: sessionTellCommand,
|
|
9873
9190
|
ls: sessionLsCommand,
|
|
9874
9191
|
get: sessionGetCommand,
|
|
9875
9192
|
run: sessionRunCommand,
|
|
@@ -9877,177 +9194,18 @@ var session = defineCommand({
|
|
|
9877
9194
|
}
|
|
9878
9195
|
});
|
|
9879
9196
|
|
|
9880
|
-
// src/commands/task.ts
|
|
9881
|
-
var createTask = (c, input, json) => c.tasks.create(input).then((t) => renderOne(t, fmtTask, json));
|
|
9882
|
-
var updateTask = (c, id, patch, json) => c.tasks.update(id, patch).then((t) => renderOne(t, fmtTask, json));
|
|
9883
|
-
var listTasks = (c, requirementId, json) => c.tasks.listByRequirement(requirementId).then((ts) => renderList(ts, fmtTask, json));
|
|
9884
|
-
var getTask = (c, id, json) => c.tasks.get(id).then((t) => renderOne(t, fmtTask, json));
|
|
9885
|
-
var setTaskStatus = (c, id, status, json) => c.tasks.setStatus(id, status).then((t) => renderOne(t, fmtTask, json));
|
|
9886
|
-
var removeTask = (c, id, label, json) => c.tasks.remove(id).then(() => removed("task", label, json));
|
|
9887
|
-
var addTaskComment = (c, taskId, body, workerId, json) => c.tasks.addComment(taskId, body, workerId).then((x) => renderOne(x, fmtComment, json));
|
|
9888
|
-
var listTaskComments = (c, taskId, json) => c.tasks.listComments(taskId).then((xs) => renderList(xs, fmtComment, json));
|
|
9889
|
-
var resolveReqByCode = async (c, projectId, code) => (await c.requirements.getByCode(projectId, code)).id;
|
|
9890
|
-
var resolveTaskByCode = async (c, projectId, code) => (await c.tasks.getByCode(projectId, code)).id;
|
|
9891
|
-
var task = defineCommand({
|
|
9892
|
-
meta: { name: "task", description: "manage tasks" },
|
|
9893
|
-
subCommands: {
|
|
9894
|
-
create: defineCommand({
|
|
9895
|
-
meta: { name: "create", description: "create a task" },
|
|
9896
|
-
args: {
|
|
9897
|
-
title: { type: "positional", required: true },
|
|
9898
|
-
requirement: { type: "string", required: true, description: "requirement code (R-N)" },
|
|
9899
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
9900
|
-
body: { type: "string", description: "task body (markdown)" },
|
|
9901
|
-
deps: { type: "string", description: "comma-separated dependency task codes (T-N,T-N)" },
|
|
9902
|
-
...common
|
|
9903
|
-
},
|
|
9904
|
-
run: async ({ args }) => {
|
|
9905
|
-
const c = clientFor(args);
|
|
9906
|
-
const projectId = resolveProjectId(args);
|
|
9907
|
-
const requirementId = await resolveReqByCode(c, projectId, args.requirement);
|
|
9908
|
-
const depCodes = splitCsv(args.deps) ?? [];
|
|
9909
|
-
const dependsOn = await Promise.all(
|
|
9910
|
-
depCodes.map((code) => resolveTaskByCode(c, projectId, code))
|
|
9911
|
-
);
|
|
9912
|
-
console.log(
|
|
9913
|
-
await createTask(
|
|
9914
|
-
c,
|
|
9915
|
-
{
|
|
9916
|
-
requirementId,
|
|
9917
|
-
title: args.title,
|
|
9918
|
-
body: args.body,
|
|
9919
|
-
dependsOn: dependsOn.length ? dependsOn : void 0
|
|
9920
|
-
},
|
|
9921
|
-
Boolean(args.json)
|
|
9922
|
-
)
|
|
9923
|
-
);
|
|
9924
|
-
}
|
|
9925
|
-
}),
|
|
9926
|
-
update: defineCommand({
|
|
9927
|
-
meta: { name: "update", description: "update a task title / body" },
|
|
9928
|
-
args: {
|
|
9929
|
-
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
9930
|
-
title: { type: "string", description: "new title" },
|
|
9931
|
-
body: { type: "string", description: "new body (markdown)" },
|
|
9932
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
9933
|
-
...common
|
|
9934
|
-
},
|
|
9935
|
-
run: async ({ args }) => {
|
|
9936
|
-
const patch = {
|
|
9937
|
-
...args.title !== void 0 ? { title: args.title } : {},
|
|
9938
|
-
...args.body !== void 0 ? { body: args.body } : {}
|
|
9939
|
-
};
|
|
9940
|
-
if (Object.keys(patch).length === 0) throw new Error("pass --title and/or --body");
|
|
9941
|
-
const c = clientFor(args);
|
|
9942
|
-
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
9943
|
-
console.log(await updateTask(c, id, patch, Boolean(args.json)));
|
|
9944
|
-
}
|
|
9945
|
-
}),
|
|
9946
|
-
ls: defineCommand({
|
|
9947
|
-
meta: { name: "ls", description: "list tasks in a requirement" },
|
|
9948
|
-
args: {
|
|
9949
|
-
requirement: { type: "string", required: true, description: "requirement code (R-N)" },
|
|
9950
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
9951
|
-
...common
|
|
9952
|
-
},
|
|
9953
|
-
run: async ({ args }) => {
|
|
9954
|
-
const c = clientFor(args);
|
|
9955
|
-
const reqId = await resolveReqByCode(c, resolveProjectId(args), args.requirement);
|
|
9956
|
-
console.log(await listTasks(c, reqId, Boolean(args.json)));
|
|
9957
|
-
}
|
|
9958
|
-
}),
|
|
9959
|
-
get: defineCommand({
|
|
9960
|
-
meta: { name: "get", description: "get a task by code (T-N)" },
|
|
9961
|
-
args: {
|
|
9962
|
-
code: { type: "positional", required: true },
|
|
9963
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
9964
|
-
...common
|
|
9965
|
-
},
|
|
9966
|
-
run: async ({ args }) => {
|
|
9967
|
-
const c = clientFor(args);
|
|
9968
|
-
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
9969
|
-
console.log(await getTask(c, id, Boolean(args.json)));
|
|
9970
|
-
}
|
|
9971
|
-
}),
|
|
9972
|
-
"set-status": defineCommand({
|
|
9973
|
-
meta: {
|
|
9974
|
-
name: "set-status",
|
|
9975
|
-
description: "set task status (todo|in_progress|blocked|done|failed|cancelled)"
|
|
9976
|
-
},
|
|
9977
|
-
args: {
|
|
9978
|
-
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
9979
|
-
status: { type: "positional", required: true },
|
|
9980
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
9981
|
-
...common
|
|
9982
|
-
},
|
|
9983
|
-
run: async ({ args }) => {
|
|
9984
|
-
const c = clientFor(args);
|
|
9985
|
-
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
9986
|
-
console.log(await setTaskStatus(c, id, args.status, Boolean(args.json)));
|
|
9987
|
-
}
|
|
9988
|
-
}),
|
|
9989
|
-
rm: defineCommand({
|
|
9990
|
-
meta: { name: "rm", description: "delete a task by code" },
|
|
9991
|
-
args: {
|
|
9992
|
-
code: { type: "positional", required: true },
|
|
9993
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
9994
|
-
...common
|
|
9995
|
-
},
|
|
9996
|
-
run: async ({ args }) => {
|
|
9997
|
-
const c = clientFor(args);
|
|
9998
|
-
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
9999
|
-
console.log(await removeTask(c, id, args.code, Boolean(args.json)));
|
|
10000
|
-
}
|
|
10001
|
-
}),
|
|
10002
|
-
comment: defineCommand({
|
|
10003
|
-
meta: { name: "comment", description: "append-only task comments" },
|
|
10004
|
-
subCommands: {
|
|
10005
|
-
add: defineCommand({
|
|
10006
|
-
meta: { name: "add", description: "add a comment to a task" },
|
|
10007
|
-
args: {
|
|
10008
|
-
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
10009
|
-
body: { type: "positional", required: true, description: "comment text (markdown)" },
|
|
10010
|
-
worker: { type: "string", description: "attribute to a worker id (omit = human)" },
|
|
10011
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
10012
|
-
...common
|
|
10013
|
-
},
|
|
10014
|
-
run: async ({ args }) => {
|
|
10015
|
-
const c = clientFor(args);
|
|
10016
|
-
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
10017
|
-
const workerId = args.worker ? Number(args.worker) : void 0;
|
|
10018
|
-
console.log(await addTaskComment(c, id, args.body, workerId, Boolean(args.json)));
|
|
10019
|
-
}
|
|
10020
|
-
}),
|
|
10021
|
-
ls: defineCommand({
|
|
10022
|
-
meta: { name: "ls", description: "list a task\u2019s comments in order" },
|
|
10023
|
-
args: {
|
|
10024
|
-
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
10025
|
-
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
10026
|
-
...common
|
|
10027
|
-
},
|
|
10028
|
-
run: async ({ args }) => {
|
|
10029
|
-
const c = clientFor(args);
|
|
10030
|
-
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
10031
|
-
console.log(await listTaskComments(c, id, Boolean(args.json)));
|
|
10032
|
-
}
|
|
10033
|
-
})
|
|
10034
|
-
}
|
|
10035
|
-
})
|
|
10036
|
-
}
|
|
10037
|
-
});
|
|
10038
|
-
|
|
10039
9197
|
// src/commands/worker/index.ts
|
|
10040
9198
|
import { hostname as osHostname } from "node:os";
|
|
10041
9199
|
|
|
10042
9200
|
// src/worker/bundled-skills.ts
|
|
10043
9201
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
10044
9202
|
import { cpSync, existsSync as existsSync5 } from "node:fs";
|
|
10045
|
-
import { dirname as dirname4, join as
|
|
9203
|
+
import { dirname as dirname4, join as join12 } from "node:path";
|
|
10046
9204
|
import { fileURLToPath } from "node:url";
|
|
10047
9205
|
|
|
10048
9206
|
// src/worker/git-exclude.ts
|
|
10049
9207
|
import { spawnSync } from "node:child_process";
|
|
10050
|
-
import { appendFileSync, existsSync as existsSync4, mkdirSync
|
|
9208
|
+
import { appendFileSync, existsSync as existsSync4, mkdirSync, readFileSync as readFileSync3 } from "node:fs";
|
|
10051
9209
|
import { dirname as dirname3, isAbsolute as isAbsolute3, resolve as resolve3 } from "node:path";
|
|
10052
9210
|
var ensureExcluded = (cwd, pattern) => {
|
|
10053
9211
|
const result = spawnSync("git", ["-C", cwd, "rev-parse", "--git-path", "info/exclude"], {
|
|
@@ -10061,9 +9219,9 @@ var ensureExcluded = (cwd, pattern) => {
|
|
|
10061
9219
|
}
|
|
10062
9220
|
const location = result.stdout.trim();
|
|
10063
9221
|
const path = isAbsolute3(location) ? location : resolve3(cwd, location);
|
|
10064
|
-
const current = existsSync4(path) ?
|
|
9222
|
+
const current = existsSync4(path) ? readFileSync3(path, "utf8") : "";
|
|
10065
9223
|
if (current.split("\n").includes(pattern)) return;
|
|
10066
|
-
|
|
9224
|
+
mkdirSync(dirname3(path), { recursive: true });
|
|
10067
9225
|
appendFileSync(path, `${current && !current.endsWith("\n") ? "\n" : ""}${pattern}
|
|
10068
9226
|
`);
|
|
10069
9227
|
};
|
|
@@ -10074,8 +9232,8 @@ var TARGETS = [`.claude/skills/${SKILL_NAME}`, `.agents/skills/${SKILL_NAME}`];
|
|
|
10074
9232
|
var bundledSkillPath = () => {
|
|
10075
9233
|
const here = dirname4(fileURLToPath(import.meta.url));
|
|
10076
9234
|
const candidates = [
|
|
10077
|
-
|
|
10078
|
-
|
|
9235
|
+
join12(here, "..", "skills", SKILL_NAME),
|
|
9236
|
+
join12(here, "..", "..", "skills", SKILL_NAME)
|
|
10079
9237
|
];
|
|
10080
9238
|
const found = candidates.find(existsSync5);
|
|
10081
9239
|
if (!found) throw new Error(`bundled skill missing: ${SKILL_NAME}`);
|
|
@@ -10092,7 +9250,7 @@ var syncBundledArtifactSkill = (cwd) => {
|
|
|
10092
9250
|
const source = bundledSkillPath();
|
|
10093
9251
|
TARGETS.filter((target) => !isTracked(cwd, target)).forEach((target) => {
|
|
10094
9252
|
ensureExcluded(cwd, `${target}/`);
|
|
10095
|
-
cpSync(source,
|
|
9253
|
+
cpSync(source, join12(cwd, target), { recursive: true, force: true });
|
|
10096
9254
|
});
|
|
10097
9255
|
};
|
|
10098
9256
|
|
|
@@ -10363,7 +9521,7 @@ var openCommitDownload = async (repo, commit, path, signal) => {
|
|
|
10363
9521
|
// src/worker/files/disk.ts
|
|
10364
9522
|
import { constants as constants2 } from "node:fs";
|
|
10365
9523
|
import { open as open2, readdir, realpath as realpath3, stat as stat3 } from "node:fs/promises";
|
|
10366
|
-
import { isAbsolute as isAbsolute4, join as
|
|
9524
|
+
import { isAbsolute as isAbsolute4, join as join13, relative, sep } from "node:path";
|
|
10367
9525
|
import { Readable as Readable3 } from "node:stream";
|
|
10368
9526
|
var isMissing = (error) => ["ENOENT", "ENOTDIR", "ELOOP"].includes(error.code ?? "");
|
|
10369
9527
|
var childPath = (parent, name) => parent ? `${parent}/${name}` : name;
|
|
@@ -10376,7 +9534,7 @@ var resolveInside = async (root, path, allowRoot) => {
|
|
|
10376
9534
|
const rel = checkedPath(path, allowRoot);
|
|
10377
9535
|
let real;
|
|
10378
9536
|
try {
|
|
10379
|
-
real = await realpath3(
|
|
9537
|
+
real = await realpath3(join13(root, rel));
|
|
10380
9538
|
} catch (error) {
|
|
10381
9539
|
if (isMissing(error)) throw notFound(rel);
|
|
10382
9540
|
throw error;
|
|
@@ -10406,7 +9564,7 @@ var toEntry = async (root, dir, dirent) => {
|
|
|
10406
9564
|
if (dirent.isDirectory())
|
|
10407
9565
|
return isExcludedDirectoryName(dirent.name) ? null : { name: dirent.name, path, kind: "directory" };
|
|
10408
9566
|
if (dirent.isFile()) return { name: dirent.name, path, kind: "file" };
|
|
10409
|
-
return dirent.isSymbolicLink() ? symlinkEntry(root,
|
|
9567
|
+
return dirent.isSymbolicLink() ? symlinkEntry(root, join13(dir.real, dirent.name), dirent.name, path) : null;
|
|
10410
9568
|
};
|
|
10411
9569
|
var listDirectory = async (root, path) => {
|
|
10412
9570
|
const dir = await resolveInside(root, path, true);
|
|
@@ -10429,7 +9587,7 @@ var searchFiles = async (root, query3, now = Date.now) => {
|
|
|
10429
9587
|
const dir = pending[index] ?? "";
|
|
10430
9588
|
let dirents;
|
|
10431
9589
|
try {
|
|
10432
|
-
dirents = await readdir(
|
|
9590
|
+
dirents = await readdir(join13(root, dir), { withFileTypes: true });
|
|
10433
9591
|
} catch (error) {
|
|
10434
9592
|
console.warn(`[files] search skipped unreadable directory ${dir || "."}`, error);
|
|
10435
9593
|
continue;
|
|
@@ -10673,14 +9831,14 @@ var createLiveness = (deps) => {
|
|
|
10673
9831
|
};
|
|
10674
9832
|
|
|
10675
9833
|
// src/worker/service-supervisor.ts
|
|
10676
|
-
import { mkdirSync as
|
|
9834
|
+
import { mkdirSync as mkdirSync2 } from "node:fs";
|
|
10677
9835
|
import { stat as stat4 } from "node:fs/promises";
|
|
10678
|
-
import { join as
|
|
9836
|
+
import { join as join15 } from "node:path";
|
|
10679
9837
|
|
|
10680
9838
|
// src/worker/service-process.ts
|
|
10681
9839
|
import { spawn as spawn3 } from "node:child_process";
|
|
10682
9840
|
import { closeSync, existsSync as existsSync6, openSync } from "node:fs";
|
|
10683
|
-
import { dirname as dirname5, join as
|
|
9841
|
+
import { dirname as dirname5, join as join14 } from "node:path";
|
|
10684
9842
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
10685
9843
|
var START_TIMEOUT_MS = 1e4;
|
|
10686
9844
|
var isWrapperMessage = (message) => {
|
|
@@ -10691,7 +9849,7 @@ var isWrapperMessage = (message) => {
|
|
|
10691
9849
|
};
|
|
10692
9850
|
var binPath = () => {
|
|
10693
9851
|
const here = dirname5(fileURLToPath2(import.meta.url));
|
|
10694
|
-
const devShim =
|
|
9852
|
+
const devShim = join14(here, "..", "..", "bin", "baton.mjs");
|
|
10695
9853
|
return existsSync6(devShim) ? devShim : fileURLToPath2(import.meta.url);
|
|
10696
9854
|
};
|
|
10697
9855
|
var startServiceProcess = (input) => {
|
|
@@ -10785,9 +9943,9 @@ var createServiceSupervisor = (deps) => {
|
|
|
10785
9943
|
if (code !== "ENOENT" && code !== "ENOTDIR") throw error;
|
|
10786
9944
|
return report({ requestId, ok: false, error: `directory not found: ${cwd}`, status: 400 });
|
|
10787
9945
|
}
|
|
10788
|
-
const logDir =
|
|
10789
|
-
const logPath =
|
|
10790
|
-
|
|
9946
|
+
const logDir = join15(workerRuntimeDir(cfg), "services");
|
|
9947
|
+
const logPath = join15(logDir, `${name}.log`);
|
|
9948
|
+
mkdirSync2(logDir, { recursive: true, mode: 448 });
|
|
10791
9949
|
if (entries.has(name))
|
|
10792
9950
|
return report({
|
|
10793
9951
|
requestId,
|
|
@@ -10852,7 +10010,7 @@ import { spawn as spawn4 } from "node:child_process";
|
|
|
10852
10010
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
10853
10011
|
import { existsSync as existsSync7 } from "node:fs";
|
|
10854
10012
|
import { mkdir as mkdir6, rm as rm3, stat as stat5 } from "node:fs/promises";
|
|
10855
|
-
import { dirname as dirname6, join as
|
|
10013
|
+
import { dirname as dirname6, join as join19 } from "node:path";
|
|
10856
10014
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
10857
10015
|
import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
|
|
10858
10016
|
|
|
@@ -10945,8 +10103,8 @@ var generateTitle = async (input) => {
|
|
|
10945
10103
|
|
|
10946
10104
|
// src/session/runner/title-codex.ts
|
|
10947
10105
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
10948
|
-
import { tmpdir
|
|
10949
|
-
import { join as
|
|
10106
|
+
import { tmpdir } from "node:os";
|
|
10107
|
+
import { join as join16 } from "node:path";
|
|
10950
10108
|
import { Codex as Codex2 } from "@openai/codex-sdk";
|
|
10951
10109
|
var generateTitleWithCodex = async (input) => {
|
|
10952
10110
|
const { userText, assistantText } = input;
|
|
@@ -10955,7 +10113,7 @@ var generateTitleWithCodex = async (input) => {
|
|
|
10955
10113
|
const timer = setTimeout(() => abort.abort(), TITLE_TIMEOUT_MS);
|
|
10956
10114
|
let cwd = "";
|
|
10957
10115
|
try {
|
|
10958
|
-
cwd = await mkdtemp(
|
|
10116
|
+
cwd = await mkdtemp(join16(tmpdir(), "baton-title-"));
|
|
10959
10117
|
const client = input.client ?? new Codex2();
|
|
10960
10118
|
const thread = client.startThread({
|
|
10961
10119
|
workingDirectory: cwd,
|
|
@@ -10983,8 +10141,8 @@ var generateTitleWithCodex = async (input) => {
|
|
|
10983
10141
|
|
|
10984
10142
|
// src/session/runner/title-pi.ts
|
|
10985
10143
|
import { mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
|
|
10986
|
-
import { tmpdir as
|
|
10987
|
-
import { join as
|
|
10144
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
10145
|
+
import { join as join17 } from "node:path";
|
|
10988
10146
|
var generateTitleWithPi = async (input) => {
|
|
10989
10147
|
const { userText, assistantText } = input;
|
|
10990
10148
|
if (`${userText}${assistantText}`.trim().length < 4) return { kind: "declined" };
|
|
@@ -10992,7 +10150,7 @@ var generateTitleWithPi = async (input) => {
|
|
|
10992
10150
|
let timedOut = false;
|
|
10993
10151
|
let timer;
|
|
10994
10152
|
try {
|
|
10995
|
-
cwd = await mkdtemp2(
|
|
10153
|
+
cwd = await mkdtemp2(join17(tmpdir2(), "baton-title-"));
|
|
10996
10154
|
const pi = await import("@earendil-works/pi-coding-agent");
|
|
10997
10155
|
const agentDir = pi.getAgentDir();
|
|
10998
10156
|
const resourceLoader = new pi.DefaultResourceLoader({
|
|
@@ -11044,11 +10202,11 @@ var generateTitleWithPi = async (input) => {
|
|
|
11044
10202
|
// src/worker/session-process.ts
|
|
11045
10203
|
import { execFile as execFile5 } from "node:child_process";
|
|
11046
10204
|
import { readFile as readFile3, rename, writeFile as writeFile4 } from "node:fs/promises";
|
|
11047
|
-
import { join as
|
|
10205
|
+
import { join as join18 } from "node:path";
|
|
11048
10206
|
import { promisify as promisify5 } from "node:util";
|
|
11049
10207
|
var run3 = promisify5(execFile5);
|
|
11050
10208
|
var RUNNER_RECORD = ".baton-runner.json";
|
|
11051
|
-
var recordPath = (cwd) =>
|
|
10209
|
+
var recordPath = (cwd) => join18(cwd, RUNNER_RECORD);
|
|
11052
10210
|
var codeOf = (error) => typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
11053
10211
|
var readRunnerRecord = async (cwd) => {
|
|
11054
10212
|
let raw;
|
|
@@ -11116,7 +10274,7 @@ var stopRecordedRunner = async (record, expected, graceMs = 5e3) => {
|
|
|
11116
10274
|
// src/worker/session-supervisor.ts
|
|
11117
10275
|
var binPath2 = () => {
|
|
11118
10276
|
const here = dirname6(fileURLToPath3(import.meta.url));
|
|
11119
|
-
const devShim =
|
|
10277
|
+
const devShim = join19(here, "..", "..", "bin", "baton.mjs");
|
|
11120
10278
|
return existsSync7(devShim) ? devShim : fileURLToPath3(import.meta.url);
|
|
11121
10279
|
};
|
|
11122
10280
|
var createSessionSupervisor = (deps) => {
|
|
@@ -11361,7 +10519,7 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
11361
10519
|
import { existsSync as existsSync8, readdirSync as readdirSync2 } from "node:fs";
|
|
11362
10520
|
import { createRequire as createModuleRequire } from "node:module";
|
|
11363
10521
|
import { homedir as homedir5 } from "node:os";
|
|
11364
|
-
import { dirname as dirname7, join as
|
|
10522
|
+
import { dirname as dirname7, join as join20 } from "node:path";
|
|
11365
10523
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
11366
10524
|
var MAX_TERMINALS = 10;
|
|
11367
10525
|
var claudePtyCommand = (agentSessionId, hasJsonl, env = process.env) => ({
|
|
@@ -11382,13 +10540,13 @@ var piPtyCommand = (agentSessionId, env = process.env) => {
|
|
|
11382
10540
|
const override = env.BATON_PI_BIN?.trim();
|
|
11383
10541
|
if (override) return { file: override, args };
|
|
11384
10542
|
const entry = fileURLToPath4(import.meta.resolve("@earendil-works/pi-coding-agent"));
|
|
11385
|
-
return { file: process.execPath, args: [
|
|
10543
|
+
return { file: process.execPath, args: [join20(dirname7(entry), "bundle", "cli.js"), ...args] };
|
|
11386
10544
|
};
|
|
11387
10545
|
var hasSessionJsonl = (agentSessionId) => {
|
|
11388
|
-
const root =
|
|
10546
|
+
const root = join20(homedir5(), ".claude", "projects");
|
|
11389
10547
|
if (!existsSync8(root)) return false;
|
|
11390
10548
|
for (const dir of readdirSync2(root))
|
|
11391
|
-
if (existsSync8(
|
|
10549
|
+
if (existsSync8(join20(root, dir, `${agentSessionId}.jsonl`))) return true;
|
|
11392
10550
|
return false;
|
|
11393
10551
|
};
|
|
11394
10552
|
var ptyCommand = (kind, agentSessionId) => ({
|
|
@@ -11585,18 +10743,18 @@ var runWorkerDaemon = async (cfg, client, signal) => {
|
|
|
11585
10743
|
|
|
11586
10744
|
// src/worker/machine-id.ts
|
|
11587
10745
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
11588
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
10746
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
|
|
11589
10747
|
import { homedir as homedir6 } from "node:os";
|
|
11590
|
-
import { dirname as dirname8, join as
|
|
11591
|
-
var machineIdPath = (env = process.env) =>
|
|
10748
|
+
import { dirname as dirname8, join as join21 } from "node:path";
|
|
10749
|
+
var machineIdPath = (env = process.env) => join21(env.XDG_DATA_HOME ?? join21(env.HOME ?? homedir6(), ".local/share"), "baton", "machine-id");
|
|
11592
10750
|
var readOrCreateMachineId = (path = machineIdPath()) => {
|
|
11593
10751
|
if (existsSync9(path)) {
|
|
11594
|
-
const s =
|
|
10752
|
+
const s = readFileSync4(path, "utf8").trim();
|
|
11595
10753
|
if (s) return s;
|
|
11596
10754
|
}
|
|
11597
10755
|
const id = randomUUID3();
|
|
11598
|
-
|
|
11599
|
-
|
|
10756
|
+
mkdirSync3(dirname8(path), { recursive: true });
|
|
10757
|
+
writeFileSync2(path, `${id}
|
|
11600
10758
|
`, "utf8");
|
|
11601
10759
|
return id;
|
|
11602
10760
|
};
|
|
@@ -11605,7 +10763,7 @@ var readOrCreateMachineId = (path = machineIdPath()) => {
|
|
|
11605
10763
|
var projectArg = {
|
|
11606
10764
|
project: { type: "string", description: "project id (overrides .baton.json)" }
|
|
11607
10765
|
};
|
|
11608
|
-
var
|
|
10766
|
+
var positiveId2 = (raw) => {
|
|
11609
10767
|
const id = Number(raw);
|
|
11610
10768
|
if (!Number.isSafeInteger(id) || id <= 0) throw new Error("positive id required");
|
|
11611
10769
|
return id;
|
|
@@ -11614,12 +10772,12 @@ var workerTemplatesCommand = defineCommand({
|
|
|
11614
10772
|
meta: { name: "templates", description: "list worker creation templates for a project" },
|
|
11615
10773
|
args: { ...projectArg, ...common },
|
|
11616
10774
|
run: async ({ args }) => {
|
|
11617
|
-
const list = await clientFor(args).workerCreations.templates(
|
|
10775
|
+
const list = await clientFor(args).workerCreations.templates(positiveId2(resolveProjectId(args)));
|
|
11618
10776
|
console.log(renderList(list, fmtWorkerTemplate, Boolean(args.json)));
|
|
11619
10777
|
}
|
|
11620
10778
|
});
|
|
11621
10779
|
var workerCreateCommand = defineCommand({
|
|
11622
|
-
meta: { name: "create", description: "request a worker from
|
|
10780
|
+
meta: { name: "create", description: "request a worker from a template (asynchronous)" },
|
|
11623
10781
|
args: {
|
|
11624
10782
|
...projectArg,
|
|
11625
10783
|
...common,
|
|
@@ -11633,6 +10791,10 @@ var workerCreateCommand = defineCommand({
|
|
|
11633
10791
|
repoPath: {
|
|
11634
10792
|
type: "string",
|
|
11635
10793
|
description: "share an existing worker's directory in this project (default: a new one)"
|
|
10794
|
+
},
|
|
10795
|
+
host: {
|
|
10796
|
+
type: "string",
|
|
10797
|
+
description: "host name or id (default: the workspace's only host)"
|
|
11636
10798
|
}
|
|
11637
10799
|
},
|
|
11638
10800
|
run: async ({ args }) => {
|
|
@@ -11643,15 +10805,16 @@ var workerCreateCommand = defineCommand({
|
|
|
11643
10805
|
throw new Error("agentKind is not supported by this template");
|
|
11644
10806
|
const name = args.name.trim();
|
|
11645
10807
|
if (!name) throw new Error("worker name required");
|
|
11646
|
-
const
|
|
11647
|
-
|
|
11648
|
-
|
|
11649
|
-
|
|
11650
|
-
|
|
11651
|
-
|
|
11652
|
-
|
|
11653
|
-
}
|
|
11654
|
-
|
|
10808
|
+
const client = clientFor(args);
|
|
10809
|
+
const projectId = positiveId2(resolveProjectId(args));
|
|
10810
|
+
const host2 = args.host ? findHost(await client.workerCreations.hosts(projectId), args.host) : null;
|
|
10811
|
+
const creation = await client.workerCreations.create(projectId, {
|
|
10812
|
+
templateId: args.template,
|
|
10813
|
+
name,
|
|
10814
|
+
agentKind,
|
|
10815
|
+
...args.repoPath ? { repoPath: args.repoPath } : {},
|
|
10816
|
+
...host2 ? { hostId: host2.id } : {}
|
|
10817
|
+
});
|
|
11655
10818
|
console.log(renderOne(creation, fmtWorkerCreation, Boolean(args.json)));
|
|
11656
10819
|
}
|
|
11657
10820
|
});
|
|
@@ -11662,7 +10825,7 @@ var workerCreationCommand = defineCommand({
|
|
|
11662
10825
|
args: { ...projectArg, ...common },
|
|
11663
10826
|
run: async ({ args }) => {
|
|
11664
10827
|
const list = await clientFor(args).workerCreations.listByProject(
|
|
11665
|
-
|
|
10828
|
+
positiveId2(resolveProjectId(args))
|
|
11666
10829
|
);
|
|
11667
10830
|
console.log(renderList(list, fmtWorkerCreation, Boolean(args.json)));
|
|
11668
10831
|
}
|
|
@@ -11670,7 +10833,7 @@ var workerCreationCommand = defineCommand({
|
|
|
11670
10833
|
get: defineCommand({
|
|
11671
10834
|
args: { ...common, id: { type: "positional", required: true } },
|
|
11672
10835
|
run: async ({ args }) => {
|
|
11673
|
-
const creation = await clientFor(args).workerCreations.get(
|
|
10836
|
+
const creation = await clientFor(args).workerCreations.get(positiveId2(args.id));
|
|
11674
10837
|
console.log(renderOne(creation, fmtWorkerCreation, Boolean(args.json)));
|
|
11675
10838
|
}
|
|
11676
10839
|
})
|
|
@@ -11962,24 +11125,21 @@ var workspace = defineCommand({
|
|
|
11962
11125
|
var main = defineCommand({
|
|
11963
11126
|
meta: {
|
|
11964
11127
|
name: "baton",
|
|
11965
|
-
description: "baton \u2014 run a worker daemon; manage projects /
|
|
11128
|
+
description: "baton \u2014 run a worker daemon; manage projects / sessions"
|
|
11966
11129
|
},
|
|
11967
11130
|
// Order matters: high-level verbs first so --help shows them on top.
|
|
11968
11131
|
subCommands: {
|
|
11969
11132
|
init,
|
|
11970
11133
|
worker,
|
|
11971
11134
|
provisioner,
|
|
11135
|
+
host,
|
|
11972
11136
|
session,
|
|
11973
11137
|
service,
|
|
11974
11138
|
artifact,
|
|
11975
11139
|
loop,
|
|
11976
11140
|
notify,
|
|
11977
|
-
relay,
|
|
11978
|
-
channel,
|
|
11979
11141
|
workspace,
|
|
11980
|
-
project
|
|
11981
|
-
requirement,
|
|
11982
|
-
task
|
|
11142
|
+
project
|
|
11983
11143
|
}
|
|
11984
11144
|
});
|
|
11985
11145
|
runMain(main);
|