@opencomputer/cli 0.6.5 → 0.6.6
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 +21 -17
- package/dist/api.d.ts +26 -2
- package/dist/api.js +22 -3
- package/dist/api.js.map +1 -1
- package/dist/api.test.d.ts +1 -0
- package/dist/api.test.js +21 -0
- package/dist/api.test.js.map +1 -0
- package/dist/binding.d.ts +0 -2
- package/dist/binding.js +7 -31
- package/dist/binding.js.map +1 -1
- package/dist/binding.test.js +24 -3
- package/dist/binding.test.js.map +1 -1
- package/dist/commands.d.ts +1 -0
- package/dist/commands.js +164 -82
- package/dist/commands.js.map +1 -1
- package/dist/dev.d.ts +0 -8
- package/dist/dev.js +1 -159
- package/dist/dev.js.map +1 -1
- package/dist/dev.test.js +2 -90
- package/dist/dev.test.js.map +1 -1
- package/dist/doctor.d.ts +19 -0
- package/dist/doctor.js +207 -0
- package/dist/doctor.js.map +1 -0
- package/dist/doctor.test.d.ts +1 -0
- package/dist/doctor.test.js +71 -0
- package/dist/doctor.test.js.map +1 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.js +74 -0
- package/dist/errors.js.map +1 -0
- package/dist/errors.test.d.ts +1 -0
- package/dist/errors.test.js +14 -0
- package/dist/errors.test.js.map +1 -0
- package/dist/index.js +16 -4
- package/dist/index.js.map +1 -1
- package/dist/project.js +10 -10
- package/dist/project.test.js +1 -1
- package/dist/project.test.js.map +1 -1
- package/package.json +1 -1
package/dist/commands.js
CHANGED
|
@@ -7,6 +7,8 @@ import { ensureProjectBinding, findOpenComputerProjectRoot, } from "./binding.js
|
|
|
7
7
|
import { assertStarterTarget, buildAgentArtifact, findAgentRoot, initializeAgentProject, } from "./project.js";
|
|
8
8
|
import { developmentAgentReference, parseSessionCommand, resolveProjectAgent, } from "./session-command.js";
|
|
9
9
|
import { formatSessionEvent } from "./session-prompt.js";
|
|
10
|
+
import { doctorProject } from "./doctor.js";
|
|
11
|
+
import { CLIError } from "./errors.js";
|
|
10
12
|
export function deploymentAlias(requestedAlias) {
|
|
11
13
|
return requestedAlias ?? "development";
|
|
12
14
|
}
|
|
@@ -16,6 +18,9 @@ export function shouldBindModelAccessProject(projectReference, currentAgentRoot)
|
|
|
16
18
|
function printJSON(value) {
|
|
17
19
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
18
20
|
}
|
|
21
|
+
function printJSONLine(value) {
|
|
22
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
23
|
+
}
|
|
19
24
|
function flag(args, name) {
|
|
20
25
|
const index = args.indexOf(name);
|
|
21
26
|
if (index < 0)
|
|
@@ -56,52 +61,33 @@ function consumeModelAccessProvider(args) {
|
|
|
56
61
|
}
|
|
57
62
|
return "codex";
|
|
58
63
|
}
|
|
59
|
-
async function
|
|
60
|
-
if (!
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
process.stdin.resume();
|
|
75
|
-
return new Promise((resolve, reject) => {
|
|
76
|
-
let value = "";
|
|
77
|
-
const finish = (error) => {
|
|
78
|
-
process.stdin.off("data", onData);
|
|
79
|
-
process.stdin.setRawMode(false);
|
|
80
|
-
process.stdin.pause();
|
|
81
|
-
process.stderr.write("\n");
|
|
82
|
-
if (error)
|
|
83
|
-
reject(error);
|
|
84
|
-
else if (!value)
|
|
85
|
-
reject(new Error("Secret value was empty"));
|
|
86
|
-
else
|
|
87
|
-
resolve(value);
|
|
88
|
-
};
|
|
89
|
-
const onData = (chunk) => {
|
|
90
|
-
for (const byte of chunk) {
|
|
91
|
-
if (byte === 3)
|
|
92
|
-
return finish(new Error("Secret entry cancelled"));
|
|
93
|
-
if (byte === 10 || byte === 13)
|
|
94
|
-
return finish();
|
|
95
|
-
if (byte === 8 || byte === 127)
|
|
96
|
-
value = value.slice(0, -1);
|
|
97
|
-
else
|
|
98
|
-
value += String.fromCharCode(byte);
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
process.stdin.on("data", onData);
|
|
102
|
-
});
|
|
64
|
+
async function readStdinValue(enabled) {
|
|
65
|
+
if (!enabled) {
|
|
66
|
+
throw new CLIError("value_stdin_required", "A value must be supplied through standard input.", "Pipe the value into this command and add `--value-stdin`.");
|
|
67
|
+
}
|
|
68
|
+
if (process.stdin.isTTY) {
|
|
69
|
+
throw new CLIError("value_stdin_required", "--value-stdin requires piped standard input.", "Use `printf %s \"$VALUE\" | opencomputer ... --value-stdin`.");
|
|
70
|
+
}
|
|
71
|
+
const chunks = [];
|
|
72
|
+
for await (const chunk of process.stdin) {
|
|
73
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
74
|
+
}
|
|
75
|
+
const value = Buffer.concat(chunks).toString("utf8").replace(/\r?\n$/, "");
|
|
76
|
+
if (!value)
|
|
77
|
+
throw new Error("Standard-input value was empty");
|
|
78
|
+
return value;
|
|
103
79
|
}
|
|
104
|
-
|
|
80
|
+
function printDoctor(result, json) {
|
|
81
|
+
if (json)
|
|
82
|
+
return printJSON(result);
|
|
83
|
+
for (const item of result.diagnostics) {
|
|
84
|
+
process.stdout.write(`${item.severity.toUpperCase()} ${item.code} ${item.file}${item.line ? `:${item.line}` : ""}\n` +
|
|
85
|
+
` ${item.message}\n fix: ${item.hint}\n`);
|
|
86
|
+
}
|
|
87
|
+
process.stdout.write(`${result.ok ? "Doctor passed" : "Doctor failed"}: ${result.summary.errors} errors, ` +
|
|
88
|
+
`${result.summary.warnings} warnings in ${result.durationMs}ms.\n`);
|
|
89
|
+
}
|
|
90
|
+
async function selectedProject(client, config, reference) {
|
|
105
91
|
if (reference) {
|
|
106
92
|
const project = (await client.projects()).find((candidate) => candidate.id === reference || candidate.slug === reference);
|
|
107
93
|
if (!project)
|
|
@@ -112,9 +98,7 @@ async function selectedProject(client, config, reference, interactive = true) {
|
|
|
112
98
|
return { projectId: project.id, agentId: agent.id };
|
|
113
99
|
}
|
|
114
100
|
const root = await findOpenComputerProjectRoot(process.cwd());
|
|
115
|
-
const binding = await ensureProjectBinding(client, config, root
|
|
116
|
-
interactive,
|
|
117
|
-
});
|
|
101
|
+
const binding = await ensureProjectBinding(client, config, root);
|
|
118
102
|
return { projectId: binding.projectId, agentId: binding.agentId };
|
|
119
103
|
}
|
|
120
104
|
async function selectedSessionAgent(client, project, selector) {
|
|
@@ -200,7 +184,7 @@ function printAgentEvent(event, json) {
|
|
|
200
184
|
printToolProgress(event);
|
|
201
185
|
}
|
|
202
186
|
}
|
|
203
|
-
async function sendAgentTurn(client, sessionId, prompt, keep, json) {
|
|
187
|
+
async function sendAgentTurn(client, sessionId, prompt, keep, json, idempotencyKey) {
|
|
204
188
|
const existing = await client.events(sessionId, 0);
|
|
205
189
|
let cursor = existing.at(-1)?.seq ?? 0;
|
|
206
190
|
const session = await client.session(sessionId);
|
|
@@ -210,7 +194,7 @@ async function sendAgentTurn(client, sessionId, prompt, keep, json) {
|
|
|
210
194
|
const connected = await waitForEvent(client, sessionId, cursor, (event) => event.type === "runtime.connected", () => undefined, 90_000);
|
|
211
195
|
cursor = connected.cursor;
|
|
212
196
|
}
|
|
213
|
-
const turn = await client.createTurn(sessionId, prompt);
|
|
197
|
+
const turn = await client.createTurn(sessionId, prompt, idempotencyKey);
|
|
214
198
|
let streamedText = "";
|
|
215
199
|
let completedText = "";
|
|
216
200
|
const completed = await waitForEvent(client, sessionId, cursor, (event) => event.type === "turn.completed" || event.type === "turn.failed", (event) => {
|
|
@@ -274,6 +258,33 @@ async function attachSession(client, sessionId, json) {
|
|
|
274
258
|
process.off("SIGINT", stop);
|
|
275
259
|
}
|
|
276
260
|
}
|
|
261
|
+
async function tailSession(client, sessionId, after, follow, json) {
|
|
262
|
+
let cursor = after;
|
|
263
|
+
let stopped = false;
|
|
264
|
+
const stop = () => {
|
|
265
|
+
stopped = true;
|
|
266
|
+
};
|
|
267
|
+
process.once("SIGINT", stop);
|
|
268
|
+
try {
|
|
269
|
+
do {
|
|
270
|
+
const events = await client.events(sessionId, cursor);
|
|
271
|
+
for (const event of events) {
|
|
272
|
+
cursor = Math.max(cursor, event.seq);
|
|
273
|
+
if (json)
|
|
274
|
+
printJSONLine({ sessionId, cursor: event.seq, ...event });
|
|
275
|
+
else {
|
|
276
|
+
process.stdout.write(`${event.seq} ${event.type} ${JSON.stringify(event.data)}\n`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (follow && !stopped) {
|
|
280
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
281
|
+
}
|
|
282
|
+
} while (follow && !stopped);
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
process.off("SIGINT", stop);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
277
288
|
export function nextAgentEventDeadline(deadline, timeoutMs, receivedEvents, now = Date.now()) {
|
|
278
289
|
return receivedEvents > 0 ? now + timeoutMs : deadline;
|
|
279
290
|
}
|
|
@@ -301,11 +312,11 @@ async function waitForEvent(client, sessionId, after, terminal, onEvent, timeout
|
|
|
301
312
|
}
|
|
302
313
|
throw new Error("Timed out waiting for the agent.");
|
|
303
314
|
}
|
|
304
|
-
async function runAgent(client, agent, prompt, keep, json, verbose) {
|
|
315
|
+
async function runAgent(client, agent, prompt, keep, json, verbose, idempotencyKey) {
|
|
305
316
|
const created = await client.createSession(agent);
|
|
306
317
|
process.stderr.write(`Starting ${agent}…\n`);
|
|
307
318
|
const connected = await waitForEvent(client, created.session.id, 0, (event) => event.type === "runtime.connected", (event) => printSessionProgress(event, json, verbose), 90_000);
|
|
308
|
-
const turn = await client.createTurn(created.session.id, prompt);
|
|
319
|
+
const turn = await client.createTurn(created.session.id, prompt, idempotencyKey);
|
|
309
320
|
let streamed = false;
|
|
310
321
|
let streamedText = "";
|
|
311
322
|
let completedText = "";
|
|
@@ -348,7 +359,7 @@ async function runAgent(client, agent, prompt, keep, json, verbose) {
|
|
|
348
359
|
export async function runCommand(command, rawArgs, globals) {
|
|
349
360
|
const args = [...rawArgs];
|
|
350
361
|
const config = await resolveConfig(globals);
|
|
351
|
-
const client = new OpenComputerClient(config);
|
|
362
|
+
const client = new OpenComputerClient(config, globals.idempotencyKey);
|
|
352
363
|
if (command === "login") {
|
|
353
364
|
const identity = await login(config, {
|
|
354
365
|
noBrowser: flag(args, "--no-browser"),
|
|
@@ -409,7 +420,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
409
420
|
const enterDirectory = directory === "." ? "" : ` cd ${directory}\n`;
|
|
410
421
|
process.stdout.write(`Created the ${initialized.manifest.name} OpenComputer app\n` +
|
|
411
422
|
`Directory: ${initialized.root}\n` +
|
|
412
|
-
`Project:
|
|
423
|
+
`Project: link explicitly with --project or --create-project\n` +
|
|
413
424
|
`Agents: opencomputer/\n` +
|
|
414
425
|
(spa
|
|
415
426
|
? `Web app: src/ (separate lifecycle)\n\n`
|
|
@@ -442,13 +453,28 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
442
453
|
}
|
|
443
454
|
return;
|
|
444
455
|
}
|
|
456
|
+
if (command === "doctor") {
|
|
457
|
+
if (args.length)
|
|
458
|
+
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
459
|
+
const root = await findOpenComputerProjectRoot(process.cwd());
|
|
460
|
+
const result = await doctorProject(root);
|
|
461
|
+
if (!result.ok) {
|
|
462
|
+
if (!globals.json)
|
|
463
|
+
printDoctor(result, false);
|
|
464
|
+
throw new CLIError("doctor_failed", "Local project diagnostics failed.", "Fix the reported errors and rerun `opencomputer doctor --json`.", result);
|
|
465
|
+
}
|
|
466
|
+
printDoctor(result, globals.json);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
445
469
|
if (command === "link") {
|
|
470
|
+
const project = option(args, "--project");
|
|
471
|
+
const createProjectName = option(args, "--create-project");
|
|
446
472
|
if (args.length)
|
|
447
473
|
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
448
474
|
const root = await findOpenComputerProjectRoot(process.cwd());
|
|
449
475
|
const binding = await ensureProjectBinding(client, config, root, {
|
|
450
|
-
|
|
451
|
-
|
|
476
|
+
project,
|
|
477
|
+
createProjectName,
|
|
452
478
|
});
|
|
453
479
|
if (globals.json)
|
|
454
480
|
printJSON(binding);
|
|
@@ -468,6 +494,10 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
468
494
|
if (!root) {
|
|
469
495
|
throw new Error("No OpenComputer project found. Run `opencomputer init <directory>` first.");
|
|
470
496
|
}
|
|
497
|
+
const diagnosis = await doctorProject(root);
|
|
498
|
+
if (!diagnosis.ok) {
|
|
499
|
+
throw new CLIError("doctor_failed", "Deploy stopped because local project diagnostics failed.", "Run `opencomputer doctor --json`, fix the errors, and deploy again.", diagnosis);
|
|
500
|
+
}
|
|
471
501
|
if (watch) {
|
|
472
502
|
if (requestedAlias && requestedAlias !== "development") {
|
|
473
503
|
throw new Error("--watch deploys only to development; omit --alias or use --alias development");
|
|
@@ -475,7 +505,6 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
475
505
|
await runDeploymentWatch(client, config, root, {
|
|
476
506
|
project,
|
|
477
507
|
createProjectName,
|
|
478
|
-
interactive: !globals.json,
|
|
479
508
|
});
|
|
480
509
|
return;
|
|
481
510
|
}
|
|
@@ -483,10 +512,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
483
512
|
throw new Error("--project and --create-project require --watch");
|
|
484
513
|
}
|
|
485
514
|
const alias = deploymentAlias(requestedAlias);
|
|
486
|
-
const binding = await ensureProjectBinding(client, config, root
|
|
487
|
-
interactive: !globals.json,
|
|
488
|
-
select: true,
|
|
489
|
-
});
|
|
515
|
+
const binding = await ensureProjectBinding(client, config, root);
|
|
490
516
|
const results = await publishProjectDeployment(client, root, binding, alias);
|
|
491
517
|
for (const { built } of results) {
|
|
492
518
|
process.stderr.write(`Built ${built.agentId} in ${String(built.elapsedMs)}ms\n`);
|
|
@@ -509,7 +535,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
509
535
|
if (!agent || !prompt) {
|
|
510
536
|
throw new Error("Usage: opencomputer run <agent> <prompt>");
|
|
511
537
|
}
|
|
512
|
-
const result = await runAgent(client, agent, prompt, keep, globals.json, globals.verbose === true);
|
|
538
|
+
const result = await runAgent(client, agent, prompt, keep, globals.json, globals.verbose === true, globals.idempotencyKey);
|
|
513
539
|
if (globals.json)
|
|
514
540
|
printJSON(result);
|
|
515
541
|
return;
|
|
@@ -520,10 +546,14 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
520
546
|
if (args.length)
|
|
521
547
|
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
522
548
|
process.stderr.write("`opencomputer dev` is deprecated. Use `opencomputer deploy --watch`; start any web app separately.\n");
|
|
523
|
-
|
|
549
|
+
const root = await findOpenComputerProjectRoot(process.cwd());
|
|
550
|
+
const diagnosis = await doctorProject(root);
|
|
551
|
+
if (!diagnosis.ok) {
|
|
552
|
+
throw new CLIError("doctor_failed", "Deploy stopped because local project diagnostics failed.", "Run `opencomputer doctor --json`, fix the errors, and deploy again.", diagnosis);
|
|
553
|
+
}
|
|
554
|
+
await runCloudDevelopment(client, config, root, {
|
|
524
555
|
project,
|
|
525
556
|
createProjectName,
|
|
526
|
-
interactive: !globals.json,
|
|
527
557
|
});
|
|
528
558
|
return;
|
|
529
559
|
}
|
|
@@ -532,7 +562,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
532
562
|
const projectReference = option(args, "--project");
|
|
533
563
|
const agentOption = option(args, "--agent");
|
|
534
564
|
const environment = environmentOption(option(args, "--environment"));
|
|
535
|
-
const project = await selectedProject(client, config, projectReference
|
|
565
|
+
const project = await selectedProject(client, config, projectReference);
|
|
536
566
|
const agentId = agentOption
|
|
537
567
|
? agentOption === "current"
|
|
538
568
|
? project.agentId
|
|
@@ -565,6 +595,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
565
595
|
}
|
|
566
596
|
if (action === "set") {
|
|
567
597
|
const explicitOrigins = options(args, "--allow-origin");
|
|
598
|
+
const valueStdin = flag(args, "--value-stdin");
|
|
568
599
|
if (args.length)
|
|
569
600
|
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
570
601
|
let allowedOrigins = explicitOrigins;
|
|
@@ -584,7 +615,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
584
615
|
const secret = await client.putSecret({
|
|
585
616
|
projectId: project.projectId,
|
|
586
617
|
name,
|
|
587
|
-
value: await
|
|
618
|
+
value: await readStdinValue(valueStdin),
|
|
588
619
|
environment,
|
|
589
620
|
...(agentId ? { agentId } : {}),
|
|
590
621
|
allowedOrigins,
|
|
@@ -636,7 +667,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
636
667
|
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
637
668
|
const currentAgentRoot = projectReference ? null : await findAgentRoot();
|
|
638
669
|
const project = shouldBindModelAccessProject(projectReference, currentAgentRoot)
|
|
639
|
-
? await selectedProject(client, config, projectReference
|
|
670
|
+
? await selectedProject(client, config, projectReference)
|
|
640
671
|
: undefined;
|
|
641
672
|
const environments = project
|
|
642
673
|
? ["development", "production"]
|
|
@@ -709,7 +740,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
709
740
|
const projectReference = option(args, "--project");
|
|
710
741
|
const agentOption = option(args, "--agent");
|
|
711
742
|
const environment = environmentOption(option(args, "--environment"));
|
|
712
|
-
const project = await selectedProject(client, config, projectReference
|
|
743
|
+
const project = await selectedProject(client, config, projectReference);
|
|
713
744
|
const agentId = agentOption
|
|
714
745
|
? agentOption === "current"
|
|
715
746
|
? project.agentId
|
|
@@ -740,12 +771,13 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
740
771
|
throw new Error("Use `opencomputer env set|list|remove <name>`.");
|
|
741
772
|
}
|
|
742
773
|
if (action === "set") {
|
|
774
|
+
const valueStdin = flag(args, "--value-stdin");
|
|
743
775
|
if (args.length)
|
|
744
776
|
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
745
777
|
const variable = await client.putRuntimeVariable({
|
|
746
778
|
projectId: project.projectId,
|
|
747
779
|
name,
|
|
748
|
-
value: await
|
|
780
|
+
value: await readStdinValue(valueStdin),
|
|
749
781
|
environment,
|
|
750
782
|
...(agentId ? { agentId } : {}),
|
|
751
783
|
});
|
|
@@ -779,7 +811,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
779
811
|
const projectReference = option(args, "--project");
|
|
780
812
|
const agentOption = option(args, "--agent");
|
|
781
813
|
const environment = environmentOption(option(args, "--environment"));
|
|
782
|
-
const project = await selectedProject(client, config, projectReference
|
|
814
|
+
const project = await selectedProject(client, config, projectReference);
|
|
783
815
|
const agentId = await selectedSessionAgent(client, project, !agentOption || agentOption === "current" ? undefined : agentOption);
|
|
784
816
|
if (action === "list") {
|
|
785
817
|
if (args.length)
|
|
@@ -806,19 +838,26 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
806
838
|
if (!name || args.length) {
|
|
807
839
|
throw new Error("Use `opencomputer webhooks create <name>`.");
|
|
808
840
|
}
|
|
809
|
-
const
|
|
841
|
+
const existing = (await client.webhooks({
|
|
810
842
|
projectId: project.projectId,
|
|
811
|
-
name,
|
|
812
843
|
environment,
|
|
813
844
|
agentId,
|
|
814
|
-
});
|
|
845
|
+
})).find((candidate) => candidate.name === name);
|
|
846
|
+
const webhook = existing ??
|
|
847
|
+
(await client.createWebhook({
|
|
848
|
+
projectId: project.projectId,
|
|
849
|
+
name,
|
|
850
|
+
environment,
|
|
851
|
+
agentId,
|
|
852
|
+
}));
|
|
815
853
|
if (globals.json)
|
|
816
|
-
printJSON(webhook);
|
|
854
|
+
printJSON({ ...webhook, reused: Boolean(existing) });
|
|
817
855
|
else {
|
|
818
|
-
process.stdout.write(
|
|
856
|
+
process.stdout.write(`${existing ? "Reused" : "Created"} ${webhook.name} (${webhook.id}) for ${agentId}@${environment}.\n` +
|
|
819
857
|
`URL: ${webhook.invocationUrl}\n` +
|
|
820
|
-
|
|
821
|
-
|
|
858
|
+
(existing
|
|
859
|
+
? "The existing token remains unchanged.\n"
|
|
860
|
+
: `Token: ${webhook.token ?? "unavailable"}\nSave this token now. It will not be shown again.\n`));
|
|
822
861
|
}
|
|
823
862
|
return;
|
|
824
863
|
}
|
|
@@ -886,7 +925,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
886
925
|
insideProject = false;
|
|
887
926
|
}
|
|
888
927
|
if (insideProject) {
|
|
889
|
-
agentId = (await selectedProject(client, config
|
|
928
|
+
agentId = (await selectedProject(client, config)).agentId;
|
|
890
929
|
}
|
|
891
930
|
}
|
|
892
931
|
let cursor = "";
|
|
@@ -916,7 +955,50 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
916
955
|
}
|
|
917
956
|
return;
|
|
918
957
|
}
|
|
919
|
-
if (command === "
|
|
958
|
+
if (command === "channels") {
|
|
959
|
+
const action = args.shift();
|
|
960
|
+
if (action !== "status") {
|
|
961
|
+
throw new Error("Use `opencomputer channels status`.");
|
|
962
|
+
}
|
|
963
|
+
const projectReference = option(args, "--project");
|
|
964
|
+
const agentOption = option(args, "--agent");
|
|
965
|
+
const environment = environmentOption(option(args, "--environment"));
|
|
966
|
+
if (args.length)
|
|
967
|
+
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
968
|
+
const project = await selectedProject(client, config, projectReference);
|
|
969
|
+
const agentId = await selectedSessionAgent(client, project, !agentOption || agentOption === "current" ? undefined : agentOption);
|
|
970
|
+
const channels = (await client.channels()).filter((channel) => channel.agentId === agentId && channel.alias === environment);
|
|
971
|
+
if (globals.json)
|
|
972
|
+
printJSON({ projectId: project.projectId, environment, channels });
|
|
973
|
+
else if (!channels.length)
|
|
974
|
+
process.stdout.write("No matching channels.\n");
|
|
975
|
+
else {
|
|
976
|
+
for (const channel of channels) {
|
|
977
|
+
process.stdout.write(`${channel.id} ${channel.status} ${channel.channel} ${channel.agentId}@${channel.alias}\n` +
|
|
978
|
+
` last event: ${channel.lastEventAt ?? "—"}\n` +
|
|
979
|
+
` last delivery: ${channel.lastDelivery ? `${channel.lastDelivery.status} at ${channel.lastDelivery.at}` : "—"}\n` +
|
|
980
|
+
` last error: ${channel.lastError ? `${channel.lastError.category} at ${channel.lastError.at}` : "—"}\n`);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
if (command === "session" || command === "sessions") {
|
|
986
|
+
if (args[0] === "tail") {
|
|
987
|
+
args.shift();
|
|
988
|
+
const sessionId = args.shift();
|
|
989
|
+
const afterValue = option(args, "--after");
|
|
990
|
+
const follow = !flag(args, "--no-follow");
|
|
991
|
+
if (!sessionId)
|
|
992
|
+
throw new Error("A session ID is required.");
|
|
993
|
+
if (args.length)
|
|
994
|
+
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
995
|
+
const after = afterValue ? Number.parseInt(afterValue, 10) : 0;
|
|
996
|
+
if (!Number.isFinite(after) || after < 0) {
|
|
997
|
+
throw new Error("--after must be a non-negative event cursor");
|
|
998
|
+
}
|
|
999
|
+
await tailSession(client, sessionId, after, follow, globals.json);
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
920
1002
|
const session = parseSessionCommand(args);
|
|
921
1003
|
const sessionArgs = session.args;
|
|
922
1004
|
if (session.action === "list") {
|
|
@@ -933,11 +1015,11 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
933
1015
|
}
|
|
934
1016
|
if (session.action === "create") {
|
|
935
1017
|
const prompt = sessionArgs.join(" ").trim();
|
|
936
|
-
const project = await selectedProject(client, config, undefined
|
|
1018
|
+
const project = await selectedProject(client, config, undefined);
|
|
937
1019
|
const agentId = await selectedSessionAgent(client, project, session.agent);
|
|
938
1020
|
const agent = developmentAgentReference(agentId);
|
|
939
1021
|
if (prompt) {
|
|
940
|
-
const result = await runAgent(client, agent, prompt, session.keep, globals.json, globals.verbose === true);
|
|
1022
|
+
const result = await runAgent(client, agent, prompt, session.keep, globals.json, globals.verbose === true, globals.idempotencyKey);
|
|
941
1023
|
if (globals.json)
|
|
942
1024
|
printJSON(result);
|
|
943
1025
|
return;
|
|
@@ -983,7 +1065,7 @@ export async function runCommand(command, rawArgs, globals) {
|
|
|
983
1065
|
const prompt = sessionArgs.join(" ").trim();
|
|
984
1066
|
if (!prompt)
|
|
985
1067
|
throw new Error("A prompt is required.");
|
|
986
|
-
const result = await sendAgentTurn(client, sessionId, prompt, session.keep, globals.json);
|
|
1068
|
+
const result = await sendAgentTurn(client, sessionId, prompt, session.keep, globals.json, globals.idempotencyKey);
|
|
987
1069
|
if (globals.json) {
|
|
988
1070
|
printJSON({ sessionId, ...result, status: "completed" });
|
|
989
1071
|
}
|