@prismer/sdk 2.0.7 → 2.0.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/dist/cli.js +280 -38
- package/dist/index.d.mts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +18 -0
- package/dist/index.mjs +18 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -163,7 +163,7 @@ var RealtimeWSClient = class extends TypedEmitter {
|
|
|
163
163
|
if (this._state === "connected" || this._state === "connecting") return;
|
|
164
164
|
this._state = "connecting";
|
|
165
165
|
this.intentionalClose = false;
|
|
166
|
-
return new Promise((
|
|
166
|
+
return new Promise((resolve6, reject) => {
|
|
167
167
|
try {
|
|
168
168
|
this.ws = new this.WS(this.wsUrl);
|
|
169
169
|
} catch (err) {
|
|
@@ -185,7 +185,7 @@ var RealtimeWSClient = class extends TypedEmitter {
|
|
|
185
185
|
this.emit("connected", void 0);
|
|
186
186
|
this.ws.removeEventListener("message", onFirstMessage);
|
|
187
187
|
this.ws.addEventListener("message", this.handleMessage);
|
|
188
|
-
|
|
188
|
+
resolve6();
|
|
189
189
|
}
|
|
190
190
|
} catch (_) {
|
|
191
191
|
}
|
|
@@ -257,12 +257,12 @@ var RealtimeWSClient = class extends TypedEmitter {
|
|
|
257
257
|
}
|
|
258
258
|
ping() {
|
|
259
259
|
const requestId = `ping-${++this.pingCounter}`;
|
|
260
|
-
return new Promise((
|
|
260
|
+
return new Promise((resolve6, reject) => {
|
|
261
261
|
const timer = setTimeout(() => {
|
|
262
262
|
this.pendingPings.delete(requestId);
|
|
263
263
|
reject(new Error("Ping timeout"));
|
|
264
264
|
}, 1e4);
|
|
265
|
-
this.pendingPings.set(requestId, { resolve:
|
|
265
|
+
this.pendingPings.set(requestId, { resolve: resolve6, timer });
|
|
266
266
|
this.sendRaw({ type: "ping", payload: { requestId } });
|
|
267
267
|
});
|
|
268
268
|
}
|
|
@@ -3868,6 +3868,19 @@ var FilesClient = class {
|
|
|
3868
3868
|
*/
|
|
3869
3869
|
async sendFile(conversationId, input, opts) {
|
|
3870
3870
|
const uploaded = await this.upload(input, opts);
|
|
3871
|
+
const outboxDir = process.env.PRISMER_OUTBOX_DIR;
|
|
3872
|
+
if (outboxDir) {
|
|
3873
|
+
try {
|
|
3874
|
+
const fsMod = await import("fs");
|
|
3875
|
+
const pathMod = await import("path");
|
|
3876
|
+
const srcPath = typeof input === "string" ? input : input.path;
|
|
3877
|
+
if (srcPath && typeof srcPath === "string") {
|
|
3878
|
+
await fsMod.promises.mkdir(outboxDir, { recursive: true });
|
|
3879
|
+
fsMod.cpSync(srcPath, pathMod.join(outboxDir, pathMod.basename(srcPath)));
|
|
3880
|
+
}
|
|
3881
|
+
} catch {
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3871
3884
|
const msgRes = await this._r("POST", `/api/im/messages/${conversationId}`, {
|
|
3872
3885
|
content: opts?.content || uploaded.fileName,
|
|
3873
3886
|
type: "file",
|
|
@@ -4184,6 +4197,7 @@ var PrismerClient = class {
|
|
|
4184
4197
|
this.timeout = config.timeout || 3e4;
|
|
4185
4198
|
this.fetchFn = config.fetch || fetch;
|
|
4186
4199
|
this.imAgent = config.imAgent;
|
|
4200
|
+
this.imWorkspace = config.imWorkspace;
|
|
4187
4201
|
if (config.identity) {
|
|
4188
4202
|
if (config.identity === "auto" && this.apiKey) {
|
|
4189
4203
|
this._identityReady = import_aip_sdk.AIPIdentity.fromApiKey(this.apiKey).then((id) => {
|
|
@@ -4280,6 +4294,7 @@ var PrismerClient = class {
|
|
|
4280
4294
|
const headers = {};
|
|
4281
4295
|
if (this.apiKey) headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
4282
4296
|
if (this.imAgent) headers["X-IM-Agent"] = this.imAgent;
|
|
4297
|
+
if (this.imWorkspace) headers["X-IM-Workspace"] = this.imWorkspace;
|
|
4283
4298
|
return headers;
|
|
4284
4299
|
}
|
|
4285
4300
|
/**
|
|
@@ -4346,6 +4361,9 @@ var PrismerClient = class {
|
|
|
4346
4361
|
if (this.imAgent) {
|
|
4347
4362
|
headers["X-IM-Agent"] = this.imAgent;
|
|
4348
4363
|
}
|
|
4364
|
+
if (this.imWorkspace) {
|
|
4365
|
+
headers["X-IM-Workspace"] = this.imWorkspace;
|
|
4366
|
+
}
|
|
4349
4367
|
if (opts?.headers) {
|
|
4350
4368
|
for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;
|
|
4351
4369
|
}
|
|
@@ -5714,7 +5732,7 @@ function register3(parent, getIMClient2, _getAPIClient) {
|
|
|
5714
5732
|
const maxIterations = 30;
|
|
5715
5733
|
let lastStatus;
|
|
5716
5734
|
for (let i = 0; i < maxIterations; i++) {
|
|
5717
|
-
await new Promise((
|
|
5735
|
+
await new Promise((resolve6) => setTimeout(resolve6, 2e3));
|
|
5718
5736
|
if (!opts.json) process.stdout.write(".");
|
|
5719
5737
|
const statusRes = await client.im.evolution.getReportStatus(traceId);
|
|
5720
5738
|
if (!statusRes.ok) break;
|
|
@@ -6098,11 +6116,94 @@ function register3(parent, getIMClient2, _getAPIClient) {
|
|
|
6098
6116
|
|
|
6099
6117
|
// src/commands/task.ts
|
|
6100
6118
|
var import_node_fs = require("fs");
|
|
6101
|
-
var
|
|
6119
|
+
var import_node_path2 = require("path");
|
|
6102
6120
|
var import_node_crypto = require("crypto");
|
|
6121
|
+
|
|
6122
|
+
// src/commands/deliver-proxy.ts
|
|
6123
|
+
var import_node_path = require("path");
|
|
6124
|
+
function detectDeliverProxy(opts) {
|
|
6125
|
+
const taskId = (opts?.taskId || opts?.runId || "").trim() || process.env.PRISMER_TASK_ID || process.env.PRISMER_RUN_ID || "";
|
|
6126
|
+
if (!taskId) return null;
|
|
6127
|
+
const port = (opts?.daemonPort || "").trim() || (process.env.PRISMER_DAEMON_PORT ?? "3210").trim() || "3210";
|
|
6128
|
+
const ctx = {
|
|
6129
|
+
daemonUrl: `http://127.0.0.1:${port}`,
|
|
6130
|
+
taskId
|
|
6131
|
+
};
|
|
6132
|
+
const agentUsername = process.env.PRISMER_AGENT_USERNAME;
|
|
6133
|
+
if (agentUsername) ctx.agentUsername = agentUsername;
|
|
6134
|
+
const conversationId = (opts?.conversationId || "").trim() || process.env.PRISMER_CONVERSATION_ID;
|
|
6135
|
+
if (conversationId) ctx.conversationId = conversationId;
|
|
6136
|
+
return ctx;
|
|
6137
|
+
}
|
|
6138
|
+
async function proxyDeliver(ctx, filePath, mode, conversationId, messageId) {
|
|
6139
|
+
const abs = (0, import_node_path.resolve)(filePath);
|
|
6140
|
+
const body = {
|
|
6141
|
+
taskId: ctx.taskId,
|
|
6142
|
+
path: abs,
|
|
6143
|
+
mode
|
|
6144
|
+
};
|
|
6145
|
+
const conv = conversationId ?? ctx.conversationId;
|
|
6146
|
+
if (mode === "send") {
|
|
6147
|
+
if (!conv) {
|
|
6148
|
+
return { ok: false, status: 400, error: "conversationId is required for send mode" };
|
|
6149
|
+
}
|
|
6150
|
+
body.conversationId = conv;
|
|
6151
|
+
}
|
|
6152
|
+
if (mode === "message-attach") {
|
|
6153
|
+
if (!conv) {
|
|
6154
|
+
return { ok: false, status: 400, error: "conversationId is required for message-attach mode" };
|
|
6155
|
+
}
|
|
6156
|
+
if (!messageId) {
|
|
6157
|
+
return { ok: false, status: 400, error: "messageId is required for message-attach mode" };
|
|
6158
|
+
}
|
|
6159
|
+
body.conversationId = conv;
|
|
6160
|
+
body.messageId = messageId;
|
|
6161
|
+
}
|
|
6162
|
+
if (ctx.agentUsername) body.agentUsername = ctx.agentUsername;
|
|
6163
|
+
let res;
|
|
6164
|
+
try {
|
|
6165
|
+
res = await fetch(`${ctx.daemonUrl}/local/deliver`, {
|
|
6166
|
+
method: "POST",
|
|
6167
|
+
headers: { "Content-Type": "application/json" },
|
|
6168
|
+
body: JSON.stringify(body)
|
|
6169
|
+
});
|
|
6170
|
+
} catch (err) {
|
|
6171
|
+
return {
|
|
6172
|
+
ok: false,
|
|
6173
|
+
status: 0,
|
|
6174
|
+
error: `daemon unreachable at ${ctx.daemonUrl}/local/deliver: ${err instanceof Error ? err.message : String(err)}`
|
|
6175
|
+
};
|
|
6176
|
+
}
|
|
6177
|
+
let parsed = {};
|
|
6178
|
+
try {
|
|
6179
|
+
parsed = await res.json();
|
|
6180
|
+
} catch {
|
|
6181
|
+
}
|
|
6182
|
+
if (res.ok && parsed.ok) {
|
|
6183
|
+
const out = { ok: true, status: res.status };
|
|
6184
|
+
if (parsed.assetId) out.assetId = parsed.assetId;
|
|
6185
|
+
return out;
|
|
6186
|
+
}
|
|
6187
|
+
return {
|
|
6188
|
+
ok: false,
|
|
6189
|
+
status: res.status,
|
|
6190
|
+
error: parsed.error ?? `daemon returned ${res.status}`
|
|
6191
|
+
};
|
|
6192
|
+
}
|
|
6193
|
+
|
|
6194
|
+
// src/commands/task.ts
|
|
6103
6195
|
var TASK_STATUSES = /* @__PURE__ */ new Set(["pending", "assigned", "running", "review", "completed", "failed", "cancelled"]);
|
|
6104
6196
|
var TASK_PRIORITIES = /* @__PURE__ */ new Set(["low", "medium", "high", "urgent"]);
|
|
6105
6197
|
var TASK_KINDS = /* @__PURE__ */ new Set(["work_item", "goal"]);
|
|
6198
|
+
function assertNotRunId(id) {
|
|
6199
|
+
if (typeof id === "string" && id.startsWith("run_")) {
|
|
6200
|
+
process.stderr.write(
|
|
6201
|
+
`Error: '${id}' is a run id (run_\u2026); a chat reply doesn't need 'cloud task' ops \u2014 the platform closes the turn from your reply.
|
|
6202
|
+
`
|
|
6203
|
+
);
|
|
6204
|
+
process.exit(1);
|
|
6205
|
+
}
|
|
6206
|
+
}
|
|
6106
6207
|
function parseTaskStatus(raw) {
|
|
6107
6208
|
if (!raw) return void 0;
|
|
6108
6209
|
if (TASK_STATUSES.has(raw)) return raw;
|
|
@@ -6325,6 +6426,7 @@ ${tasks.length} task(s) listed.
|
|
|
6325
6426
|
}
|
|
6326
6427
|
});
|
|
6327
6428
|
task.command("move-project <task-id> [project-id]").description("Move a task to a project, or use --unscoped to return it to workspace-level").option("--unscoped", "set projectId to null", false).option("--json", "output raw JSON response").action(async (taskId, projectId, opts) => {
|
|
6429
|
+
assertNotRunId(taskId);
|
|
6328
6430
|
const client = getIMClient2();
|
|
6329
6431
|
try {
|
|
6330
6432
|
if (!opts.unscoped && !projectId) {
|
|
@@ -6351,6 +6453,7 @@ ${tasks.length} task(s) listed.
|
|
|
6351
6453
|
}
|
|
6352
6454
|
});
|
|
6353
6455
|
task.command("get <task-id>").description("Get task details and logs").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
6456
|
+
assertNotRunId(taskId);
|
|
6354
6457
|
const client = getIMClient2();
|
|
6355
6458
|
try {
|
|
6356
6459
|
const res = await client.im.tasks.get(taskId);
|
|
@@ -6415,6 +6518,7 @@ Logs (${logs.length}):
|
|
|
6415
6518
|
}
|
|
6416
6519
|
});
|
|
6417
6520
|
task.command("claim <task-id>").description("Claim a pending task").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
6521
|
+
assertNotRunId(taskId);
|
|
6418
6522
|
const client = getIMClient2();
|
|
6419
6523
|
try {
|
|
6420
6524
|
const res = await client.im.tasks.claim(taskId);
|
|
@@ -6445,6 +6549,7 @@ Logs (${logs.length}):
|
|
|
6445
6549
|
}
|
|
6446
6550
|
});
|
|
6447
6551
|
task.command("update <task-id>").description("Update a task").option("--title <title>", "new title").option("--description <description>", "new description").option("--status <status>", "new status").option("--progress <progress>", "progress (0.0 to 1.0)", parseFloat).option("--status-message <statusMessage>", "status message").option("--skip-checkpoint", "bypass local daemon checkpoint when transitioning to review (release201/09 \xA79.4a.7)", false).option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
6552
|
+
assertNotRunId(taskId);
|
|
6448
6553
|
const client = getIMClient2();
|
|
6449
6554
|
try {
|
|
6450
6555
|
if (opts.status === "review" && !opts.skipCheckpoint) {
|
|
@@ -6452,7 +6557,7 @@ Logs (${logs.length}):
|
|
|
6452
6557
|
if (!checkpoint.ok) {
|
|
6453
6558
|
if (checkpoint.pendingFiles && checkpoint.pendingFiles.length > 0) {
|
|
6454
6559
|
process.stderr.write(
|
|
6455
|
-
`[checkpoint]
|
|
6560
|
+
`[checkpoint] artifacts/ \u542B ${checkpoint.pendingFiles.length} \u4E2A\u672A attach \u6587\u4EF6:
|
|
6456
6561
|
`
|
|
6457
6562
|
);
|
|
6458
6563
|
for (const f of checkpoint.pendingFiles) {
|
|
@@ -6513,6 +6618,7 @@ Logs (${logs.length}):
|
|
|
6513
6618
|
}
|
|
6514
6619
|
});
|
|
6515
6620
|
task.command("complete <task-id>").description("Mark a task as complete").option("--result <result>", "result or output of the task").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
6621
|
+
assertNotRunId(taskId);
|
|
6516
6622
|
const client = getIMClient2();
|
|
6517
6623
|
try {
|
|
6518
6624
|
const res = await client.im.tasks.complete(taskId, {
|
|
@@ -6547,6 +6653,7 @@ Logs (${logs.length}):
|
|
|
6547
6653
|
}
|
|
6548
6654
|
});
|
|
6549
6655
|
task.command("fail <task-id>").description("Mark a task as failed").requiredOption("--error <error>", "error message describing why the task failed").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
6656
|
+
assertNotRunId(taskId);
|
|
6550
6657
|
const client = getIMClient2();
|
|
6551
6658
|
try {
|
|
6552
6659
|
const res = await client.im.tasks.fail(taskId, opts.error);
|
|
@@ -6579,6 +6686,7 @@ Logs (${logs.length}):
|
|
|
6579
6686
|
}
|
|
6580
6687
|
});
|
|
6581
6688
|
task.command("approve <task-id>").description("Approve a completed task").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
6689
|
+
assertNotRunId(taskId);
|
|
6582
6690
|
const client = getIMClient2();
|
|
6583
6691
|
try {
|
|
6584
6692
|
const res = await client.im.tasks.approve(taskId);
|
|
@@ -6609,6 +6717,7 @@ Logs (${logs.length}):
|
|
|
6609
6717
|
}
|
|
6610
6718
|
});
|
|
6611
6719
|
task.command("reject <task-id>").description("Reject a task").requiredOption("--reason <reason>", "reason for rejection").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
6720
|
+
assertNotRunId(taskId);
|
|
6612
6721
|
const client = getIMClient2();
|
|
6613
6722
|
try {
|
|
6614
6723
|
const res = await client.im.tasks.reject(taskId, opts.reason);
|
|
@@ -6638,14 +6747,34 @@ Logs (${logs.length}):
|
|
|
6638
6747
|
process.exit(1);
|
|
6639
6748
|
}
|
|
6640
6749
|
});
|
|
6641
|
-
task.command("attach <path>").description("Attach a file to a task as a user-deliverable (release201/09 \xA79.4a.5)").option("--task <taskId>", "target task id; defaults to PRISMER_TASK_ID env").option("--name <displayName>", "override the display filename; defaults to basename(path)").option("--json", "output raw JSON response").action(async (filePath, opts) => {
|
|
6642
|
-
const
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6750
|
+
task.command("attach <path>").description("Attach a file to a task as a user-deliverable (release201/09 \xA79.4a.5)").option("--task <taskId>", "target task id; defaults to PRISMER_TASK_ID env").option("--name <displayName>", "override the display filename; defaults to basename(path)").option("--run-id <id>", "dispatch task id (alias for --task; from <execution_context>; env fallback PRISMER_TASK_ID)").option("--daemon-port <port>", "daemon local-server port (env fallback PRISMER_DAEMON_PORT, default 3210)").option("--json", "output raw JSON response").action(async (filePath, opts) => {
|
|
6751
|
+
const targetTaskId = opts.task ?? opts.runId ?? process.env.PRISMER_TASK_ID;
|
|
6752
|
+
if (!targetTaskId) {
|
|
6753
|
+
process.stderr.write("Error: --task is required (or set PRISMER_TASK_ID env)\n");
|
|
6754
|
+
process.exit(1);
|
|
6755
|
+
}
|
|
6756
|
+
assertNotRunId(targetTaskId);
|
|
6757
|
+
const proxy = detectDeliverProxy({
|
|
6758
|
+
taskId: targetTaskId,
|
|
6759
|
+
daemonPort: opts.daemonPort
|
|
6760
|
+
});
|
|
6761
|
+
if (proxy) {
|
|
6762
|
+
const result = await proxyDeliver(proxy, filePath, "task-attach");
|
|
6763
|
+
if (!result.ok) {
|
|
6764
|
+
process.stderr.write(`Error: ${result.error ?? "task attach failed"}
|
|
6765
|
+
`);
|
|
6647
6766
|
process.exit(1);
|
|
6648
6767
|
}
|
|
6768
|
+
if (opts.json) {
|
|
6769
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
6770
|
+
return;
|
|
6771
|
+
}
|
|
6772
|
+
process.stdout.write(`Attached to task ${targetTaskId} (assetId: ${result.assetId ?? "-"})
|
|
6773
|
+
`);
|
|
6774
|
+
return;
|
|
6775
|
+
}
|
|
6776
|
+
const client = getIMClient2();
|
|
6777
|
+
try {
|
|
6649
6778
|
const getRes = await client.im.tasks.get(targetTaskId);
|
|
6650
6779
|
if (!getRes.ok || !getRes.data) {
|
|
6651
6780
|
process.stderr.write(`Error: task ${targetTaskId} not found: ${getRes.error?.message ?? "unknown"}
|
|
@@ -6667,7 +6796,7 @@ Logs (${logs.length}):
|
|
|
6667
6796
|
process.exit(1);
|
|
6668
6797
|
}
|
|
6669
6798
|
const contentHash = (0, import_node_crypto.createHash)("sha256").update(bytes).digest("hex");
|
|
6670
|
-
const displayName = opts.name ?? (0,
|
|
6799
|
+
const displayName = opts.name ?? (0, import_node_path2.basename)(filePath);
|
|
6671
6800
|
const uploadRes = await client.im.assets.upload(bytes, {
|
|
6672
6801
|
workspaceId: wsId,
|
|
6673
6802
|
sourceTaskId: targetTaskId,
|
|
@@ -6716,6 +6845,7 @@ Logs (${logs.length}):
|
|
|
6716
6845
|
}
|
|
6717
6846
|
});
|
|
6718
6847
|
task.command("cancel <task-id>").description("Cancel a task").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
6848
|
+
assertNotRunId(taskId);
|
|
6719
6849
|
const client = getIMClient2();
|
|
6720
6850
|
try {
|
|
6721
6851
|
const res = await client.im.tasks.cancel(taskId);
|
|
@@ -6746,6 +6876,7 @@ Logs (${logs.length}):
|
|
|
6746
6876
|
}
|
|
6747
6877
|
});
|
|
6748
6878
|
task.command("spec-set <task-id>").description("Owner writes / updates SPEC.md for a task").option("-f, --file <path>", "read SPEC.md content from a file").option("-m, --markdown <markdown>", "inline SPEC.md content").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
6879
|
+
assertNotRunId(taskId);
|
|
6749
6880
|
const client = getIMClient2();
|
|
6750
6881
|
try {
|
|
6751
6882
|
let md = "";
|
|
@@ -6776,6 +6907,7 @@ Logs (${logs.length}):
|
|
|
6776
6907
|
}
|
|
6777
6908
|
});
|
|
6778
6909
|
task.command("spec-show <task-id>").description("Print SPEC.md content for a task").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
6910
|
+
assertNotRunId(taskId);
|
|
6779
6911
|
const client = getIMClient2();
|
|
6780
6912
|
try {
|
|
6781
6913
|
const res = await client.im.tasks.spec.get(taskId);
|
|
@@ -6800,6 +6932,7 @@ Logs (${logs.length}):
|
|
|
6800
6932
|
}
|
|
6801
6933
|
});
|
|
6802
6934
|
task.command("todo-add <task-id> <text...>").description("Append an item to the task TODO.md (assignee)").option("--depth <n>", "nesting depth (0..3)", (v) => parseInt(v, 10), 0).option("--json", "output raw JSON response").action(async (taskId, text, opts) => {
|
|
6935
|
+
assertNotRunId(taskId);
|
|
6803
6936
|
const client = getIMClient2();
|
|
6804
6937
|
try {
|
|
6805
6938
|
const res = await client.im.tasks.todo.add(taskId, {
|
|
@@ -6825,6 +6958,7 @@ Logs (${logs.length}):
|
|
|
6825
6958
|
}
|
|
6826
6959
|
});
|
|
6827
6960
|
task.command("todo-done <task-id> <index>").description("Mark a TODO item as done").option("--json", "output raw JSON response").action(async (taskId, indexRaw, opts) => {
|
|
6961
|
+
assertNotRunId(taskId);
|
|
6828
6962
|
const client = getIMClient2();
|
|
6829
6963
|
try {
|
|
6830
6964
|
const idx = parseInt(indexRaw, 10);
|
|
@@ -6851,6 +6985,7 @@ Logs (${logs.length}):
|
|
|
6851
6985
|
}
|
|
6852
6986
|
});
|
|
6853
6987
|
task.command("todo-uncheck <task-id> <index>").description("Un-tick a TODO item").option("--json", "output raw JSON response").action(async (taskId, indexRaw, opts) => {
|
|
6988
|
+
assertNotRunId(taskId);
|
|
6854
6989
|
const client = getIMClient2();
|
|
6855
6990
|
try {
|
|
6856
6991
|
const idx = parseInt(indexRaw, 10);
|
|
@@ -6875,6 +7010,7 @@ Logs (${logs.length}):
|
|
|
6875
7010
|
}
|
|
6876
7011
|
});
|
|
6877
7012
|
task.command("todo-show <task-id>").description("Render TODO.md checklist + progress for a task").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
7013
|
+
assertNotRunId(taskId);
|
|
6878
7014
|
const client = getIMClient2();
|
|
6879
7015
|
try {
|
|
6880
7016
|
const res = await client.im.tasks.todo.list(taskId);
|
|
@@ -6905,6 +7041,7 @@ Logs (${logs.length}):
|
|
|
6905
7041
|
}
|
|
6906
7042
|
});
|
|
6907
7043
|
task.command("acceptance <task-id>").description("Show acceptance criteria + rolled-up status for a task").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
7044
|
+
assertNotRunId(taskId);
|
|
6908
7045
|
const client = getIMClient2();
|
|
6909
7046
|
try {
|
|
6910
7047
|
const res = await client.im.tasks.getAcceptance(taskId);
|
|
@@ -6937,6 +7074,7 @@ Logs (${logs.length}):
|
|
|
6937
7074
|
"--mode <mode>",
|
|
6938
7075
|
"verifyMode: qualitative | quantitative | agent-self-check | manual"
|
|
6939
7076
|
).requiredOption("--expectation <markdown>", "markdown describing what done looks like").option("--verifier-agent <agentId>", "verifier agent id (default = creator)").option("--weight <n>", "weight (numeric, default 1)", parseFloat).option("--optional", "mark this criterion optional (default required)").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
7077
|
+
assertNotRunId(taskId);
|
|
6940
7078
|
const client = getIMClient2();
|
|
6941
7079
|
try {
|
|
6942
7080
|
const VALID = ["qualitative", "quantitative", "agent-self-check", "manual"];
|
|
@@ -6971,6 +7109,7 @@ Logs (${logs.length}):
|
|
|
6971
7109
|
task.command("verify <task-id>").description(
|
|
6972
7110
|
"Assignee self-check: list all agent-self-check criteria + mark them passed (run before status=review)"
|
|
6973
7111
|
).option("--note <note>", "note to attach to each self-check", "agent self-check via `cloud task verify`").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
7112
|
+
assertNotRunId(taskId);
|
|
6974
7113
|
const client = getIMClient2();
|
|
6975
7114
|
try {
|
|
6976
7115
|
const view = await client.im.tasks.getAcceptance(taskId);
|
|
@@ -7015,6 +7154,7 @@ Logs (${logs.length}):
|
|
|
7015
7154
|
task.command("verify-criterion <task-id> <criterion-id>").description(
|
|
7016
7155
|
"Report verify outcome for one criterion. Used by reviewers (manual), verifier agents, and assignees (self-check)."
|
|
7017
7156
|
).requiredOption("--outcome <outcome>", "passed | failed | n/a | waived").option("--note <note>", "free-form markdown: method + result + repro steps").option("--evidence <ref...>", "evidence refs (repeatable; e.g. asset:<id>, url:..., taskRun:<id>)").option("--waive-reason <reason>", "required when --outcome waived").option("--json", "output raw JSON response").action(async (taskId, criterionId, opts) => {
|
|
7157
|
+
assertNotRunId(taskId);
|
|
7018
7158
|
const client = getIMClient2();
|
|
7019
7159
|
try {
|
|
7020
7160
|
const VALID = ["passed", "failed", "n/a", "waived"];
|
|
@@ -7049,6 +7189,7 @@ Logs (${logs.length}):
|
|
|
7049
7189
|
}
|
|
7050
7190
|
});
|
|
7051
7191
|
task.command("apply-template <task-id>").description("Apply an acceptance criteria template to a task").requiredOption("--template <templateId>", "template id to apply").option("--json", "output raw JSON response").action(async (taskId, opts) => {
|
|
7192
|
+
assertNotRunId(taskId);
|
|
7052
7193
|
const client = getIMClient2();
|
|
7053
7194
|
try {
|
|
7054
7195
|
const res = await client.im.tasks.applyTemplate(taskId, opts.template);
|
|
@@ -8092,7 +8233,9 @@ function register9(parent, _getIMClient, _getAPIClient) {
|
|
|
8092
8233
|
// src/commands/files.ts
|
|
8093
8234
|
function register10(parent, getIMClient2, _getAPIClient) {
|
|
8094
8235
|
const file = parent.command("file").description("File upload, transfer, quota, and type management");
|
|
8095
|
-
file.command("upload <path>").description(
|
|
8236
|
+
file.command("upload <path>").description(
|
|
8237
|
+
"Upload bytes only \u2192 returns an upload ID + CDN URL. NOT a delivery: nothing reaches the user. To deliver an artifact use `cloud deliver <path>`."
|
|
8238
|
+
).option("--mime <type>", "Override MIME type (e.g. image/png)").option("--json", "Output raw JSON response").action(async (filePath, opts) => {
|
|
8096
8239
|
const client = getIMClient2();
|
|
8097
8240
|
try {
|
|
8098
8241
|
const uploadOpts = {};
|
|
@@ -8112,13 +8255,39 @@ function register10(parent, getIMClient2, _getAPIClient) {
|
|
|
8112
8255
|
`);
|
|
8113
8256
|
process.stdout.write(`MIME: ${res.mimeType}
|
|
8114
8257
|
`);
|
|
8258
|
+
process.stdout.write(
|
|
8259
|
+
"Note: this only uploaded bytes \u2014 nothing was delivered to the user. To deliver an artifact, run `cloud deliver <abs-path>`.\n"
|
|
8260
|
+
);
|
|
8115
8261
|
} catch (err) {
|
|
8116
8262
|
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
|
|
8117
8263
|
`);
|
|
8118
8264
|
process.exit(1);
|
|
8119
8265
|
}
|
|
8120
8266
|
});
|
|
8121
|
-
file.command("send <conversation-id> <path>").description(
|
|
8267
|
+
file.command("send <conversation-id> <path>").description(
|
|
8268
|
+
"Send a file as its OWN standalone message (ad-hoc sharing). For a final deliverable use `cloud deliver` instead \u2014 do not run both on the same file (double-delivery)."
|
|
8269
|
+
).option("-c, --content <text>", "Optional text caption to accompany the file").option("--mime <type>", "Override MIME type").option("--run-id <id>", "dispatch run/task id (from <execution_context>; env fallback PRISMER_TASK_ID/RUN_ID)").option("--conversation-id <id>", "conversation id (alternative source; positional <conversation-id> takes precedence)").option("--daemon-port <port>", "daemon local-server port (env fallback PRISMER_DAEMON_PORT, default 3210)").option("--json", "Output raw JSON response").action(async (conversationIdArg, filePath, opts) => {
|
|
8270
|
+
const conversationId = conversationIdArg || opts.conversationId || "";
|
|
8271
|
+
const proxy = detectDeliverProxy({
|
|
8272
|
+
runId: opts.runId,
|
|
8273
|
+
conversationId,
|
|
8274
|
+
daemonPort: opts.daemonPort
|
|
8275
|
+
});
|
|
8276
|
+
if (proxy) {
|
|
8277
|
+
const result = await proxyDeliver(proxy, filePath, "send", conversationId);
|
|
8278
|
+
if (!result.ok) {
|
|
8279
|
+
process.stderr.write(`Error: ${result.error ?? "delivery failed"}
|
|
8280
|
+
`);
|
|
8281
|
+
process.exit(1);
|
|
8282
|
+
}
|
|
8283
|
+
if (opts.json) {
|
|
8284
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
8285
|
+
return;
|
|
8286
|
+
}
|
|
8287
|
+
process.stdout.write(`File sent to conversation ${conversationId} (assetId: ${result.assetId ?? "-"})
|
|
8288
|
+
`);
|
|
8289
|
+
return;
|
|
8290
|
+
}
|
|
8122
8291
|
const client = getIMClient2();
|
|
8123
8292
|
try {
|
|
8124
8293
|
const sendOpts = {};
|
|
@@ -9482,13 +9651,13 @@ function parseIntOpt2(value) {
|
|
|
9482
9651
|
var import_node_crypto2 = require("crypto");
|
|
9483
9652
|
var import_node_fs3 = require("fs");
|
|
9484
9653
|
var import_node_os = require("os");
|
|
9485
|
-
var
|
|
9654
|
+
var import_node_path3 = require("path");
|
|
9486
9655
|
var import_node_child_process = require("child_process");
|
|
9487
9656
|
function resolvePrismerRoot() {
|
|
9488
|
-
return process.env.PRISMER_HOME ? (0,
|
|
9657
|
+
return process.env.PRISMER_HOME ? (0, import_node_path3.resolve)(process.env.PRISMER_HOME) : (0, import_node_path3.join)((0, import_node_os.homedir)(), ".prismer");
|
|
9489
9658
|
}
|
|
9490
9659
|
function readDaemonConfig() {
|
|
9491
|
-
const path6 = (0,
|
|
9660
|
+
const path6 = (0, import_node_path3.join)(resolvePrismerRoot(), "config.toml");
|
|
9492
9661
|
if (!(0, import_node_fs3.existsSync)(path6)) {
|
|
9493
9662
|
throw new Error(`${path6} not found. Run \`prismer setup\` first.`);
|
|
9494
9663
|
}
|
|
@@ -9501,7 +9670,7 @@ function readDaemonConfig() {
|
|
|
9501
9670
|
return { daemonId: idMatch[1], apiKey: keyMatch[1] };
|
|
9502
9671
|
}
|
|
9503
9672
|
function resolveAgentDir(daemonId, agentId) {
|
|
9504
|
-
return (0,
|
|
9673
|
+
return (0, import_node_path3.join)(resolvePrismerRoot(), "devices", daemonId, "agents", agentId);
|
|
9505
9674
|
}
|
|
9506
9675
|
function collectFiles(root, excludeBasenames) {
|
|
9507
9676
|
const out = [];
|
|
@@ -9514,7 +9683,7 @@ function collectFiles(root, excludeBasenames) {
|
|
|
9514
9683
|
}
|
|
9515
9684
|
for (const name of entries) {
|
|
9516
9685
|
if (excludeBasenames.has(name)) continue;
|
|
9517
|
-
const full = (0,
|
|
9686
|
+
const full = (0, import_node_path3.join)(dir, name);
|
|
9518
9687
|
let st;
|
|
9519
9688
|
try {
|
|
9520
9689
|
st = (0, import_node_fs3.statSync)(full);
|
|
@@ -9526,7 +9695,7 @@ function collectFiles(root, excludeBasenames) {
|
|
|
9526
9695
|
const buf = (0, import_node_fs3.readFileSync)(full);
|
|
9527
9696
|
const sha = (0, import_node_crypto2.createHash)("sha256").update(buf).digest("hex");
|
|
9528
9697
|
out.push({
|
|
9529
|
-
rel: (0,
|
|
9698
|
+
rel: (0, import_node_path3.relative)(root, full).split(import_node_path3.sep).join("/"),
|
|
9530
9699
|
sha,
|
|
9531
9700
|
size: buf.byteLength
|
|
9532
9701
|
});
|
|
@@ -9652,11 +9821,11 @@ function register17(parent, getIMClient2, _getAPIClient) {
|
|
|
9652
9821
|
sha256,
|
|
9653
9822
|
signature
|
|
9654
9823
|
};
|
|
9655
|
-
(0, import_node_fs3.writeFileSync)((0,
|
|
9656
|
-
const parentOfAgents = (0,
|
|
9657
|
-
const outputAbs = (0,
|
|
9824
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(agentDir, "transfer-manifest.json"), JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
9825
|
+
const parentOfAgents = (0, import_node_path3.join)(resolvePrismerRoot(), "devices", daemonId);
|
|
9826
|
+
const outputAbs = (0, import_node_path3.resolve)(opts.output);
|
|
9658
9827
|
try {
|
|
9659
|
-
(0, import_node_child_process.execFileSync)("tar", ["-czf", outputAbs, "-C", parentOfAgents, (0,
|
|
9828
|
+
(0, import_node_child_process.execFileSync)("tar", ["-czf", outputAbs, "-C", parentOfAgents, (0, import_node_path3.join)("agents", agentId)], { stdio: "inherit" });
|
|
9660
9829
|
} catch (err) {
|
|
9661
9830
|
process.stderr.write(`Error: tar failed: ${err.message}
|
|
9662
9831
|
`);
|
|
@@ -9686,14 +9855,14 @@ function register17(parent, getIMClient2, _getAPIClient) {
|
|
|
9686
9855
|
}
|
|
9687
9856
|
});
|
|
9688
9857
|
agent.command("import <tar-file>").description("release201/09 \xA79.7 \u2014 extract + rebind an agent transferred from another device").option("--json", "Output raw JSON result").action(async (tarFile, opts) => {
|
|
9689
|
-
const tarAbs = (0,
|
|
9858
|
+
const tarAbs = (0, import_node_path3.resolve)(tarFile);
|
|
9690
9859
|
if (!(0, import_node_fs3.existsSync)(tarAbs)) {
|
|
9691
9860
|
process.stderr.write(`Error: tar file not found: ${tarAbs}
|
|
9692
9861
|
`);
|
|
9693
9862
|
process.exit(1);
|
|
9694
9863
|
}
|
|
9695
9864
|
const { daemonId: toDaemonId, apiKey } = readDaemonConfig();
|
|
9696
|
-
const tmpRoot = (0,
|
|
9865
|
+
const tmpRoot = (0, import_node_path3.join)(resolvePrismerRoot(), ".transfer-staging", `${Date.now()}`);
|
|
9697
9866
|
(0, import_node_fs3.mkdirSync)(tmpRoot, { recursive: true });
|
|
9698
9867
|
try {
|
|
9699
9868
|
(0, import_node_child_process.execFileSync)("tar", ["-xzf", tarAbs, "-C", tmpRoot], { stdio: "inherit" });
|
|
@@ -9703,7 +9872,7 @@ function register17(parent, getIMClient2, _getAPIClient) {
|
|
|
9703
9872
|
`);
|
|
9704
9873
|
process.exit(1);
|
|
9705
9874
|
}
|
|
9706
|
-
const agentsRoot = (0,
|
|
9875
|
+
const agentsRoot = (0, import_node_path3.join)(tmpRoot, "agents");
|
|
9707
9876
|
if (!(0, import_node_fs3.existsSync)(agentsRoot)) {
|
|
9708
9877
|
(0, import_node_fs3.rmSync)(tmpRoot, { recursive: true, force: true });
|
|
9709
9878
|
process.stderr.write("Error: tar layout invalid \u2014 no agents/ root inside archive\n");
|
|
@@ -9717,8 +9886,8 @@ function register17(parent, getIMClient2, _getAPIClient) {
|
|
|
9717
9886
|
process.exit(1);
|
|
9718
9887
|
}
|
|
9719
9888
|
const agentId = entries[0];
|
|
9720
|
-
const stagedAgentDir = (0,
|
|
9721
|
-
const manifestPath = (0,
|
|
9889
|
+
const stagedAgentDir = (0, import_node_path3.join)(agentsRoot, agentId);
|
|
9890
|
+
const manifestPath = (0, import_node_path3.join)(stagedAgentDir, "transfer-manifest.json");
|
|
9722
9891
|
if (!(0, import_node_fs3.existsSync)(manifestPath)) {
|
|
9723
9892
|
(0, import_node_fs3.rmSync)(tmpRoot, { recursive: true, force: true });
|
|
9724
9893
|
process.stderr.write("Error: transfer-manifest.json missing from archive\n");
|
|
@@ -9766,7 +9935,7 @@ function register17(parent, getIMClient2, _getAPIClient) {
|
|
|
9766
9935
|
);
|
|
9767
9936
|
process.exit(1);
|
|
9768
9937
|
}
|
|
9769
|
-
(0, import_node_fs3.mkdirSync)((0,
|
|
9938
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path3.join)(resolvePrismerRoot(), "devices", toDaemonId, "agents"), { recursive: true });
|
|
9770
9939
|
try {
|
|
9771
9940
|
(0, import_node_child_process.execFileSync)("mv", [stagedAgentDir, targetAgentDir]);
|
|
9772
9941
|
} catch {
|
|
@@ -9817,7 +9986,7 @@ function register17(parent, getIMClient2, _getAPIClient) {
|
|
|
9817
9986
|
});
|
|
9818
9987
|
agent.command("cleanup-orphan").description("release201/09 \xA79.7.3 \u2014 list devices/*/agents/* dirs whose cloud binding points elsewhere").option("--delete", "Actually remove orphan dirs (default: dry-run)").option("--json", "Output raw JSON list").action(async (opts) => {
|
|
9819
9988
|
const { daemonId } = readDaemonConfig();
|
|
9820
|
-
const devicesRoot = (0,
|
|
9989
|
+
const devicesRoot = (0, import_node_path3.join)(resolvePrismerRoot(), "devices");
|
|
9821
9990
|
if (!(0, import_node_fs3.existsSync)(devicesRoot)) {
|
|
9822
9991
|
if (opts.json) process.stdout.write("[]\n");
|
|
9823
9992
|
else console.log("No devices/ dir yet.");
|
|
@@ -9826,10 +9995,10 @@ function register17(parent, getIMClient2, _getAPIClient) {
|
|
|
9826
9995
|
const orphans = [];
|
|
9827
9996
|
for (const did of (0, import_node_fs3.readdirSync)(devicesRoot)) {
|
|
9828
9997
|
if (did === daemonId) continue;
|
|
9829
|
-
const agentsRoot = (0,
|
|
9998
|
+
const agentsRoot = (0, import_node_path3.join)(devicesRoot, did, "agents");
|
|
9830
9999
|
if (!(0, import_node_fs3.existsSync)(agentsRoot)) continue;
|
|
9831
10000
|
for (const aid of (0, import_node_fs3.readdirSync)(agentsRoot)) {
|
|
9832
|
-
const dir = (0,
|
|
10001
|
+
const dir = (0, import_node_path3.join)(agentsRoot, aid);
|
|
9833
10002
|
try {
|
|
9834
10003
|
const st = (0, import_node_fs3.statSync)(dir);
|
|
9835
10004
|
if (!st.isDirectory()) continue;
|
|
@@ -10578,16 +10747,32 @@ function getIMClient() {
|
|
|
10578
10747
|
const cfg = readConfig();
|
|
10579
10748
|
const env = cfg?.default?.environment || "production";
|
|
10580
10749
|
const baseUrl = cfg?.default?.base_url || "";
|
|
10750
|
+
const agentUsername = process.env.PRISMER_AGENT_USERNAME;
|
|
10751
|
+
const imAgentOpt = agentUsername ? { imAgent: agentUsername } : {};
|
|
10752
|
+
const workspaceId = process.env.PRISMER_WORKSPACE_ID;
|
|
10753
|
+
const imWorkspaceOpt = workspaceId ? { imWorkspace: workspaceId } : {};
|
|
10581
10754
|
const imToken = cfg?.auth?.im_token;
|
|
10582
10755
|
if (imToken) {
|
|
10583
|
-
return new PrismerClient({
|
|
10756
|
+
return new PrismerClient({
|
|
10757
|
+
apiKey: imToken,
|
|
10758
|
+
environment: env,
|
|
10759
|
+
...baseUrl ? { baseUrl } : {},
|
|
10760
|
+
...imAgentOpt,
|
|
10761
|
+
...imWorkspaceOpt
|
|
10762
|
+
});
|
|
10584
10763
|
}
|
|
10585
10764
|
const apiKey = cfg?.default?.api_key;
|
|
10586
10765
|
if (!apiKey) {
|
|
10587
10766
|
errorLine('No credentials. Run "cloud setup" first (or "cloud setup --agent" / "cloud register <username>" for IM-JWT path).');
|
|
10588
10767
|
process.exit(1);
|
|
10589
10768
|
}
|
|
10590
|
-
return new PrismerClient({
|
|
10769
|
+
return new PrismerClient({
|
|
10770
|
+
apiKey,
|
|
10771
|
+
environment: env,
|
|
10772
|
+
...baseUrl ? { baseUrl } : {},
|
|
10773
|
+
...imAgentOpt,
|
|
10774
|
+
...imWorkspaceOpt
|
|
10775
|
+
});
|
|
10591
10776
|
}
|
|
10592
10777
|
function getAPIClient() {
|
|
10593
10778
|
const cfg = readConfig();
|
|
@@ -10598,7 +10783,11 @@ function getAPIClient() {
|
|
|
10598
10783
|
}
|
|
10599
10784
|
const env = cfg?.default?.environment || "production";
|
|
10600
10785
|
const baseUrl = cfg?.default?.base_url || "";
|
|
10601
|
-
|
|
10786
|
+
const agentUsername = process.env.PRISMER_AGENT_USERNAME;
|
|
10787
|
+
const imAgentOpt = agentUsername ? { imAgent: agentUsername } : {};
|
|
10788
|
+
const workspaceId = process.env.PRISMER_WORKSPACE_ID;
|
|
10789
|
+
const imWorkspaceOpt = workspaceId ? { imWorkspace: workspaceId } : {};
|
|
10790
|
+
return new PrismerClient({ apiKey, environment: env, ...baseUrl ? { baseUrl } : {}, ...imAgentOpt, ...imWorkspaceOpt });
|
|
10602
10791
|
}
|
|
10603
10792
|
var program = new import_commander.Command();
|
|
10604
10793
|
program.name("cloud").description("Prismer Cloud SDK CLI").version(cliVersion);
|
|
@@ -10997,6 +11186,59 @@ program.command("send").description("Send a direct message (shortcut for: im sen
|
|
|
10997
11186
|
}
|
|
10998
11187
|
success(`Message sent (conversation: ${res.data?.conversationId})`);
|
|
10999
11188
|
});
|
|
11189
|
+
program.command("deliver <path>").description("Attach a file you wrote to your current reply (in-container explicit delivery)").option("--run-id <id>", "dispatch run/task id (from <execution_context>; env fallback PRISMER_TASK_ID/RUN_ID)").option("--conversation-id <id>", "conversation id (from <execution_context>; env fallback PRISMER_CONVERSATION_ID)").option("--daemon-port <port>", "daemon local-server port (env fallback PRISMER_DAEMON_PORT, default 3210)").option("--json", "JSON output").action(async (filePath, opts) => {
|
|
11190
|
+
const proxy = detectDeliverProxy({
|
|
11191
|
+
runId: opts.runId,
|
|
11192
|
+
conversationId: opts.conversationId,
|
|
11193
|
+
daemonPort: opts.daemonPort
|
|
11194
|
+
});
|
|
11195
|
+
if (!proxy) {
|
|
11196
|
+
errorLine(
|
|
11197
|
+
"cloud deliver only works inside a daemon dispatch (no PRISMER_TASK_ID/PRISMER_RUN_ID, and no --run-id flag). On hermes, pass --run-id <id> (and --conversation-id <id>) copied from <execution_context>. Outside a dispatch, use `cloud file send <conversationId> <path>`."
|
|
11198
|
+
);
|
|
11199
|
+
process.exit(1);
|
|
11200
|
+
}
|
|
11201
|
+
const result = await proxyDeliver(proxy, filePath, "attach");
|
|
11202
|
+
if (!result.ok) {
|
|
11203
|
+
errorLine(`Delivery failed: ${result.error ?? `daemon returned ${result.status}`}`);
|
|
11204
|
+
process.exit(1);
|
|
11205
|
+
}
|
|
11206
|
+
if (opts.json) {
|
|
11207
|
+
console.log(JSON.stringify(result, null, 2));
|
|
11208
|
+
return;
|
|
11209
|
+
}
|
|
11210
|
+
success(`Attached to your reply (assetId: ${result.assetId ?? "-"})`);
|
|
11211
|
+
});
|
|
11212
|
+
program.command("attach <messageId> <path>").description("Attach a file to a message you ALREADY sent (by its messageId)").option("--run-id <id>", "dispatch run/task id (from <execution_context>; env fallback PRISMER_TASK_ID/RUN_ID)").option("--conversation-id <id>", "conversation id of the target message (from <execution_context>; env fallback PRISMER_CONVERSATION_ID)").option("--daemon-port <port>", "daemon local-server port (env fallback PRISMER_DAEMON_PORT, default 3210)").option("--json", "JSON output").action(async (messageId, filePath, opts) => {
|
|
11213
|
+
const proxy = detectDeliverProxy({
|
|
11214
|
+
runId: opts.runId,
|
|
11215
|
+
conversationId: opts.conversationId,
|
|
11216
|
+
daemonPort: opts.daemonPort
|
|
11217
|
+
});
|
|
11218
|
+
if (!proxy) {
|
|
11219
|
+
errorLine(
|
|
11220
|
+
"cloud attach only works inside a daemon dispatch (no PRISMER_TASK_ID/PRISMER_RUN_ID, and no --run-id flag). On hermes, pass --run-id <id> and --conversation-id <id> copied from <execution_context>."
|
|
11221
|
+
);
|
|
11222
|
+
process.exit(1);
|
|
11223
|
+
}
|
|
11224
|
+
const conversationId = (opts.conversationId || proxy.conversationId || "").trim();
|
|
11225
|
+
if (!conversationId) {
|
|
11226
|
+
errorLine(
|
|
11227
|
+
"cloud attach needs the conversation id of the target message. Set PRISMER_CONVERSATION_ID or pass --conversation-id <id> (copy it from <execution_context>)."
|
|
11228
|
+
);
|
|
11229
|
+
process.exit(1);
|
|
11230
|
+
}
|
|
11231
|
+
const result = await proxyDeliver(proxy, filePath, "message-attach", conversationId, messageId);
|
|
11232
|
+
if (!result.ok) {
|
|
11233
|
+
errorLine(`Attach failed: ${result.error ?? `daemon returned ${result.status}`}`);
|
|
11234
|
+
process.exit(1);
|
|
11235
|
+
}
|
|
11236
|
+
if (opts.json) {
|
|
11237
|
+
console.log(JSON.stringify(result, null, 2));
|
|
11238
|
+
return;
|
|
11239
|
+
}
|
|
11240
|
+
success(`Attached to message ${messageId} (assetId: ${result.assetId ?? "-"})`);
|
|
11241
|
+
});
|
|
11000
11242
|
program.command("emit <namespace.name>").description("Emit a metric event (shortcut for: metric emit)").option("--value <value>", "metric value (number or string)").option("--dim <k=v>", "dimension (repeatable; workspaceId is required)", (val, prev = []) => {
|
|
11001
11243
|
prev.push(val);
|
|
11002
11244
|
return prev;
|
package/dist/index.d.mts
CHANGED
|
@@ -258,6 +258,13 @@ interface PrismerConfig {
|
|
|
258
258
|
fetch?: typeof fetch;
|
|
259
259
|
/** Default X-IM-Agent header for IM requests (select which agent identity to use) */
|
|
260
260
|
imAgent?: string;
|
|
261
|
+
/**
|
|
262
|
+
* Default X-IM-Workspace header for IM requests (release202/09 §3.6 B).
|
|
263
|
+
* Lets the cloud agent-proxy reach its workspace-scoped fallback when the
|
|
264
|
+
* owner `userId`/`numericId` bridge can't resolve the agent. Optional —
|
|
265
|
+
* absent header preserves legacy behavior.
|
|
266
|
+
*/
|
|
267
|
+
imWorkspace?: string;
|
|
261
268
|
/** Enable offline-first mode for IM with local persistence and sync */
|
|
262
269
|
offline?: OfflineConfig;
|
|
263
270
|
/**
|
|
@@ -5284,6 +5291,7 @@ declare class PrismerClient {
|
|
|
5284
5291
|
private readonly timeout;
|
|
5285
5292
|
private readonly fetchFn;
|
|
5286
5293
|
private readonly imAgent?;
|
|
5294
|
+
private readonly imWorkspace?;
|
|
5287
5295
|
private _offlineManager;
|
|
5288
5296
|
/** AIP identity for auto-signing (v1.8.0 S1) */
|
|
5289
5297
|
private _identity;
|
package/dist/index.d.ts
CHANGED
|
@@ -258,6 +258,13 @@ interface PrismerConfig {
|
|
|
258
258
|
fetch?: typeof fetch;
|
|
259
259
|
/** Default X-IM-Agent header for IM requests (select which agent identity to use) */
|
|
260
260
|
imAgent?: string;
|
|
261
|
+
/**
|
|
262
|
+
* Default X-IM-Workspace header for IM requests (release202/09 §3.6 B).
|
|
263
|
+
* Lets the cloud agent-proxy reach its workspace-scoped fallback when the
|
|
264
|
+
* owner `userId`/`numericId` bridge can't resolve the agent. Optional —
|
|
265
|
+
* absent header preserves legacy behavior.
|
|
266
|
+
*/
|
|
267
|
+
imWorkspace?: string;
|
|
261
268
|
/** Enable offline-first mode for IM with local persistence and sync */
|
|
262
269
|
offline?: OfflineConfig;
|
|
263
270
|
/**
|
|
@@ -5284,6 +5291,7 @@ declare class PrismerClient {
|
|
|
5284
5291
|
private readonly timeout;
|
|
5285
5292
|
private readonly fetchFn;
|
|
5286
5293
|
private readonly imAgent?;
|
|
5294
|
+
private readonly imWorkspace?;
|
|
5287
5295
|
private _offlineManager;
|
|
5288
5296
|
/** AIP identity for auto-signing (v1.8.0 S1) */
|
|
5289
5297
|
private _identity;
|
package/dist/index.js
CHANGED
|
@@ -5579,6 +5579,19 @@ var FilesClient = class {
|
|
|
5579
5579
|
*/
|
|
5580
5580
|
async sendFile(conversationId, input, opts) {
|
|
5581
5581
|
const uploaded = await this.upload(input, opts);
|
|
5582
|
+
const outboxDir = process.env.PRISMER_OUTBOX_DIR;
|
|
5583
|
+
if (outboxDir) {
|
|
5584
|
+
try {
|
|
5585
|
+
const fsMod = await import("fs");
|
|
5586
|
+
const pathMod = await import("path");
|
|
5587
|
+
const srcPath = typeof input === "string" ? input : input.path;
|
|
5588
|
+
if (srcPath && typeof srcPath === "string") {
|
|
5589
|
+
await fsMod.promises.mkdir(outboxDir, { recursive: true });
|
|
5590
|
+
fsMod.cpSync(srcPath, pathMod.join(outboxDir, pathMod.basename(srcPath)));
|
|
5591
|
+
}
|
|
5592
|
+
} catch {
|
|
5593
|
+
}
|
|
5594
|
+
}
|
|
5582
5595
|
const msgRes = await this._r("POST", `/api/im/messages/${conversationId}`, {
|
|
5583
5596
|
content: opts?.content || uploaded.fileName,
|
|
5584
5597
|
type: "file",
|
|
@@ -5895,6 +5908,7 @@ var PrismerClient = class {
|
|
|
5895
5908
|
this.timeout = config.timeout || 3e4;
|
|
5896
5909
|
this.fetchFn = config.fetch || fetch;
|
|
5897
5910
|
this.imAgent = config.imAgent;
|
|
5911
|
+
this.imWorkspace = config.imWorkspace;
|
|
5898
5912
|
if (config.identity) {
|
|
5899
5913
|
if (config.identity === "auto" && this.apiKey) {
|
|
5900
5914
|
this._identityReady = import_aip_sdk.AIPIdentity.fromApiKey(this.apiKey).then((id) => {
|
|
@@ -5991,6 +6005,7 @@ var PrismerClient = class {
|
|
|
5991
6005
|
const headers = {};
|
|
5992
6006
|
if (this.apiKey) headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
5993
6007
|
if (this.imAgent) headers["X-IM-Agent"] = this.imAgent;
|
|
6008
|
+
if (this.imWorkspace) headers["X-IM-Workspace"] = this.imWorkspace;
|
|
5994
6009
|
return headers;
|
|
5995
6010
|
}
|
|
5996
6011
|
/**
|
|
@@ -6057,6 +6072,9 @@ var PrismerClient = class {
|
|
|
6057
6072
|
if (this.imAgent) {
|
|
6058
6073
|
headers["X-IM-Agent"] = this.imAgent;
|
|
6059
6074
|
}
|
|
6075
|
+
if (this.imWorkspace) {
|
|
6076
|
+
headers["X-IM-Workspace"] = this.imWorkspace;
|
|
6077
|
+
}
|
|
6060
6078
|
if (opts?.headers) {
|
|
6061
6079
|
for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;
|
|
6062
6080
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -5497,6 +5497,19 @@ var FilesClient = class {
|
|
|
5497
5497
|
*/
|
|
5498
5498
|
async sendFile(conversationId, input, opts) {
|
|
5499
5499
|
const uploaded = await this.upload(input, opts);
|
|
5500
|
+
const outboxDir = process.env.PRISMER_OUTBOX_DIR;
|
|
5501
|
+
if (outboxDir) {
|
|
5502
|
+
try {
|
|
5503
|
+
const fsMod = await import("fs");
|
|
5504
|
+
const pathMod = await import("path");
|
|
5505
|
+
const srcPath = typeof input === "string" ? input : input.path;
|
|
5506
|
+
if (srcPath && typeof srcPath === "string") {
|
|
5507
|
+
await fsMod.promises.mkdir(outboxDir, { recursive: true });
|
|
5508
|
+
fsMod.cpSync(srcPath, pathMod.join(outboxDir, pathMod.basename(srcPath)));
|
|
5509
|
+
}
|
|
5510
|
+
} catch {
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5500
5513
|
const msgRes = await this._r("POST", `/api/im/messages/${conversationId}`, {
|
|
5501
5514
|
content: opts?.content || uploaded.fileName,
|
|
5502
5515
|
type: "file",
|
|
@@ -5813,6 +5826,7 @@ var PrismerClient = class {
|
|
|
5813
5826
|
this.timeout = config.timeout || 3e4;
|
|
5814
5827
|
this.fetchFn = config.fetch || fetch;
|
|
5815
5828
|
this.imAgent = config.imAgent;
|
|
5829
|
+
this.imWorkspace = config.imWorkspace;
|
|
5816
5830
|
if (config.identity) {
|
|
5817
5831
|
if (config.identity === "auto" && this.apiKey) {
|
|
5818
5832
|
this._identityReady = AIPIdentity.fromApiKey(this.apiKey).then((id) => {
|
|
@@ -5909,6 +5923,7 @@ var PrismerClient = class {
|
|
|
5909
5923
|
const headers = {};
|
|
5910
5924
|
if (this.apiKey) headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
5911
5925
|
if (this.imAgent) headers["X-IM-Agent"] = this.imAgent;
|
|
5926
|
+
if (this.imWorkspace) headers["X-IM-Workspace"] = this.imWorkspace;
|
|
5912
5927
|
return headers;
|
|
5913
5928
|
}
|
|
5914
5929
|
/**
|
|
@@ -5975,6 +5990,9 @@ var PrismerClient = class {
|
|
|
5975
5990
|
if (this.imAgent) {
|
|
5976
5991
|
headers["X-IM-Agent"] = this.imAgent;
|
|
5977
5992
|
}
|
|
5993
|
+
if (this.imWorkspace) {
|
|
5994
|
+
headers["X-IM-Workspace"] = this.imWorkspace;
|
|
5995
|
+
}
|
|
5978
5996
|
if (opts?.headers) {
|
|
5979
5997
|
for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;
|
|
5980
5998
|
}
|