commonswarm 0.1.41 → 0.1.43
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/cswarm.cjs +258 -34
- package/package.json +1 -1
package/cswarm.cjs
CHANGED
|
@@ -22943,7 +22943,7 @@ async function sendFileCommand(options, command2) {
|
|
|
22943
22943
|
const body = await response.json().catch(() => null);
|
|
22944
22944
|
if (!response.ok) {
|
|
22945
22945
|
const code = typeof body?.error === "string" ? body.error : "http_error";
|
|
22946
|
-
const message = typeof body?.message === "string" ? body.message : `file command failed (HTTP ${response.status})`;
|
|
22946
|
+
const message = typeof body?.message === "string" ? body.message : `file command failed (HTTP ${response.status}) DEBUGBODY=${JSON.stringify(body).slice(0, 300)}`;
|
|
22947
22947
|
throw new FileCommandRefused(response.status, code, message);
|
|
22948
22948
|
}
|
|
22949
22949
|
if (!body || typeof body !== "object") {
|
|
@@ -23119,6 +23119,40 @@ async function listFilesAsHuman(target2, accessToken, workspaceId2, fetcher = fe
|
|
|
23119
23119
|
return body;
|
|
23120
23120
|
}
|
|
23121
23121
|
|
|
23122
|
+
// src/cloud/brain.ts
|
|
23123
|
+
var BRAIN_FILE_PREFIX = "brain--";
|
|
23124
|
+
var BRAIN_FILE_SUFFIX = ".md";
|
|
23125
|
+
var BRAIN_TOPIC_MAX_LENGTH = 255 - BRAIN_FILE_PREFIX.length - BRAIN_FILE_SUFFIX.length;
|
|
23126
|
+
var BRAIN_TOPIC_RE = /^[a-z0-9][a-z0-9._-]*$/;
|
|
23127
|
+
var BrainTopicError = class extends Error {
|
|
23128
|
+
name = "BrainTopicError";
|
|
23129
|
+
};
|
|
23130
|
+
function canonicalBrainTopic(value) {
|
|
23131
|
+
const topic = value.trim().toLowerCase();
|
|
23132
|
+
if (topic.length < 1 || topic.length > BRAIN_TOPIC_MAX_LENGTH || !BRAIN_TOPIC_RE.test(topic)) {
|
|
23133
|
+
throw new BrainTopicError(
|
|
23134
|
+
`brain topics use ${BRAIN_TOPIC_MAX_LENGTH} or fewer lowercase letters, numbers, dots, dashes, or underscores; start with a letter or number`
|
|
23135
|
+
);
|
|
23136
|
+
}
|
|
23137
|
+
return topic;
|
|
23138
|
+
}
|
|
23139
|
+
function brainFileName(value) {
|
|
23140
|
+
return `${BRAIN_FILE_PREFIX}${canonicalBrainTopic(value)}${BRAIN_FILE_SUFFIX}`;
|
|
23141
|
+
}
|
|
23142
|
+
function brainTopicFromFileName(name) {
|
|
23143
|
+
const lower = name.toLowerCase();
|
|
23144
|
+
if (!lower.startsWith(BRAIN_FILE_PREFIX) || !lower.endsWith(BRAIN_FILE_SUFFIX)) {
|
|
23145
|
+
return null;
|
|
23146
|
+
}
|
|
23147
|
+
const topic = lower.slice(BRAIN_FILE_PREFIX.length, -BRAIN_FILE_SUFFIX.length);
|
|
23148
|
+
try {
|
|
23149
|
+
return canonicalBrainTopic(topic);
|
|
23150
|
+
} catch (error) {
|
|
23151
|
+
if (error instanceof BrainTopicError) return null;
|
|
23152
|
+
throw error;
|
|
23153
|
+
}
|
|
23154
|
+
}
|
|
23155
|
+
|
|
23122
23156
|
// src/cloud/feedback.ts
|
|
23123
23157
|
var FeedbackTransportError = class extends Error {
|
|
23124
23158
|
name = "FeedbackTransportError";
|
|
@@ -30034,6 +30068,12 @@ function parseDeliveryReceipt(value) {
|
|
|
30034
30068
|
);
|
|
30035
30069
|
}
|
|
30036
30070
|
const row = value;
|
|
30071
|
+
if (Object.hasOwn(row, "recipient_user_id")) {
|
|
30072
|
+
return {
|
|
30073
|
+
recipient_user_id: uuid4(row.recipient_user_id, "recipient_user_id"),
|
|
30074
|
+
seen_at: nullableTimestamp2(row.seen_at, "seen_at")
|
|
30075
|
+
};
|
|
30076
|
+
}
|
|
30037
30077
|
const ackedAt = nullableTimestamp2(row.acked_at, "acked_at");
|
|
30038
30078
|
const ackOutcome = row.ack_outcome === null ? null : typeof row.ack_outcome === "string" && ACK_OUTCOMES.has(row.ack_outcome) ? row.ack_outcome : (() => {
|
|
30039
30079
|
throw new DeliveryReceiptReadError(
|
|
@@ -30085,10 +30125,10 @@ function parseDeliveryReceiptResult(value) {
|
|
|
30085
30125
|
);
|
|
30086
30126
|
}
|
|
30087
30127
|
const receipts = body.receipts.map(parseDeliveryReceipt);
|
|
30088
|
-
if (body.addressed === false && receipts.
|
|
30128
|
+
if (body.addressed === false && receipts.some((row) => "recipient_agent_principal_id" in row)) {
|
|
30089
30129
|
throw new DeliveryReceiptReadError(
|
|
30090
30130
|
"protocol",
|
|
30091
|
-
"delivery receipt read returned
|
|
30131
|
+
"delivery receipt read returned an agent recipient for a broadcast"
|
|
30092
30132
|
);
|
|
30093
30133
|
}
|
|
30094
30134
|
if (body.addressed === true && receipts.length === 0) {
|
|
@@ -30098,7 +30138,9 @@ function parseDeliveryReceiptResult(value) {
|
|
|
30098
30138
|
);
|
|
30099
30139
|
}
|
|
30100
30140
|
const recipientIds = new Set(
|
|
30101
|
-
receipts.map(
|
|
30141
|
+
receipts.map(
|
|
30142
|
+
(row) => "recipient_agent_principal_id" in row ? `agent:${row.recipient_agent_principal_id}` : `human:${row.recipient_user_id}`
|
|
30143
|
+
)
|
|
30102
30144
|
);
|
|
30103
30145
|
if (recipientIds.size !== receipts.length) {
|
|
30104
30146
|
throw new DeliveryReceiptReadError(
|
|
@@ -30197,6 +30239,9 @@ async function readAgentDeliveryReceipts(target2, token, workspaceId2, signalId,
|
|
|
30197
30239
|
}
|
|
30198
30240
|
|
|
30199
30241
|
// src/cloud/receipts.ts
|
|
30242
|
+
function humanReceipt(receipt) {
|
|
30243
|
+
return "recipient_user_id" in receipt;
|
|
30244
|
+
}
|
|
30200
30245
|
function signalReceiptCliState(receipt, nowMs) {
|
|
30201
30246
|
const state = deliveryReceiptState(receipt, nowMs);
|
|
30202
30247
|
if (state === "enqueued") return "not_delivered";
|
|
@@ -30215,13 +30260,24 @@ function newAskCommand(report, receipt) {
|
|
|
30215
30260
|
return `cswarm ask "<question>" --to ${receipt.recipient_agent_principal_id} --workspace-id ${report.workspaceId}`;
|
|
30216
30261
|
}
|
|
30217
30262
|
function renderSignalReceiptReport(report, nowMs = Date.now()) {
|
|
30263
|
+
const humanReceipts = report.receipts.filter(humanReceipt);
|
|
30264
|
+
const agentReceipts = report.receipts.filter(
|
|
30265
|
+
(receipt) => !humanReceipt(receipt)
|
|
30266
|
+
);
|
|
30267
|
+
const humanSections = humanReceipts.map(
|
|
30268
|
+
(receipt) => receipt.seen_at === null ? `Not seen yet \u2014 the member's browser reports seen state when the message is viewed.` : [
|
|
30269
|
+
`Seen by ${receipt.recipient_user_id} at ${receipt.seen_at}.`,
|
|
30270
|
+
"This is a browser proxy: the message row was in view while the document had focus."
|
|
30271
|
+
].join("\n")
|
|
30272
|
+
);
|
|
30218
30273
|
if (!report.addressed) {
|
|
30219
30274
|
return [
|
|
30220
30275
|
"This was a broadcast; no agent was addressed and none was woken.",
|
|
30276
|
+
...humanSections,
|
|
30221
30277
|
`To wake an agent, send a new ask with: cswarm ask "<text>" --to <agent> --workspace-id ${report.workspaceId}`
|
|
30222
30278
|
].join("\n");
|
|
30223
30279
|
}
|
|
30224
|
-
const sections =
|
|
30280
|
+
const sections = agentReceipts.map((receipt) => {
|
|
30225
30281
|
const state = deliveryReceiptState(receipt, nowMs);
|
|
30226
30282
|
if (state === "enqueued") {
|
|
30227
30283
|
return [
|
|
@@ -30276,25 +30332,31 @@ function renderSignalReceiptReport(report, nowMs = Date.now()) {
|
|
|
30276
30332
|
`Ask the agent's operator to check its listener with: ${listenerStatusCommand(report, receipt)}`
|
|
30277
30333
|
].join("\n");
|
|
30278
30334
|
});
|
|
30279
|
-
return sections.join("\n\n");
|
|
30335
|
+
return [...humanSections, ...sections].join("\n\n");
|
|
30280
30336
|
}
|
|
30281
30337
|
function signalReceiptJsonPayload(report, nowMs = Date.now()) {
|
|
30282
30338
|
return {
|
|
30283
30339
|
workspace_id: report.workspaceId,
|
|
30284
30340
|
signal_id: report.signalId,
|
|
30285
30341
|
broadcast: !report.addressed,
|
|
30286
|
-
receipts: report.receipts.map(
|
|
30287
|
-
|
|
30288
|
-
|
|
30289
|
-
|
|
30290
|
-
|
|
30291
|
-
|
|
30292
|
-
|
|
30293
|
-
|
|
30294
|
-
|
|
30295
|
-
|
|
30296
|
-
|
|
30297
|
-
|
|
30342
|
+
receipts: report.receipts.map(
|
|
30343
|
+
(receipt) => humanReceipt(receipt) ? {
|
|
30344
|
+
recipient_user_id: receipt.recipient_user_id,
|
|
30345
|
+
state: receipt.seen_at === null ? "not_seen" : "seen",
|
|
30346
|
+
seen_at: receipt.seen_at
|
|
30347
|
+
} : {
|
|
30348
|
+
recipient_agent_principal_id: receipt.recipient_agent_principal_id,
|
|
30349
|
+
state: signalReceiptCliState(receipt, nowMs),
|
|
30350
|
+
outcome: receipt.ack_outcome,
|
|
30351
|
+
enqueued_at: receipt.enqueued_at,
|
|
30352
|
+
delivered_at: receipt.delivered_at,
|
|
30353
|
+
leased_until: receipt.leased_until,
|
|
30354
|
+
acked_at: receipt.acked_at,
|
|
30355
|
+
attempt_count: receipt.attempt_count,
|
|
30356
|
+
lease_expiry_count: receipt.lease_expiry_count,
|
|
30357
|
+
last_error_code: receipt.last_error_code
|
|
30358
|
+
}
|
|
30359
|
+
)
|
|
30298
30360
|
};
|
|
30299
30361
|
}
|
|
30300
30362
|
|
|
@@ -39209,8 +39271,8 @@ var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
|
|
|
39209
39271
|
AGENT_CREDENTIAL_MESSAGE_D088
|
|
39210
39272
|
];
|
|
39211
39273
|
function packageVersion() {
|
|
39212
|
-
if ("0.1.
|
|
39213
|
-
return "0.1.
|
|
39274
|
+
if ("0.1.43".length > 0) {
|
|
39275
|
+
return "0.1.43";
|
|
39214
39276
|
}
|
|
39215
39277
|
try {
|
|
39216
39278
|
const value = JSON.parse(
|
|
@@ -39342,6 +39404,9 @@ Usage:
|
|
|
39342
39404
|
cswarm file get <name|file-id> [--version <n>] [--out <local-path>] [--force] [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json]
|
|
39343
39405
|
cswarm file rm <name|file-id> [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json]
|
|
39344
39406
|
cswarm file restore <name|file-id> [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json]
|
|
39407
|
+
cswarm brain ls [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json]
|
|
39408
|
+
cswarm brain get <topic> [--version <n>] [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json]
|
|
39409
|
+
cswarm brain put <topic> [<markdown-path>] [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json] # without a path, reads Markdown from stdin
|
|
39345
39410
|
cswarm feedback "<text>" --kind bug|idea|friction [--about <ref>] [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json]
|
|
39346
39411
|
cswarm listen start ${requiredAgentCredential} [--url <url> --anon-key <key>] --workspace-id <uuid> --provider grok|opencode|claude|codex [--cwd <absolute-path>] [--model <model>] [--effort <level>] [--permissions deny|allow] [--grok-executable <path>] [--opencode-executable <path>] [--claude-executable <path>] [--codex-executable <path>] [--turn-budget <duration>] [--route worker|main|split] [--defer-over <chars>] [--foreground] [--json]
|
|
39347
39412
|
cswarm listen status [--url <url> --anon-key <key>] --workspace-id <uuid> --principal-id <uuid> [--json]
|
|
@@ -39387,7 +39452,8 @@ Credential selection for command/dogfood:
|
|
|
39387
39452
|
signal command/read only -- either form
|
|
39388
39453
|
receipt reads only -- either form
|
|
39389
39454
|
inbox --notify persists a per-agent cursor -- needs principal_id
|
|
39390
|
-
file put, file ls, file get, file rm, file restore
|
|
39455
|
+
file put, file ls, file get, file rm, file restore,
|
|
39456
|
+
brain ls, brain get, brain put
|
|
39391
39457
|
read and command, nothing persisted -- either form
|
|
39392
39458
|
feedback command only, nothing persisted -- either form
|
|
39393
39459
|
command, dogfood
|
|
@@ -43085,17 +43151,7 @@ async function resolveFileSelector(context, selector) {
|
|
|
43085
43151
|
}
|
|
43086
43152
|
return match.file_id;
|
|
43087
43153
|
}
|
|
43088
|
-
async function
|
|
43089
|
-
const localPath = args.positionals[2];
|
|
43090
|
-
if (!localPath) throw new UsageError("cswarm file put needs a local path");
|
|
43091
|
-
const context = await fileContext(args, ["name"], 3);
|
|
43092
|
-
let bytes;
|
|
43093
|
-
try {
|
|
43094
|
-
bytes = (0, import_node_fs7.readFileSync)(localPath);
|
|
43095
|
-
} catch {
|
|
43096
|
-
throw new Error(`could not read ${localPath}; check the path and permissions`);
|
|
43097
|
-
}
|
|
43098
|
-
const name = args.optional("name") ?? (0, import_node_path20.basename)(localPath);
|
|
43154
|
+
async function uploadNamedFile(context, name, bytes) {
|
|
43099
43155
|
if (bytes.byteLength > FILE_MAX_VERSION_BYTES) {
|
|
43100
43156
|
throw new Error(
|
|
43101
43157
|
`this file is ${formatFileSize(bytes.byteLength)}; the per-file limit is ${formatFileSize(FILE_MAX_VERSION_BYTES)}, so the upload was not started`
|
|
@@ -43128,13 +43184,26 @@ async function runFilePut(args) {
|
|
|
43128
43184
|
await onceRetried(
|
|
43129
43185
|
() => putObject(context.cloud, created.upload_path, bytes, contentType)
|
|
43130
43186
|
);
|
|
43131
|
-
|
|
43187
|
+
return await onceRetried(
|
|
43132
43188
|
() => fileVersionCommit({ ...send, commandId: commitCommandId }, {
|
|
43133
43189
|
fileId: created.file_id,
|
|
43134
43190
|
versionId: created.version_id,
|
|
43135
43191
|
sha256: sha256Hex(bytes)
|
|
43136
43192
|
})
|
|
43137
43193
|
);
|
|
43194
|
+
}
|
|
43195
|
+
async function runFilePut(args) {
|
|
43196
|
+
const localPath = args.positionals[2];
|
|
43197
|
+
if (!localPath) throw new UsageError("cswarm file put needs a local path");
|
|
43198
|
+
const context = await fileContext(args, ["name"], 3);
|
|
43199
|
+
let bytes;
|
|
43200
|
+
try {
|
|
43201
|
+
bytes = (0, import_node_fs7.readFileSync)(localPath);
|
|
43202
|
+
} catch {
|
|
43203
|
+
throw new Error(`could not read ${localPath}; check the path and permissions`);
|
|
43204
|
+
}
|
|
43205
|
+
const name = args.optional("name") ?? (0, import_node_path20.basename)(localPath);
|
|
43206
|
+
const committed = await uploadNamedFile(context, name, bytes);
|
|
43138
43207
|
if (args.has("json")) {
|
|
43139
43208
|
process.stdout.write(`${JSON.stringify(committed, null, 2)}
|
|
43140
43209
|
`);
|
|
@@ -43260,6 +43329,157 @@ async function runFileRestore(args) {
|
|
|
43260
43329
|
`
|
|
43261
43330
|
);
|
|
43262
43331
|
}
|
|
43332
|
+
async function brainRows(context) {
|
|
43333
|
+
const rows3 = await fileRows(context);
|
|
43334
|
+
return rows3.filter((row) => row.tombstoned_at === null).flatMap((file) => {
|
|
43335
|
+
const topic = brainTopicFromFileName(file.name);
|
|
43336
|
+
return topic === null ? [] : [{ topic, file }];
|
|
43337
|
+
}).sort((left, right) => left.topic.localeCompare(right.topic));
|
|
43338
|
+
}
|
|
43339
|
+
async function readBrainMarkdownFromStdin() {
|
|
43340
|
+
if (process.stdin.isTTY) {
|
|
43341
|
+
throw new UsageError(
|
|
43342
|
+
"cswarm brain put needs a Markdown path or piped Markdown on stdin"
|
|
43343
|
+
);
|
|
43344
|
+
}
|
|
43345
|
+
const chunks = [];
|
|
43346
|
+
let size2 = 0;
|
|
43347
|
+
for await (const chunk of process.stdin) {
|
|
43348
|
+
const bytes2 = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
43349
|
+
size2 += bytes2.byteLength;
|
|
43350
|
+
if (size2 > FILE_MAX_VERSION_BYTES) {
|
|
43351
|
+
throw new Error(
|
|
43352
|
+
`brain topic input is larger than ${formatFileSize(FILE_MAX_VERSION_BYTES)}; nothing was uploaded`
|
|
43353
|
+
);
|
|
43354
|
+
}
|
|
43355
|
+
chunks.push(bytes2);
|
|
43356
|
+
}
|
|
43357
|
+
const bytes = Buffer.concat(chunks);
|
|
43358
|
+
if (bytes.byteLength === 0) {
|
|
43359
|
+
throw new UsageError("cswarm brain put received empty Markdown; nothing was uploaded");
|
|
43360
|
+
}
|
|
43361
|
+
return bytes;
|
|
43362
|
+
}
|
|
43363
|
+
function decodeBrainMarkdown(bytes) {
|
|
43364
|
+
try {
|
|
43365
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
43366
|
+
} catch {
|
|
43367
|
+
throw new Error("the brain topic is not valid UTF-8 Markdown");
|
|
43368
|
+
}
|
|
43369
|
+
}
|
|
43370
|
+
async function runBrainLs(args) {
|
|
43371
|
+
const context = await fileContext(args, [], 2);
|
|
43372
|
+
const topics = await brainRows(context);
|
|
43373
|
+
if (args.has("json")) {
|
|
43374
|
+
process.stdout.write(
|
|
43375
|
+
`${JSON.stringify({
|
|
43376
|
+
workspace_id: context.selected.selectedWorkspace,
|
|
43377
|
+
topics: topics.map(({ topic, file }) => ({ topic, ...file }))
|
|
43378
|
+
}, null, 2)}
|
|
43379
|
+
`
|
|
43380
|
+
);
|
|
43381
|
+
return;
|
|
43382
|
+
}
|
|
43383
|
+
if (topics.length === 0) {
|
|
43384
|
+
process.stdout.write(
|
|
43385
|
+
"No brain topics yet. Add one with: cswarm brain put <topic> <markdown-path>.\n"
|
|
43386
|
+
);
|
|
43387
|
+
return;
|
|
43388
|
+
}
|
|
43389
|
+
process.stdout.write(`Brain topics (${topics.length}):
|
|
43390
|
+
`);
|
|
43391
|
+
for (const { topic, file } of topics) {
|
|
43392
|
+
const versions = `${file.current_version} ${file.current_version === 1 ? "version" : "versions"}`;
|
|
43393
|
+
const author = file.uploaded_by ? `${file.uploaded_by_kind ?? file.created_by_kind} ${file.uploaded_by.slice(0, 8)}` : file.created_by_kind;
|
|
43394
|
+
process.stdout.write(
|
|
43395
|
+
`- ${topic} \xB7 ${versions} \xB7 updated ${file.committed_at ?? file.created_at} \xB7 by ${author}
|
|
43396
|
+
`
|
|
43397
|
+
);
|
|
43398
|
+
}
|
|
43399
|
+
}
|
|
43400
|
+
async function runBrainGet(args) {
|
|
43401
|
+
const requestedTopic = args.positionals[2];
|
|
43402
|
+
if (!requestedTopic) throw new UsageError("cswarm brain get needs a topic");
|
|
43403
|
+
const topic = canonicalBrainTopic(requestedTopic);
|
|
43404
|
+
const context = await fileContext(args, ["version"], 3);
|
|
43405
|
+
const row = (await brainRows(context)).find((candidate) => candidate.topic === topic);
|
|
43406
|
+
if (!row) {
|
|
43407
|
+
throw new Error(
|
|
43408
|
+
`no brain topic named "${sanitizeDisplayLabel(topic, "that topic")}" exists; run cswarm brain ls to see the current topics`
|
|
43409
|
+
);
|
|
43410
|
+
}
|
|
43411
|
+
const versionN = args.has("version") ? integer2(args, "version", { minimum: 1 }) : null;
|
|
43412
|
+
const grant = await fileDownloadUrl({
|
|
43413
|
+
target: context.cloud,
|
|
43414
|
+
workspaceId: context.selected.selectedWorkspace,
|
|
43415
|
+
credential: context.selected.bearer
|
|
43416
|
+
}, { fileId: row.file.file_id, versionN });
|
|
43417
|
+
const content = decodeBrainMarkdown(
|
|
43418
|
+
await getObject(context.cloud, grant.download_path)
|
|
43419
|
+
);
|
|
43420
|
+
if (args.has("json")) {
|
|
43421
|
+
process.stdout.write(`${JSON.stringify({
|
|
43422
|
+
topic,
|
|
43423
|
+
file_id: grant.file_id,
|
|
43424
|
+
version_n: grant.version_n,
|
|
43425
|
+
updated_at: row.file.committed_at,
|
|
43426
|
+
updated_by_kind: row.file.uploaded_by_kind,
|
|
43427
|
+
updated_by: row.file.uploaded_by,
|
|
43428
|
+
content
|
|
43429
|
+
}, null, 2)}
|
|
43430
|
+
`);
|
|
43431
|
+
return;
|
|
43432
|
+
}
|
|
43433
|
+
process.stdout.write(content.endsWith("\n") ? content : `${content}
|
|
43434
|
+
`);
|
|
43435
|
+
}
|
|
43436
|
+
async function runBrainPut(args) {
|
|
43437
|
+
const requestedTopic = args.positionals[2];
|
|
43438
|
+
if (!requestedTopic) throw new UsageError("cswarm brain put needs a topic");
|
|
43439
|
+
if (args.positionals.length > 4) {
|
|
43440
|
+
throw new UsageError("cswarm brain put takes one topic and, optionally, one Markdown path");
|
|
43441
|
+
}
|
|
43442
|
+
const topic = canonicalBrainTopic(requestedTopic);
|
|
43443
|
+
const localPath = args.positionals[3];
|
|
43444
|
+
if (!localPath && args.has("agent-token-stdin")) {
|
|
43445
|
+
throw new UsageError(
|
|
43446
|
+
"cswarm brain put cannot read both the credential and Markdown from stdin; use --agent-token-file or pass a Markdown path"
|
|
43447
|
+
);
|
|
43448
|
+
}
|
|
43449
|
+
const context = await fileContext(args, [], args.positionals.length);
|
|
43450
|
+
let bytes;
|
|
43451
|
+
if (localPath) {
|
|
43452
|
+
try {
|
|
43453
|
+
bytes = (0, import_node_fs7.readFileSync)(localPath);
|
|
43454
|
+
} catch {
|
|
43455
|
+
throw new Error(`could not read ${localPath}; check the path and permissions`);
|
|
43456
|
+
}
|
|
43457
|
+
if (bytes.byteLength === 0) {
|
|
43458
|
+
throw new UsageError("cswarm brain put received an empty Markdown file; nothing was uploaded");
|
|
43459
|
+
}
|
|
43460
|
+
} else {
|
|
43461
|
+
bytes = await readBrainMarkdownFromStdin();
|
|
43462
|
+
}
|
|
43463
|
+
decodeBrainMarkdown(bytes);
|
|
43464
|
+
const committed = await uploadNamedFile(context, brainFileName(topic), bytes);
|
|
43465
|
+
if (args.has("json")) {
|
|
43466
|
+
process.stdout.write(`${JSON.stringify({ topic, ...committed }, null, 2)}
|
|
43467
|
+
`);
|
|
43468
|
+
return;
|
|
43469
|
+
}
|
|
43470
|
+
process.stdout.write(
|
|
43471
|
+
`Saved brain topic ${topic} as version ${committed.version_n}. It is now visible to everyone in this workspace.
|
|
43472
|
+
Read it with: cswarm brain get ${topic}
|
|
43473
|
+
`
|
|
43474
|
+
);
|
|
43475
|
+
}
|
|
43476
|
+
async function runBrain(args) {
|
|
43477
|
+
const action = args.positionals[1];
|
|
43478
|
+
if (action === "ls") return await runBrainLs(args);
|
|
43479
|
+
if (action === "get") return await runBrainGet(args);
|
|
43480
|
+
if (action === "put") return await runBrainPut(args);
|
|
43481
|
+
throw new UsageError("cswarm brain takes ls, get, or put");
|
|
43482
|
+
}
|
|
43263
43483
|
async function runFeedback(args) {
|
|
43264
43484
|
const body = args.positionals[1];
|
|
43265
43485
|
if (!body) {
|
|
@@ -43577,6 +43797,10 @@ async function main() {
|
|
|
43577
43797
|
await runFile(args);
|
|
43578
43798
|
return;
|
|
43579
43799
|
}
|
|
43800
|
+
if (verb === "brain") {
|
|
43801
|
+
await runBrain(args);
|
|
43802
|
+
return;
|
|
43803
|
+
}
|
|
43580
43804
|
if (verb === "members") {
|
|
43581
43805
|
await runMembers(args);
|
|
43582
43806
|
return;
|
|
@@ -43669,7 +43893,7 @@ main().catch((error) => {
|
|
|
43669
43893
|
if (error instanceof WorkspaceCliError) {
|
|
43670
43894
|
const structured = error.structured();
|
|
43671
43895
|
const verb = process.argv[2];
|
|
43672
|
-
const json = process.argv.includes("--json") && (verb === "status" || verb === "workspaces" || verb === "use" || verb === "working-on" || verb === "note" || verb === "ask" || verb === "reply" || verb === "receipt" || verb === "feed" || verb === "inbox");
|
|
43896
|
+
const json = process.argv.includes("--json") && (verb === "status" || verb === "workspaces" || verb === "use" || verb === "working-on" || verb === "note" || verb === "ask" || verb === "reply" || verb === "receipt" || verb === "feed" || verb === "inbox" || verb === "file" || verb === "brain");
|
|
43673
43897
|
if (json) {
|
|
43674
43898
|
process.stdout.write(`${JSON.stringify(structured, null, 2)}
|
|
43675
43899
|
`);
|