@ocis/myagent-cli 0.2.4 → 0.2.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 +5 -3
- package/dist/index.js +13 -4
- package/dist/protocol/client.d.ts +8 -1
- package/dist/protocol/client.js +25 -6
- package/dist/protocol/types.d.ts +4 -0
- package/dist/ui/app.js +22 -0
- package/dist/ui/help.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -229,7 +229,7 @@ terminal.
|
|
|
229
229
|
|
|
230
230
|
### Commands
|
|
231
231
|
|
|
232
|
-
`/help` `/new` `/session [all]` (`/sessions`, `/resume` — aliases) `/plan` `/coding` `/cowork` `/mode` `/edit` `/thinking` `/model` `/compact`
|
|
232
|
+
`/help` `/new` `/session [all]` (`/sessions`, `/resume` — aliases) `/plan` `/coding` `/cowork` `/mode` `/edit` `/thinking` `/model` `/balance` `/compact`
|
|
233
233
|
`/stop` `/reload` `/export` `/config` `/quit`
|
|
234
234
|
|
|
235
235
|
## Sessions
|
|
@@ -291,8 +291,10 @@ Integrations page (`https://host/integrations/<id>`) — the integration id is d
|
|
|
291
291
|
Create an integration + API key on the MyAgent **Integrations** page. Recommended settings
|
|
292
292
|
for the CLI:
|
|
293
293
|
|
|
294
|
-
- **Tools**: leave empty (all coding tools are supplied by the CLI) or enable `
|
|
295
|
-
server-side fetching.
|
|
294
|
+
- **Tools**: leave empty (all coding tools are supplied by the CLI) or enable the `web` group for
|
|
295
|
+
server-side fetching. Server tool groups are extras — the CLI's own tools are client-side.
|
|
296
|
+
- **Skills**: enable the ones you need. The CLI's local tools satisfy their script needs
|
|
297
|
+
(`bash`/`read`/`write`), so no server tool group is required for them.
|
|
296
298
|
- **Model**: any tool-capable model with a reasonable context window.
|
|
297
299
|
|
|
298
300
|
The CLI and the server deploy in lockstep — every documented integration-API feature is
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { stdin as input, stdout as output } from "node:process";
|
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import { resolve } from "node:path";
|
|
12
12
|
import pkg from "../package.json" with { type: "json" };
|
|
13
|
-
import { IntegrationClient } from "./protocol/client.js";
|
|
13
|
+
import { IntegrationClient, IntegrationApiError } from "./protocol/client.js";
|
|
14
14
|
import { ToolRegistry } from "./tools/registry.js";
|
|
15
15
|
import { combinedIntegrationUrl, configDir, isConfigured, loadConfig, migrateLegacyConfigDir, resolveConfig, saveConfig, sessionsPath, splitIntegrationUrl, } from "./config.js";
|
|
16
16
|
import { SessionIndex } from "./agent/sessions.js";
|
|
@@ -335,15 +335,24 @@ async function main() {
|
|
|
335
335
|
integrationId: config.integrationId,
|
|
336
336
|
apiKey: config.apiKey,
|
|
337
337
|
});
|
|
338
|
-
let status;
|
|
338
|
+
let status = null;
|
|
339
339
|
try {
|
|
340
340
|
// Bounded connect: a hung server must fail (exit 2) instead of hanging CI.
|
|
341
341
|
status = await client.getStatus({ signal: AbortSignal.timeout(30_000) });
|
|
342
342
|
}
|
|
343
343
|
catch (err) {
|
|
344
|
-
|
|
344
|
+
// A paused platform sandbox answers the status check with 503 — the check
|
|
345
|
+
// deliberately does not wake it (see the platform's proxy-activator). That
|
|
346
|
+
// is not a connection failure: the first run wakes the sandbox, so proceed
|
|
347
|
+
// with a notice instead of failing.
|
|
348
|
+
if (err instanceof IntegrationApiError && err.status === 503) {
|
|
349
|
+
process.stderr.write("Sandbox is paused — it will start on your first message.\n");
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
return fail(args.flags.outputFormat, `Could not reach ${config.baseUrl}: ${err instanceof Error ? err.message : String(err)}`, "connection_failed");
|
|
353
|
+
}
|
|
345
354
|
}
|
|
346
|
-
if (!status.enabled) {
|
|
355
|
+
if (status && !status.enabled) {
|
|
347
356
|
return fail(args.flags.outputFormat, `Integration "${status.label}" is disabled on the server.`, "integration_disabled");
|
|
348
357
|
}
|
|
349
358
|
const sessionIndex = await SessionIndex.load(sessionsPath());
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AguiEvent, AguiInputMessage, AguiRunRequest, AguiToolDef, IntegrationStatus, ModelInfo, RunStreamResult, SessionDetail, SessionSummary, WorkspaceEntry, WorkspaceFile, WorkspaceWriteResult } from "./types.js";
|
|
1
|
+
import type { AguiEvent, AguiInputMessage, AguiRunRequest, AguiToolDef, BalanceInfo, IntegrationStatus, ModelInfo, RunStreamResult, SessionDetail, SessionSummary, WorkspaceEntry, WorkspaceFile, WorkspaceWriteResult } from "./types.js";
|
|
2
2
|
export interface IntegrationClientOptions {
|
|
3
3
|
baseUrl: string;
|
|
4
4
|
integrationId: string;
|
|
@@ -73,6 +73,13 @@ export declare class IntegrationClient {
|
|
|
73
73
|
getStatus(opts?: {
|
|
74
74
|
signal?: AbortSignal;
|
|
75
75
|
}): Promise<IntegrationStatus>;
|
|
76
|
+
/**
|
|
77
|
+
* The user's platform credit balance. Platform mode only — a standalone
|
|
78
|
+
* server answers 404 with code `platform_only`. Used by `/balance`.
|
|
79
|
+
*/
|
|
80
|
+
getBalance(opts?: {
|
|
81
|
+
signal?: AbortSignal;
|
|
82
|
+
}): Promise<BalanceInfo>;
|
|
76
83
|
/**
|
|
77
84
|
* Models this integration accepts (default first, `default: true` marks it).
|
|
78
85
|
* A forced-model integration returns exactly one entry — there is nothing to
|
package/dist/protocol/client.js
CHANGED
|
@@ -126,6 +126,13 @@ export class IntegrationClient {
|
|
|
126
126
|
async getStatus(opts = {}) {
|
|
127
127
|
return this.json(this.url(""), { method: "GET", signal: opts.signal });
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* The user's platform credit balance. Platform mode only — a standalone
|
|
131
|
+
* server answers 404 with code `platform_only`. Used by `/balance`.
|
|
132
|
+
*/
|
|
133
|
+
async getBalance(opts = {}) {
|
|
134
|
+
return this.json(this.url("/balance"), { method: "GET", signal: opts.signal });
|
|
135
|
+
}
|
|
129
136
|
/**
|
|
130
137
|
* Models this integration accepts (default first, `default: true` marks it).
|
|
131
138
|
* A forced-model integration returns exactly one entry — there is nothing to
|
|
@@ -231,14 +238,26 @@ export class IntegrationClient {
|
|
|
231
238
|
let message = `HTTP ${res.status}`;
|
|
232
239
|
let code;
|
|
233
240
|
let details;
|
|
241
|
+
// Read the body once as text: myagent's error bodies are JSON, but the
|
|
242
|
+
// platform proxy answers with plain text (e.g. its 503 for a paused
|
|
243
|
+
// sandbox) — keep that text instead of collapsing it to "HTTP 503".
|
|
244
|
+
let text = "";
|
|
234
245
|
try {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
246
|
+
text = await res.text();
|
|
247
|
+
}
|
|
248
|
+
catch { /* unreadable body */ }
|
|
249
|
+
if (text) {
|
|
250
|
+
try {
|
|
251
|
+
const body = JSON.parse(text);
|
|
252
|
+
if (body.error?.message)
|
|
253
|
+
message = body.error.message;
|
|
254
|
+
code = body.error?.code;
|
|
255
|
+
details = body.error?.details;
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
message = text.trim() || message;
|
|
259
|
+
}
|
|
240
260
|
}
|
|
241
|
-
catch { /* non-JSON error body */ }
|
|
242
261
|
if (res.status === 404) {
|
|
243
262
|
message += " (check the integration id and that the integration is enabled)";
|
|
244
263
|
}
|
package/dist/protocol/types.d.ts
CHANGED
|
@@ -39,6 +39,10 @@ export interface IntegrationStatus {
|
|
|
39
39
|
label: string;
|
|
40
40
|
enabled: boolean;
|
|
41
41
|
}
|
|
42
|
+
/** Response of GET /balance (platform mode only). */
|
|
43
|
+
export interface BalanceInfo {
|
|
44
|
+
balance: number;
|
|
45
|
+
}
|
|
42
46
|
/** One directory entry from GET /integrations/workspace. */
|
|
43
47
|
export interface WorkspaceEntry {
|
|
44
48
|
name: string;
|
package/dist/ui/app.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { writeFile } from "node:fs/promises";
|
|
9
9
|
import { basename, join, resolve } from "node:path";
|
|
10
10
|
import { CombinedAutocompleteProvider, Box, Container, HStack, isViewportTUI, matchesKey, MouseRegion, ProcessTerminal, ScrollView, SelectList, Spacer, TuiAltScreen, VStack, visibleWidth, } from "@earendil-works/pi-tui";
|
|
11
|
+
import { IntegrationApiError } from "../protocol/client.js";
|
|
11
12
|
import { AgentRunner, usageFromSession } from "../agent/turn.js";
|
|
12
13
|
import { MODES, nextMode, stripModeMarker } from "../agent/modes.js";
|
|
13
14
|
import { createSystemPromptBuilder } from "../agent/prompt-builder.js";
|
|
@@ -484,6 +485,7 @@ export async function runTui(opts) {
|
|
|
484
485
|
{ name: "edit", description: "toggle auto/ask approval" },
|
|
485
486
|
{ name: "thinking", description: "set the thinking level" },
|
|
486
487
|
{ name: "model", description: "choose the model (new sessions)" },
|
|
488
|
+
{ name: "balance", description: "show the credit balance" },
|
|
487
489
|
{ name: "compact", description: "compact the session history" },
|
|
488
490
|
{ name: "stop", description: "force-stop the running turn" },
|
|
489
491
|
{ name: "reload", description: "reload context files and skills" },
|
|
@@ -628,6 +630,9 @@ export async function runTui(opts) {
|
|
|
628
630
|
case "model":
|
|
629
631
|
await showModelPicker();
|
|
630
632
|
break;
|
|
633
|
+
case "balance":
|
|
634
|
+
await showBalance();
|
|
635
|
+
break;
|
|
631
636
|
case "compact":
|
|
632
637
|
if (!runner.threadId)
|
|
633
638
|
addTranscript(new NoticeComponent("No active session.", "warn"));
|
|
@@ -668,6 +673,23 @@ export async function runTui(opts) {
|
|
|
668
673
|
addTranscript(new NoticeComponent(`Unknown command: /${name} (try /help)`, "warn"));
|
|
669
674
|
}
|
|
670
675
|
}
|
|
676
|
+
/** `/balance` — the platform credit balance (platform mode only). */
|
|
677
|
+
async function showBalance() {
|
|
678
|
+
try {
|
|
679
|
+
const { balance } = await opts.client.getBalance();
|
|
680
|
+
const amount = balance < 0 ? `-$${Math.abs(balance).toFixed(2)}` : `$${balance.toFixed(2)}`;
|
|
681
|
+
addTranscript(new NoticeComponent(`Credit balance: ${amount}`, "info"));
|
|
682
|
+
}
|
|
683
|
+
catch (err) {
|
|
684
|
+
// The server's 404 for a standalone deployment carries code
|
|
685
|
+
// `platform_only`; show it plainly instead of the generic 404 hint.
|
|
686
|
+
if (err instanceof IntegrationApiError && err.code === "platform_only") {
|
|
687
|
+
addTranscript(new NoticeComponent("Credit balance is only available on platform deployments.", "warn"));
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
addTranscript(new NoticeComponent(`Failed to fetch balance: ${err instanceof Error ? err.message : String(err)}`, "error"));
|
|
691
|
+
}
|
|
692
|
+
}
|
|
671
693
|
function setMode(mode) {
|
|
672
694
|
runner.setMode(mode);
|
|
673
695
|
editor.mode = mode;
|
package/dist/ui/help.js
CHANGED
|
@@ -24,7 +24,8 @@ const COMMANDS = [
|
|
|
24
24
|
["/cowork", "general tasks", "/edit", "AUTO/ASK"],
|
|
25
25
|
["/new", "new session", "/session [all]", "list · switch"],
|
|
26
26
|
["/thinking /model", "level · model", "/compact /stop", "compact · stop"],
|
|
27
|
-
["/
|
|
27
|
+
["/balance", "credit balance", "/reload /export", "reload · export"],
|
|
28
|
+
["/config /quit", "info · exit", "", ""],
|
|
28
29
|
];
|
|
29
30
|
const KEYS = [
|
|
30
31
|
["Tab", "plan/coding/cowork", "Shift+Tab", "AUTO/ASK"],
|