dexto 1.14.6 → 2.0.0-beta.1
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/agents/coding-agent/coding-agent.yml +0 -2
- package/dist/cli/agent-audit.d.ts +12 -0
- package/dist/cli/agent-audit.d.ts.map +1 -0
- package/dist/cli/agent-audit.js +52 -0
- package/dist/cli/auth/billing.d.ts +0 -6
- package/dist/cli/auth/billing.d.ts.map +1 -1
- package/dist/cli/auth/billing.js +0 -23
- package/dist/cli/auth/constants.d.ts +3 -31
- package/dist/cli/auth/constants.d.ts.map +1 -1
- package/dist/cli/auth/constants.js +9 -33
- package/dist/cli/auth/index.d.ts +2 -9
- package/dist/cli/auth/index.d.ts.map +1 -1
- package/dist/cli/auth/index.js +2 -7
- package/dist/cli/auth/sign-in-runtime.d.ts +12 -0
- package/dist/cli/auth/sign-in-runtime.d.ts.map +1 -0
- package/dist/cli/auth/sign-in-runtime.js +59 -0
- package/dist/cli/cloud/app-scopes.d.ts +4 -0
- package/dist/cli/cloud/app-scopes.d.ts.map +1 -0
- package/dist/cli/cloud/app-scopes.js +19 -0
- package/dist/cli/cloud/command.d.ts +107 -0
- package/dist/cli/cloud/command.d.ts.map +1 -0
- package/dist/cli/cloud/command.js +154 -0
- package/dist/cli/cloud/commands/account.d.ts +11 -0
- package/dist/cli/cloud/commands/account.d.ts.map +1 -0
- package/dist/cli/cloud/commands/account.js +129 -0
- package/dist/cli/cloud/commands/agents.d.ts +3 -0
- package/dist/cli/cloud/commands/agents.d.ts.map +1 -0
- package/dist/cli/cloud/commands/agents.js +526 -0
- package/dist/cli/cloud/commands/api.d.ts +3 -0
- package/dist/cli/cloud/commands/api.d.ts.map +1 -0
- package/dist/cli/cloud/commands/api.js +26 -0
- package/dist/cli/cloud/commands/app-files.d.ts +29 -0
- package/dist/cli/cloud/commands/app-files.d.ts.map +1 -0
- package/dist/cli/cloud/commands/app-files.js +72 -0
- package/dist/cli/cloud/commands/artifacts.d.ts +3 -0
- package/dist/cli/cloud/commands/artifacts.d.ts.map +1 -0
- package/dist/cli/cloud/commands/artifacts.js +267 -0
- package/dist/cli/cloud/commands/automations.d.ts +3 -0
- package/dist/cli/cloud/commands/automations.d.ts.map +1 -0
- package/dist/cli/cloud/commands/automations.js +233 -0
- package/dist/cli/cloud/commands/chats.d.ts +3 -0
- package/dist/cli/cloud/commands/chats.d.ts.map +1 -0
- package/dist/cli/cloud/commands/chats.js +204 -0
- package/dist/cli/cloud/commands/data-deletions.d.ts +3 -0
- package/dist/cli/cloud/commands/data-deletions.d.ts.map +1 -0
- package/dist/cli/cloud/commands/data-deletions.js +55 -0
- package/dist/cli/cloud/commands/deploys.d.ts +10 -0
- package/dist/cli/cloud/commands/deploys.d.ts.map +1 -0
- package/dist/cli/cloud/commands/deploys.js +225 -0
- package/dist/cli/cloud/commands/drive.d.ts +12 -0
- package/dist/cli/cloud/commands/drive.d.ts.map +1 -0
- package/dist/cli/cloud/commands/drive.js +321 -0
- package/dist/cli/cloud/commands/files.d.ts +24 -0
- package/dist/cli/cloud/commands/files.d.ts.map +1 -0
- package/dist/cli/cloud/commands/files.js +284 -0
- package/dist/cli/cloud/commands/find.d.ts +3 -0
- package/dist/cli/cloud/commands/find.d.ts.map +1 -0
- package/dist/cli/cloud/commands/find.js +63 -0
- package/dist/cli/cloud/commands/models.d.ts +3 -0
- package/dist/cli/cloud/commands/models.d.ts.map +1 -0
- package/dist/cli/cloud/commands/models.js +250 -0
- package/dist/cli/cloud/commands/profile.d.ts +3 -0
- package/dist/cli/cloud/commands/profile.d.ts.map +1 -0
- package/dist/cli/cloud/commands/profile.js +120 -0
- package/dist/cli/cloud/commands/projects.d.ts +5 -0
- package/dist/cli/cloud/commands/projects.d.ts.map +1 -0
- package/dist/cli/cloud/commands/projects.js +66 -0
- package/dist/cli/cloud/commands/publish.d.ts +3 -0
- package/dist/cli/cloud/commands/publish.d.ts.map +1 -0
- package/dist/cli/cloud/commands/publish.js +139 -0
- package/dist/cli/cloud/commands/sandboxes.d.ts +3 -0
- package/dist/cli/cloud/commands/sandboxes.d.ts.map +1 -0
- package/dist/cli/cloud/commands/sandboxes.js +266 -0
- package/dist/cli/cloud/commands/secrets.d.ts +3 -0
- package/dist/cli/cloud/commands/secrets.d.ts.map +1 -0
- package/dist/cli/cloud/commands/secrets.js +111 -0
- package/dist/cli/cloud/commands/skills.d.ts +3 -0
- package/dist/cli/cloud/commands/skills.d.ts.map +1 -0
- package/dist/cli/cloud/commands/skills.js +203 -0
- package/dist/cli/cloud/commands/traces.d.ts +3 -0
- package/dist/cli/cloud/commands/traces.d.ts.map +1 -0
- package/dist/cli/cloud/commands/traces.js +142 -0
- package/dist/cli/cloud/commands/web.d.ts +3 -0
- package/dist/cli/cloud/commands/web.d.ts.map +1 -0
- package/dist/cli/cloud/commands/web.js +53 -0
- package/dist/cli/cloud/commands/workspace-apps.d.ts +58 -0
- package/dist/cli/cloud/commands/workspace-apps.d.ts.map +1 -0
- package/dist/cli/cloud/commands/workspace-apps.js +657 -0
- package/dist/cli/cloud/commands/workspace.d.ts +36 -0
- package/dist/cli/cloud/commands/workspace.d.ts.map +1 -0
- package/dist/cli/cloud/commands/workspace.js +281 -0
- package/dist/cli/cloud/connection.d.ts +33 -0
- package/dist/cli/cloud/connection.d.ts.map +1 -0
- package/dist/cli/cloud/connection.js +38 -0
- package/dist/cli/cloud/events.d.ts +63 -0
- package/dist/cli/cloud/events.d.ts.map +1 -0
- package/dist/cli/cloud/events.js +72 -0
- package/dist/cli/cloud/host.d.ts +9 -0
- package/dist/cli/cloud/host.d.ts.map +1 -0
- package/dist/cli/cloud/host.js +109 -0
- package/dist/cli/cloud/output.d.ts +34 -0
- package/dist/cli/cloud/output.d.ts.map +1 -0
- package/dist/cli/cloud/output.js +77 -0
- package/dist/cli/cloud/run.d.ts +26 -0
- package/dist/cli/cloud/run.d.ts.map +1 -0
- package/dist/cli/cloud/run.js +444 -0
- package/dist/cli/cloud/runtime.d.ts +33 -0
- package/dist/cli/cloud/runtime.d.ts.map +1 -0
- package/dist/cli/cloud/runtime.js +86 -0
- package/dist/cli/cloud/tar.d.ts +9 -0
- package/dist/cli/cloud/tar.d.ts.map +1 -0
- package/dist/cli/cloud/tar.js +69 -0
- package/dist/cli/cloud/transfer.d.ts +13 -0
- package/dist/cli/cloud/transfer.d.ts.map +1 -0
- package/dist/cli/cloud/transfer.js +36 -0
- package/dist/cli/cloud/v1.d.ts +20 -0
- package/dist/cli/cloud/v1.d.ts.map +1 -0
- package/dist/cli/cloud/v1.js +66 -0
- package/dist/cli/cloud/zip.d.ts +8 -0
- package/dist/cli/cloud/zip.d.ts.map +1 -0
- package/dist/cli/cloud/zip.js +66 -0
- package/dist/cli/commands/auth/sign-in-commands.d.ts +62 -0
- package/dist/cli/commands/auth/sign-in-commands.d.ts.map +1 -0
- package/dist/cli/commands/auth/sign-in-commands.js +248 -0
- package/dist/cli/commands/auth/sign-in-context.d.ts +16 -0
- package/dist/cli/commands/auth/sign-in-context.d.ts.map +1 -0
- package/dist/cli/commands/auth/sign-in-context.js +68 -0
- package/dist/cli/commands/cloud/register.d.ts +5 -0
- package/dist/cli/commands/cloud/register.d.ts.map +1 -1
- package/dist/cli/commands/cloud/register.js +44 -24
- package/dist/cli/commands/create-app.js +5 -6
- package/dist/cli/commands/create-image.d.ts.map +1 -1
- package/dist/cli/commands/create-image.js +9 -10
- package/dist/cli/commands/index.d.ts +0 -2
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +0 -2
- package/dist/cli/commands/init.d.ts +0 -2
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +5 -26
- package/dist/cli/commands/run/headless.d.ts.map +1 -1
- package/dist/cli/commands/run/headless.js +57 -2
- package/dist/cli/commands/run/output.d.ts +29 -10
- package/dist/cli/commands/run/output.d.ts.map +1 -1
- package/dist/cli/commands/run/output.js +44 -22
- package/dist/cli/commands/run/register.d.ts.map +1 -1
- package/dist/cli/commands/run/register.js +21 -9
- package/dist/cli/commands/run/step-log.d.ts +11 -0
- package/dist/cli/commands/run/step-log.d.ts.map +1 -0
- package/dist/cli/commands/run/step-log.js +42 -0
- package/dist/cli/commands/session/register.d.ts.map +1 -1
- package/dist/cli/commands/session/register.js +51 -21
- package/dist/cli/commands/session-commands.js +1 -1
- package/dist/cli/commands/setup.js +17 -14
- package/dist/cli/failure.d.ts +29 -0
- package/dist/cli/failure.d.ts.map +1 -0
- package/dist/cli/failure.js +31 -0
- package/dist/cli/help-json.d.ts +22 -0
- package/dist/cli/help-json.d.ts.map +1 -0
- package/dist/cli/help-json.js +20 -0
- package/dist/cli/import/claude-code.d.ts +10 -0
- package/dist/cli/import/claude-code.d.ts.map +1 -0
- package/dist/cli/import/claude-code.js +131 -0
- package/dist/cli/import/codex.d.ts +27 -0
- package/dist/cli/import/codex.d.ts.map +1 -0
- package/dist/cli/import/codex.js +148 -0
- package/dist/cli/import/git.d.ts +19 -0
- package/dist/cli/import/git.d.ts.map +1 -0
- package/dist/cli/import/git.js +95 -0
- package/dist/cli/import/local-chats.d.ts +28 -0
- package/dist/cli/import/local-chats.d.ts.map +1 -0
- package/dist/cli/import/local-chats.js +129 -0
- package/dist/cli/import/redaction.d.ts +37 -0
- package/dist/cli/import/redaction.d.ts.map +1 -0
- package/dist/cli/import/redaction.js +148 -0
- package/dist/cli/import/test-utils.d.ts +16 -0
- package/dist/cli/import/test-utils.d.ts.map +1 -0
- package/dist/cli/import/test-utils.js +223 -0
- package/dist/cli/import/transcript.d.ts +75 -0
- package/dist/cli/import/transcript.d.ts.map +1 -0
- package/dist/cli/import/transcript.js +123 -0
- package/dist/cli/interaction.d.ts +18 -0
- package/dist/cli/interaction.d.ts.map +1 -0
- package/dist/cli/interaction.js +30 -0
- package/dist/cli/modes/cli.d.ts.map +1 -1
- package/dist/cli/modes/cli.js +42 -9
- package/dist/cli/modes/server.js +8 -8
- package/dist/cli/modes/web.js +3 -3
- package/dist/cli/output.d.ts +9 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +6 -0
- package/dist/cli/utils/dexto-auth-check.d.ts +1 -1
- package/dist/cli/utils/dexto-auth-check.d.ts.map +1 -1
- package/dist/cli/utils/dexto-auth-check.js +4 -5
- package/dist/cli/utils/dexto-setup.d.ts +4 -5
- package/dist/cli/utils/dexto-setup.d.ts.map +1 -1
- package/dist/cli/utils/dexto-setup.js +17 -14
- package/dist/cli/utils/provider-setup.js +1 -1
- package/dist/cli/utils/scaffolding-utils.d.ts +9 -3
- package/dist/cli/utils/scaffolding-utils.d.ts.map +1 -1
- package/dist/cli/utils/scaffolding-utils.js +48 -40
- package/dist/cli/utils/version-check.d.ts.map +1 -1
- package/dist/cli/utils/version-check.js +2 -1
- package/dist/index-main.js +44 -65
- package/dist/webui/assets/index-D9xiOs62.js +1649 -0
- package/dist/webui/index.html +1 -1
- package/package.json +15 -14
- package/dist/cli/auth/api-client.d.ts +0 -125
- package/dist/cli/auth/api-client.d.ts.map +0 -1
- package/dist/cli/auth/api-client.js +0 -585
- package/dist/cli/auth/device.d.ts +0 -14
- package/dist/cli/auth/device.d.ts.map +0 -1
- package/dist/cli/auth/device.js +0 -84
- package/dist/cli/auth/dexto-api-key.d.ts +0 -34
- package/dist/cli/auth/dexto-api-key.d.ts.map +0 -1
- package/dist/cli/auth/dexto-api-key.js +0 -160
- package/dist/cli/auth/login-persistence.d.ts +0 -15
- package/dist/cli/auth/login-persistence.d.ts.map +0 -1
- package/dist/cli/auth/login-persistence.js +0 -72
- package/dist/cli/auth/oauth.d.ts +0 -39
- package/dist/cli/auth/oauth.d.ts.map +0 -1
- package/dist/cli/auth/oauth.js +0 -434
- package/dist/cli/auth/service.d.ts +0 -24
- package/dist/cli/auth/service.d.ts.map +0 -1
- package/dist/cli/auth/service.js +0 -161
- package/dist/cli/auth/types.d.ts +0 -11
- package/dist/cli/auth/types.d.ts.map +0 -1
- package/dist/cli/auth/types.js +0 -1
- package/dist/cli/cloud-chat.d.ts +0 -18
- package/dist/cli/cloud-chat.d.ts.map +0 -1
- package/dist/cli/cloud-chat.js +0 -734
- package/dist/cli/commands/auth/index.d.ts +0 -4
- package/dist/cli/commands/auth/index.d.ts.map +0 -1
- package/dist/cli/commands/auth/index.js +0 -4
- package/dist/cli/commands/auth/login.d.ts +0 -12
- package/dist/cli/commands/auth/login.d.ts.map +0 -1
- package/dist/cli/commands/auth/login.js +0 -153
- package/dist/cli/commands/auth/logout.d.ts +0 -5
- package/dist/cli/commands/auth/logout.d.ts.map +0 -1
- package/dist/cli/commands/auth/logout.js +0 -81
- package/dist/cli/commands/auth/register.d.ts +0 -3
- package/dist/cli/commands/auth/register.d.ts.map +0 -1
- package/dist/cli/commands/auth/register.js +0 -96
- package/dist/cli/commands/auth/status.d.ts +0 -2
- package/dist/cli/commands/auth/status.d.ts.map +0 -1
- package/dist/cli/commands/auth/status.js +0 -22
- package/dist/cli/commands/billing/index.d.ts +0 -2
- package/dist/cli/commands/billing/index.d.ts.map +0 -1
- package/dist/cli/commands/billing/index.js +0 -2
- package/dist/cli/commands/billing/register.d.ts +0 -3
- package/dist/cli/commands/billing/register.d.ts.map +0 -1
- package/dist/cli/commands/billing/register.js +0 -20
- package/dist/cli/commands/billing/status.d.ts +0 -8
- package/dist/cli/commands/billing/status.d.ts.map +0 -1
- package/dist/cli/commands/billing/status.js +0 -71
- package/dist/cli/commands/cloud/discovery.d.ts +0 -17
- package/dist/cli/commands/cloud/discovery.d.ts.map +0 -1
- package/dist/cli/commands/cloud/discovery.js +0 -88
- package/dist/cli/commands/deploy/client.d.ts +0 -113
- package/dist/cli/commands/deploy/client.d.ts.map +0 -1
- package/dist/cli/commands/deploy/client.js +0 -519
- package/dist/cli/commands/deploy/config.d.ts +0 -37
- package/dist/cli/commands/deploy/config.d.ts.map +0 -1
- package/dist/cli/commands/deploy/config.js +0 -144
- package/dist/cli/commands/deploy/entry-agent.d.ts +0 -3
- package/dist/cli/commands/deploy/entry-agent.d.ts.map +0 -1
- package/dist/cli/commands/deploy/entry-agent.js +0 -70
- package/dist/cli/commands/deploy/index.d.ts +0 -12
- package/dist/cli/commands/deploy/index.d.ts.map +0 -1
- package/dist/cli/commands/deploy/index.js +0 -370
- package/dist/cli/commands/deploy/links.d.ts +0 -3
- package/dist/cli/commands/deploy/links.d.ts.map +0 -1
- package/dist/cli/commands/deploy/links.js +0 -53
- package/dist/cli/commands/deploy/register.d.ts +0 -6
- package/dist/cli/commands/deploy/register.d.ts.map +0 -1
- package/dist/cli/commands/deploy/register.js +0 -128
- package/dist/cli/commands/deploy/snapshot.d.ts +0 -12
- package/dist/cli/commands/deploy/snapshot.d.ts.map +0 -1
- package/dist/cli/commands/deploy/snapshot.js +0 -76
- package/dist/cli/commands/deploy/state.d.ts +0 -13
- package/dist/cli/commands/deploy/state.d.ts.map +0 -1
- package/dist/cli/commands/deploy/state.js +0 -122
- package/dist/cli/commands/span/register.d.ts +0 -6
- package/dist/cli/commands/span/register.d.ts.map +0 -1
- package/dist/cli/commands/span/register.js +0 -25
- package/dist/cli/commands/trace/client.d.ts +0 -98
- package/dist/cli/commands/trace/client.d.ts.map +0 -1
- package/dist/cli/commands/trace/client.js +0 -150
- package/dist/cli/commands/trace/format.d.ts +0 -5
- package/dist/cli/commands/trace/format.d.ts.map +0 -1
- package/dist/cli/commands/trace/format.js +0 -58
- package/dist/cli/commands/trace/index.d.ts +0 -21
- package/dist/cli/commands/trace/index.d.ts.map +0 -1
- package/dist/cli/commands/trace/index.js +0 -49
- package/dist/cli/commands/trace/register.d.ts +0 -6
- package/dist/cli/commands/trace/register.d.ts.map +0 -1
- package/dist/cli/commands/trace/register.js +0 -71
- package/dist/webui/assets/index-DEfRFmFT.js +0 -1667
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/cli/cloud/commands/api.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoD,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAgC/F,eAAO,MAAM,WAAW,EAAE,SAAS,OAAO,EAAU,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// `cloud api`: call any /v1 operation with the sign-in, for what no command covers yet.
|
|
2
|
+
import { argument, BODY_OPTIONS, readJsonBody, UsageError } from '../command.js';
|
|
3
|
+
import { fetchV1, v1Failure } from '../v1.js';
|
|
4
|
+
const METHODS = new Set(['DELETE', 'GET', 'PATCH', 'POST', 'PUT']);
|
|
5
|
+
const api = {
|
|
6
|
+
arguments: '<method> <path>',
|
|
7
|
+
options: BODY_OPTIONS,
|
|
8
|
+
path: ['cloud', 'api'],
|
|
9
|
+
summary: 'Call a /v1 path, such as: dexto cloud api GET /v1/agents. Prints the response body.',
|
|
10
|
+
async run(context, input) {
|
|
11
|
+
const method = argument(input, 0, 'method').toUpperCase();
|
|
12
|
+
if (!METHODS.has(method))
|
|
13
|
+
throw new UsageError(`Unknown method ${method}.`);
|
|
14
|
+
const body = await readJsonBody(context, input);
|
|
15
|
+
const response = await fetchV1(context, method, argument(input, 1, 'path'), body === null ? null : JSON.stringify(body));
|
|
16
|
+
const text = await response.text();
|
|
17
|
+
if (response.headers.get('content-type')?.includes('application/json') === true)
|
|
18
|
+
context.runtime.writeOutput(`${JSON.stringify(JSON.parse(text), null, 2)}\n`);
|
|
19
|
+
else
|
|
20
|
+
context.runtime.writeOutput(text.endsWith('\n') || text.length === 0 ? text : `${text}\n`);
|
|
21
|
+
if (!response.ok)
|
|
22
|
+
throw v1Failure(context, response.status, text);
|
|
23
|
+
return 0;
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
export const apiCommands = [api];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type CommandContext } from '../command.js';
|
|
2
|
+
/** The JSON Schema `format` of a string that takes a Drive file, as `drive:<id>`. */
|
|
3
|
+
export declare const DRIVE_FILE_FORMAT = "dexto-drive-file";
|
|
4
|
+
/**
|
|
5
|
+
* How a field takes files: as the reference itself, or as an object whose `property` is the
|
|
6
|
+
* reference, with the file's `name` and `mimeType` beside it where the object has them. `list`
|
|
7
|
+
* says the field takes several.
|
|
8
|
+
*/
|
|
9
|
+
export interface FileField {
|
|
10
|
+
readonly list: boolean;
|
|
11
|
+
readonly slot: {
|
|
12
|
+
readonly kind: 'reference';
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: 'object';
|
|
15
|
+
readonly mimeType: boolean;
|
|
16
|
+
readonly name: boolean;
|
|
17
|
+
readonly property: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** A field's file slot, from its schema: a string of the Drive file format, alone or in an object. */
|
|
21
|
+
export declare function fileFieldOf(property: Record<string, unknown>): FileField | null;
|
|
22
|
+
/**
|
|
23
|
+
* The field's values with each local path uploaded into the app's Drive folder: a link (`https:`,
|
|
24
|
+
* `drive:`) is kept as it is, and a value given as JSON is left alone.
|
|
25
|
+
*/
|
|
26
|
+
export declare function attachFiles(context: CommandContext, appId: string, field: FileField, values: readonly unknown[]): Promise<unknown[]>;
|
|
27
|
+
/** A value naming a local file to upload, rather than a link or JSON given as it is. */
|
|
28
|
+
export declare function isLocalFile(value: unknown): boolean;
|
|
29
|
+
//# sourceMappingURL=app-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-files.d.ts","sourceRoot":"","sources":["../../../../src/cli/cloud/commands/app-files.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAGlE,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AAEpD;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EACP;QAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;KAAE,GAC9B;QACI,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;QACxB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;QAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;QACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC7B,CAAC;CACX;AAED,sGAAsG;AACtG,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAI/E;AAwBD;;;GAGG;AACH,wBAAsB,WAAW,CAC7B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,SAAS,OAAO,EAAE,GAC3B,OAAO,CAAC,OAAO,EAAE,CAAC,CAwBpB;AAKD,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEnD"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Local files given for an App action's file fields: uploaded to the app's Drive folder, then referred to.
|
|
2
|
+
import { isJsonObject } from '../command.js';
|
|
3
|
+
import { putAppFile } from './drive.js';
|
|
4
|
+
/** The JSON Schema `format` of a string that takes a Drive file, as `drive:<id>`. */
|
|
5
|
+
export const DRIVE_FILE_FORMAT = 'dexto-drive-file';
|
|
6
|
+
/** A field's file slot, from its schema: a string of the Drive file format, alone or in an object. */
|
|
7
|
+
export function fileFieldOf(property) {
|
|
8
|
+
const items = property.type === 'array' && isJsonObject(property.items) ? property.items : null;
|
|
9
|
+
const slot = slotOf(items ?? property);
|
|
10
|
+
return slot === null ? null : { list: items !== null, slot };
|
|
11
|
+
}
|
|
12
|
+
function slotOf(schema) {
|
|
13
|
+
if (takesFile(schema))
|
|
14
|
+
return { kind: 'reference' };
|
|
15
|
+
if (schema.type !== 'object' || !isJsonObject(schema.properties))
|
|
16
|
+
return null;
|
|
17
|
+
const { properties } = schema;
|
|
18
|
+
const property = Object.keys(properties).find((name) => {
|
|
19
|
+
const each = properties[name];
|
|
20
|
+
return isJsonObject(each) && takesFile(each);
|
|
21
|
+
});
|
|
22
|
+
return property === undefined
|
|
23
|
+
? null
|
|
24
|
+
: {
|
|
25
|
+
kind: 'object',
|
|
26
|
+
mimeType: isJsonObject(properties.mimeType),
|
|
27
|
+
name: isJsonObject(properties.name),
|
|
28
|
+
property,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function takesFile(schema) {
|
|
32
|
+
return schema.type === 'string' && schema.format === DRIVE_FILE_FORMAT;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The field's values with each local path uploaded into the app's Drive folder: a link (`https:`,
|
|
36
|
+
* `drive:`) is kept as it is, and a value given as JSON is left alone.
|
|
37
|
+
*/
|
|
38
|
+
export async function attachFiles(context, appId, field, values) {
|
|
39
|
+
const attached = [];
|
|
40
|
+
for (const value of values) {
|
|
41
|
+
if (typeof value !== 'string') {
|
|
42
|
+
attached.push(value);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const file = LINK.test(value)
|
|
46
|
+
? { mimeType: null, name: null, uri: value }
|
|
47
|
+
: await uploadAppFile(context, appId, value);
|
|
48
|
+
const { slot } = field;
|
|
49
|
+
attached.push(slot.kind === 'reference'
|
|
50
|
+
? file.uri
|
|
51
|
+
: {
|
|
52
|
+
[slot.property]: file.uri,
|
|
53
|
+
...(slot.name && file.name !== null ? { name: file.name } : {}),
|
|
54
|
+
...(slot.mimeType && file.mimeType !== null
|
|
55
|
+
? { mimeType: file.mimeType }
|
|
56
|
+
: {}),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return attached;
|
|
60
|
+
}
|
|
61
|
+
/** A value that already refers to a file, rather than naming a local one. */
|
|
62
|
+
const LINK = /^(?:https?:\/\/|drive:)/iu;
|
|
63
|
+
/** A value naming a local file to upload, rather than a link or JSON given as it is. */
|
|
64
|
+
export function isLocalFile(value) {
|
|
65
|
+
return typeof value === 'string' && !LINK.test(value);
|
|
66
|
+
}
|
|
67
|
+
async function uploadAppFile(context, appId, localPath) {
|
|
68
|
+
const file = await putAppFile(context, localPath, appId);
|
|
69
|
+
const uri = `drive:${file.id}`;
|
|
70
|
+
context.output.note(`Uploaded ${localPath} to your Drive as ${uri}.`);
|
|
71
|
+
return { mimeType: file.mimeType, name: file.name, uri };
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../../../src/cli/cloud/commands/artifacts.ts"],"names":[],"mappings":"AASA,OAAO,EAWH,KAAK,OAAO,EAIf,MAAM,eAAe,CAAC;AAyUvB,eAAO,MAAM,gBAAgB,EAAE,SAAS,OAAO,EAAwC,CAAC"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// `workspace artifacts`: the person's saved HTML Artifacts, over Dexto's typed Artifacts tools.
|
|
2
|
+
import { CommandFailure } from '../../failure.js';
|
|
3
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { argument, choiceOption, flag, integerOption, listOption, PAGE_OPTIONS, requiredOption, stringOption, UsageError, YES_OPTION, } from '../command.js';
|
|
7
|
+
import { requireLoginScopes } from './deploys.js';
|
|
8
|
+
import { agreeToCall, listWorkspaceTools, queryWorkspaceTool, toolCallLevel } from './workspace.js';
|
|
9
|
+
/** What Dexto keeps of one Artifact's HTML. */
|
|
10
|
+
const MAX_HTML_BYTES = 524_288;
|
|
11
|
+
const KINDS = [
|
|
12
|
+
'document',
|
|
13
|
+
'plan',
|
|
14
|
+
'mockup',
|
|
15
|
+
'prototype',
|
|
16
|
+
'slide-deck',
|
|
17
|
+
'visualization',
|
|
18
|
+
'interactive',
|
|
19
|
+
'other',
|
|
20
|
+
];
|
|
21
|
+
const SURFACES = ['inline', 'panel', 'fullscreen'];
|
|
22
|
+
const RENDERERS = ['html', 'reveal'];
|
|
23
|
+
const VISIBILITIES = ['private', 'org-shared', 'link-shared'];
|
|
24
|
+
const SummarySchema = z.object({
|
|
25
|
+
artifactId: z.string(),
|
|
26
|
+
kind: z.string(),
|
|
27
|
+
preferredSurface: z.string(),
|
|
28
|
+
summary: z.string(),
|
|
29
|
+
title: z.string(),
|
|
30
|
+
updatedAt: z.string(),
|
|
31
|
+
});
|
|
32
|
+
const ListSchema = z.object({ artifacts: z.array(SummarySchema), next: z.string().nullable() });
|
|
33
|
+
const ArtifactSchema = SummarySchema.extend({
|
|
34
|
+
html: z.string(),
|
|
35
|
+
renderer: z.string().nullable(),
|
|
36
|
+
});
|
|
37
|
+
const GetSchema = z.object({ artifact: ArtifactSchema.nullable() });
|
|
38
|
+
const SavedSchema = z.object({
|
|
39
|
+
artifact: z.object({ artifactId: z.string(), title: z.string() }),
|
|
40
|
+
});
|
|
41
|
+
const SharedSchema = z.object({ url: z.string().nullable(), visibility: z.string() });
|
|
42
|
+
const COLUMNS = [
|
|
43
|
+
{ header: 'id', value: (artifact) => artifact.artifactId },
|
|
44
|
+
{ header: 'title', value: (artifact) => artifact.title },
|
|
45
|
+
{ header: 'kind', value: (artifact) => artifact.kind },
|
|
46
|
+
{ header: 'updated', value: (artifact) => artifact.updatedAt },
|
|
47
|
+
];
|
|
48
|
+
const CONTENT_OPTIONS = {
|
|
49
|
+
kind: { description: `What it is: ${KINDS.join(', ')}.`, type: 'string' },
|
|
50
|
+
renderer: {
|
|
51
|
+
description: 'html, or reveal for a slide-deck written for reveal.js.',
|
|
52
|
+
type: 'string',
|
|
53
|
+
},
|
|
54
|
+
summary: { description: 'One or two lines on what it is.', type: 'string' },
|
|
55
|
+
surface: {
|
|
56
|
+
description: `Where it opens: ${SURFACES.join(', ')}.`,
|
|
57
|
+
type: 'string',
|
|
58
|
+
},
|
|
59
|
+
tag: { description: 'A tag; repeat for more.', multiple: true, type: 'string' },
|
|
60
|
+
title: { description: "The Artifact's title.", type: 'string' },
|
|
61
|
+
};
|
|
62
|
+
const DRY_RUN_OPTION = {
|
|
63
|
+
'dry-run': {
|
|
64
|
+
description: 'Check the input and show the call, without making it.',
|
|
65
|
+
type: 'boolean',
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
const list = {
|
|
69
|
+
options: PAGE_OPTIONS,
|
|
70
|
+
path: ['workspace', 'artifacts', 'list'],
|
|
71
|
+
summary: 'List your saved Artifacts, newest first.',
|
|
72
|
+
async run(context, input) {
|
|
73
|
+
await requireLoginScopes(context, ['apps:read']);
|
|
74
|
+
const after = stringOption(input, 'after');
|
|
75
|
+
const limit = integerOption(input, 'limit');
|
|
76
|
+
const page = ListSchema.parse(await queryWorkspaceTool(context, 'dexto_artifacts_list', {
|
|
77
|
+
...(after === undefined ? {} : { cursor: after }),
|
|
78
|
+
...(limit === undefined ? {} : { limit }),
|
|
79
|
+
}));
|
|
80
|
+
context.output.list({ data: page.artifacts, has_more: page.next !== null, next_after: page.next }, COLUMNS);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
const get = {
|
|
84
|
+
arguments: '<artifact_id>',
|
|
85
|
+
options: {
|
|
86
|
+
out: {
|
|
87
|
+
description: 'Write the HTML to this file, and show the rest without it.',
|
|
88
|
+
type: 'string',
|
|
89
|
+
valueName: 'PATH',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
path: ['workspace', 'artifacts', 'get'],
|
|
93
|
+
summary: 'Show one Artifact, with its HTML or with --out writing the HTML to a file.',
|
|
94
|
+
async run(context, input) {
|
|
95
|
+
await requireLoginScopes(context, ['apps:read']);
|
|
96
|
+
const artifact = await readArtifact(context, argument(input, 0, 'artifact_id'));
|
|
97
|
+
const out = stringOption(input, 'out');
|
|
98
|
+
if (out === undefined)
|
|
99
|
+
return context.output.record(artifact);
|
|
100
|
+
await writeFile(out, artifact.html, 'utf8');
|
|
101
|
+
const { html: _html, ...rest } = artifact;
|
|
102
|
+
context.output.record({ ...rest, htmlPath: path.resolve(out) });
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
const create = {
|
|
106
|
+
arguments: '<file>',
|
|
107
|
+
options: {
|
|
108
|
+
...CONTENT_OPTIONS,
|
|
109
|
+
collection: {
|
|
110
|
+
description: 'A collection to put it in, by id; repeat for more.',
|
|
111
|
+
multiple: true,
|
|
112
|
+
type: 'string',
|
|
113
|
+
},
|
|
114
|
+
'idempotency-key': {
|
|
115
|
+
description: 'Any string unique to this Artifact: running again with the same key returns the first one instead of a copy.',
|
|
116
|
+
type: 'string',
|
|
117
|
+
valueName: 'KEY',
|
|
118
|
+
},
|
|
119
|
+
...DRY_RUN_OPTION,
|
|
120
|
+
...YES_OPTION,
|
|
121
|
+
},
|
|
122
|
+
path: ['workspace', 'artifacts', 'create'],
|
|
123
|
+
summary: "Save an HTML file (or - for stdin) as an Artifact in your library. Its title defaults to the file's name.",
|
|
124
|
+
async run(context, input) {
|
|
125
|
+
await requireLoginScopes(context, ['apps:execute']);
|
|
126
|
+
const file = argument(input, 0, 'file');
|
|
127
|
+
const title = stringOption(input, 'title') ??
|
|
128
|
+
(file === '-' ? requiredOption(input, 'title') : path.parse(file).name);
|
|
129
|
+
const key = stringOption(input, 'idempotency-key');
|
|
130
|
+
const collections = listOption(input, 'collection');
|
|
131
|
+
const call = {
|
|
132
|
+
...contentFields(input, {
|
|
133
|
+
kind: 'document',
|
|
134
|
+
preferredSurface: 'panel',
|
|
135
|
+
renderer: 'html',
|
|
136
|
+
summary: '',
|
|
137
|
+
title,
|
|
138
|
+
}),
|
|
139
|
+
html: await readHtml(context, file),
|
|
140
|
+
...(collections.length === 0 ? {} : { collectionIds: collections }),
|
|
141
|
+
...(key === undefined ? {} : { idempotencyKey: key }),
|
|
142
|
+
};
|
|
143
|
+
const saved = await save(context, input, 'dexto_artifacts_create', call, `Save ${title}`);
|
|
144
|
+
if (saved === null)
|
|
145
|
+
return;
|
|
146
|
+
context.output.result(saved.value, `Saved ${saved.artifact.title} as Artifact ${saved.artifact.artifactId}.`);
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
const replace = {
|
|
150
|
+
arguments: '<artifact_id> <file>',
|
|
151
|
+
options: { ...CONTENT_OPTIONS, ...DRY_RUN_OPTION, ...YES_OPTION },
|
|
152
|
+
path: ['workspace', 'artifacts', 'replace'],
|
|
153
|
+
summary: 'Replace an Artifact with an HTML file (or - for stdin), keeping its id; it keeps its title, kind, summary, surface and renderer unless you give new ones.',
|
|
154
|
+
async run(context, input) {
|
|
155
|
+
await requireLoginScopes(context, ['apps:read', 'apps:execute']);
|
|
156
|
+
const artifactId = argument(input, 0, 'artifact_id');
|
|
157
|
+
const html = await readHtml(context, argument(input, 1, 'file'));
|
|
158
|
+
const current = await readArtifact(context, artifactId);
|
|
159
|
+
const call = {
|
|
160
|
+
artifactId,
|
|
161
|
+
...contentFields(input, {
|
|
162
|
+
kind: current.kind,
|
|
163
|
+
preferredSurface: current.preferredSurface,
|
|
164
|
+
renderer: current.renderer ?? 'html',
|
|
165
|
+
summary: current.summary,
|
|
166
|
+
title: current.title,
|
|
167
|
+
}),
|
|
168
|
+
html,
|
|
169
|
+
};
|
|
170
|
+
const saved = await save(context, input, 'dexto_artifacts_replace', call, `Replace Artifact ${artifactId}`);
|
|
171
|
+
if (saved === null)
|
|
172
|
+
return;
|
|
173
|
+
context.output.result(saved.value, `Replaced Artifact ${artifactId}.`);
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
const share = {
|
|
177
|
+
arguments: '<artifact_id>',
|
|
178
|
+
options: {
|
|
179
|
+
visibility: {
|
|
180
|
+
description: 'private (only you), org-shared (your organization) or link-shared (anyone with the link).',
|
|
181
|
+
type: 'string',
|
|
182
|
+
},
|
|
183
|
+
...DRY_RUN_OPTION,
|
|
184
|
+
...YES_OPTION,
|
|
185
|
+
},
|
|
186
|
+
path: ['workspace', 'artifacts', 'share'],
|
|
187
|
+
summary: 'Change who can open an Artifact: only you, your organization, or anyone with its link.',
|
|
188
|
+
async run(context, input) {
|
|
189
|
+
await requireLoginScopes(context, ['apps:execute']);
|
|
190
|
+
const visibility = choiceOption(input, 'visibility', VISIBILITIES);
|
|
191
|
+
if (visibility === undefined)
|
|
192
|
+
throw new UsageError('--visibility is required.');
|
|
193
|
+
const artifactId = argument(input, 0, 'artifact_id');
|
|
194
|
+
const call = { artifactId, visibility };
|
|
195
|
+
const tool = await requireTool(context, 'dexto_artifacts_share');
|
|
196
|
+
if (flag(input, 'dry-run'))
|
|
197
|
+
return dryRun(context, 'dexto_artifacts_share', call);
|
|
198
|
+
const agreed = await agreeToCall(context, {
|
|
199
|
+
level: toolCallLevel(tool, call),
|
|
200
|
+
schema: tool.inputSchema,
|
|
201
|
+
title: `Make Artifact ${artifactId} ${visibility}`,
|
|
202
|
+
}, flag(input, 'yes'));
|
|
203
|
+
const value = await queryWorkspaceTool(context, 'dexto_artifacts_share', {
|
|
204
|
+
...call,
|
|
205
|
+
...agreed,
|
|
206
|
+
});
|
|
207
|
+
const shared = SharedSchema.parse(value);
|
|
208
|
+
context.output.result(value, shared.url === null
|
|
209
|
+
? `Artifact ${artifactId} is now ${shared.visibility}.`
|
|
210
|
+
: `Artifact ${artifactId} is now ${shared.visibility}: ${shared.url}`);
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
async function readArtifact(context, artifactId) {
|
|
214
|
+
const { artifact } = GetSchema.parse(await queryWorkspaceTool(context, 'dexto_artifacts_get', { artifactId }));
|
|
215
|
+
if (artifact === null)
|
|
216
|
+
throw new CommandFailure('not_found', `There is no Artifact ${artifactId}.`, null);
|
|
217
|
+
return artifact;
|
|
218
|
+
}
|
|
219
|
+
/** The HTML of a file, or of stdin for -, checked against what an Artifact holds. */
|
|
220
|
+
async function readHtml(context, file) {
|
|
221
|
+
const html = file === '-' ? await context.runtime.readStdin() : await readFile(file, 'utf8');
|
|
222
|
+
if (html.length === 0)
|
|
223
|
+
throw new UsageError(`${file === '-' ? 'stdin' : file} is empty.`);
|
|
224
|
+
const bytes = Buffer.byteLength(html, 'utf8');
|
|
225
|
+
if (bytes > MAX_HTML_BYTES)
|
|
226
|
+
throw new UsageError(`The HTML is ${bytes} bytes; an Artifact holds up to ${MAX_HTML_BYTES}.`);
|
|
227
|
+
return html;
|
|
228
|
+
}
|
|
229
|
+
/** The content flags given, each falling back to `defaults`. */
|
|
230
|
+
function contentFields(input, defaults) {
|
|
231
|
+
const tags = listOption(input, 'tag');
|
|
232
|
+
const fields = {
|
|
233
|
+
kind: choiceOption(input, 'kind', KINDS) ?? defaults.kind,
|
|
234
|
+
preferredSurface: choiceOption(input, 'surface', SURFACES) ?? defaults.preferredSurface,
|
|
235
|
+
renderer: choiceOption(input, 'renderer', RENDERERS) ?? defaults.renderer,
|
|
236
|
+
summary: stringOption(input, 'summary') ?? defaults.summary,
|
|
237
|
+
title: stringOption(input, 'title') ?? defaults.title,
|
|
238
|
+
...(tags.length === 0 ? {} : { tags }),
|
|
239
|
+
};
|
|
240
|
+
if (fields.renderer === 'reveal' && fields.kind !== 'slide-deck')
|
|
241
|
+
throw new UsageError('--renderer reveal needs --kind slide-deck.');
|
|
242
|
+
return fields;
|
|
243
|
+
}
|
|
244
|
+
async function requireTool(context, name) {
|
|
245
|
+
const tool = (await listWorkspaceTools(context)).find((each) => each.name === name);
|
|
246
|
+
if (tool === undefined)
|
|
247
|
+
throw new CommandFailure('failed', "This Dexto can't manage Artifacts yet.", null);
|
|
248
|
+
return tool;
|
|
249
|
+
}
|
|
250
|
+
/** Creates or replaces once agreed, or with --dry-run shows the call; null when it only showed it. */
|
|
251
|
+
async function save(context, input, name, call, title) {
|
|
252
|
+
const tool = await requireTool(context, name);
|
|
253
|
+
if (flag(input, 'dry-run')) {
|
|
254
|
+
dryRun(context, name, call);
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
const agreed = await agreeToCall(context, { level: toolCallLevel(tool, call), schema: tool.inputSchema, title }, flag(input, 'yes'));
|
|
258
|
+
const value = await queryWorkspaceTool(context, name, { ...call, ...agreed });
|
|
259
|
+
return { artifact: SavedSchema.parse(value).artifact, value };
|
|
260
|
+
}
|
|
261
|
+
/** The call a write would make, its HTML shown by size. */
|
|
262
|
+
function dryRun(context, tool, call) {
|
|
263
|
+
const { html, ...rest } = call;
|
|
264
|
+
const shown = typeof html === 'string' ? { ...rest, htmlBytes: Buffer.byteLength(html, 'utf8') } : rest;
|
|
265
|
+
context.output.result({ dryRun: true, tool, arguments: shown }, `Would call ${tool} with ${JSON.stringify(shown)}.`);
|
|
266
|
+
}
|
|
267
|
+
export const artifactCommands = [list, get, create, replace, share];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"automations.d.ts","sourceRoot":"","sources":["../../../../src/cli/cloud/commands/automations.ts"],"names":[],"mappings":"AAMA,OAAO,EAWH,KAAK,OAAO,EAEf,MAAM,eAAe,CAAC;AAoSvB,eAAO,MAAM,kBAAkB,EAAE,SAAS,OAAO,EAWhD,CAAC"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// `cloud automations`: run the project's agents on a schedule or on a signed webhook.
|
|
2
|
+
import { requireConsent } from '../../interaction.js';
|
|
3
|
+
import { unwrap } from '@dexto/cloud-client';
|
|
4
|
+
import { argument, BODY_OPTIONS, PAGE_OPTIONS, pageQuery, readJsonBody, stringOption, UsageError, YES_OPTION, flag, isJsonObject, } from '../command.js';
|
|
5
|
+
function automationPath(id) {
|
|
6
|
+
return { params: { path: { automation_id: id } } };
|
|
7
|
+
}
|
|
8
|
+
const COLUMNS = [
|
|
9
|
+
{ header: 'id', value: (automation) => automation.id },
|
|
10
|
+
{ header: 'name', value: (automation) => automation.name },
|
|
11
|
+
{ header: 'status', value: (automation) => automation.status },
|
|
12
|
+
{ header: 'trigger', value: (automation) => describeTrigger(automation) },
|
|
13
|
+
{ header: 'agent', value: (automation) => automation.target.agent_id },
|
|
14
|
+
{ header: 'last fired', value: (automation) => automation.last_fired_at },
|
|
15
|
+
];
|
|
16
|
+
const list = {
|
|
17
|
+
options: PAGE_OPTIONS,
|
|
18
|
+
path: ['cloud', 'automations', 'list'],
|
|
19
|
+
summary: "List the project's automations.",
|
|
20
|
+
async run(context, input) {
|
|
21
|
+
context.output.list(await unwrap(await (await context.client()).GET('/v1/automations', {
|
|
22
|
+
params: { query: pageQuery(input) },
|
|
23
|
+
})), COLUMNS);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
const get = {
|
|
27
|
+
arguments: '<automation_id>',
|
|
28
|
+
path: ['cloud', 'automations', 'get'],
|
|
29
|
+
summary: 'Show an automation.',
|
|
30
|
+
async run(context, input) {
|
|
31
|
+
context.output.record(await unwrap(await (await context.client()).GET('/v1/automations/{automation_id}', automationPath(argument(input, 0, 'automation_id')))));
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
const create = {
|
|
35
|
+
options: {
|
|
36
|
+
...BODY_OPTIONS,
|
|
37
|
+
agent: { description: 'The agent each firing runs.', type: 'string', valueName: 'ID' },
|
|
38
|
+
at: {
|
|
39
|
+
description: 'Fire once at this ISO 8601 time with an offset.',
|
|
40
|
+
type: 'string',
|
|
41
|
+
valueName: 'TIME',
|
|
42
|
+
},
|
|
43
|
+
cron: { description: 'Fire on this five-field cron expression.', type: 'string' },
|
|
44
|
+
message: { description: 'The message each firing sends the agent.', type: 'string' },
|
|
45
|
+
name: { description: 'Display name.', type: 'string' },
|
|
46
|
+
session: {
|
|
47
|
+
description: 'Send every firing to this session instead of a new one each time.',
|
|
48
|
+
type: 'string',
|
|
49
|
+
valueName: 'ID',
|
|
50
|
+
},
|
|
51
|
+
timezone: {
|
|
52
|
+
description: 'The IANA timezone the cron is read in (default UTC).',
|
|
53
|
+
type: 'string',
|
|
54
|
+
},
|
|
55
|
+
webhook: { description: 'Fire on each signed request to a webhook URL.', type: 'boolean' },
|
|
56
|
+
},
|
|
57
|
+
path: ['cloud', 'automations', 'create'],
|
|
58
|
+
summary: 'Create an automation from flags (--name --agent --message and one of --cron, --at, --webhook) or --file.',
|
|
59
|
+
async run(context, input) {
|
|
60
|
+
const body = await readJsonBody(context, input);
|
|
61
|
+
const definition = body === null ? fromFlags(input) : asCreateInput(body);
|
|
62
|
+
const automation = await unwrap(await (await context.client()).POST('/v1/automations', { body: definition }));
|
|
63
|
+
if (context.output.json)
|
|
64
|
+
return context.output.record(automation);
|
|
65
|
+
context.runtime.writeOutput(`Created automation ${automation.id} (${automation.name}).\n`);
|
|
66
|
+
if (automation.trigger.type === 'webhook') {
|
|
67
|
+
context.runtime.writeOutput(`Webhook URL: ${automation.trigger.url}\n`);
|
|
68
|
+
context.runtime.writeOutput(`Signing secret (shown once): ${automation.webhook_secret ?? '-'}\n`);
|
|
69
|
+
}
|
|
70
|
+
else if (automation.trigger.next_run_at !== null)
|
|
71
|
+
context.runtime.writeOutput(`Next run: ${automation.trigger.next_run_at}\n`);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
const update = {
|
|
75
|
+
arguments: '<automation_id>',
|
|
76
|
+
options: {
|
|
77
|
+
...BODY_OPTIONS,
|
|
78
|
+
message: { description: 'The message each firing sends.', type: 'string' },
|
|
79
|
+
name: { description: 'Display name.', type: 'string' },
|
|
80
|
+
},
|
|
81
|
+
path: ['cloud', 'automations', 'update'],
|
|
82
|
+
summary: "Change an automation's name or message, or any field with --file.",
|
|
83
|
+
async run(context, input) {
|
|
84
|
+
const body = await readJsonBody(context, input);
|
|
85
|
+
const name = stringOption(input, 'name');
|
|
86
|
+
const message = stringOption(input, 'message');
|
|
87
|
+
const changes = body === null
|
|
88
|
+
? {
|
|
89
|
+
...(name === undefined ? {} : { name }),
|
|
90
|
+
...(message === undefined ? {} : { target: { message } }),
|
|
91
|
+
}
|
|
92
|
+
: asUpdateInput(body);
|
|
93
|
+
const automation = await unwrap(await (await context.client()).PATCH('/v1/automations/{automation_id}', {
|
|
94
|
+
...automationPath(argument(input, 0, 'automation_id')),
|
|
95
|
+
body: changes,
|
|
96
|
+
}));
|
|
97
|
+
context.output.result(automation, `Updated automation ${automation.id}.`);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
function lifecycle(action, summary) {
|
|
101
|
+
return {
|
|
102
|
+
arguments: '<automation_id>',
|
|
103
|
+
...(action === 'delete' ? { options: YES_OPTION } : {}),
|
|
104
|
+
path: ['cloud', 'automations', action],
|
|
105
|
+
summary,
|
|
106
|
+
async run(context, input) {
|
|
107
|
+
const client = await context.client();
|
|
108
|
+
const id = argument(input, 0, 'automation_id');
|
|
109
|
+
if (action === 'delete') {
|
|
110
|
+
await requireConsent(context, flag(input, 'yes'), `Deleting automation ${id} removes it and its firing history for good.`);
|
|
111
|
+
const result = await unwrap(await client.DELETE('/v1/automations/{automation_id}', automationPath(id)));
|
|
112
|
+
return context.output.result(result, `Deleted automation ${id}.`);
|
|
113
|
+
}
|
|
114
|
+
if (action === 'run') {
|
|
115
|
+
const firing = await unwrap(await client.POST('/v1/automations/{automation_id}/run', automationPath(id)));
|
|
116
|
+
return context.output.result(firing, `Fired ${firing.id}: ${firing.status}${firing.run_id === null ? '' : `, run ${firing.run_id} in session ${firing.session_id ?? '-'}`}.`);
|
|
117
|
+
}
|
|
118
|
+
const automation = await unwrap(action === 'pause'
|
|
119
|
+
? await client.POST('/v1/automations/{automation_id}/pause', automationPath(id))
|
|
120
|
+
: await client.POST('/v1/automations/{automation_id}/resume', automationPath(id)));
|
|
121
|
+
context.output.result(automation, `Automation ${id} is ${automation.status}.`);
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const firings = {
|
|
126
|
+
arguments: '<automation_id>',
|
|
127
|
+
options: PAGE_OPTIONS,
|
|
128
|
+
path: ['cloud', 'automations', 'firings'],
|
|
129
|
+
summary: "List an automation's firings, newest first, with each run's status.",
|
|
130
|
+
async run(context, input) {
|
|
131
|
+
const page = await unwrap(await (await context.client()).GET('/v1/automations/{automation_id}/firings', {
|
|
132
|
+
params: {
|
|
133
|
+
path: { automation_id: argument(input, 0, 'automation_id') },
|
|
134
|
+
query: pageQuery(input),
|
|
135
|
+
},
|
|
136
|
+
}));
|
|
137
|
+
context.output.list(page, [
|
|
138
|
+
{ header: 'id', value: (firing) => firing.id },
|
|
139
|
+
{ header: 'source', value: (firing) => firing.source },
|
|
140
|
+
{ header: 'status', value: (firing) => firing.status },
|
|
141
|
+
{ header: 'run', value: (firing) => firing.run_id },
|
|
142
|
+
{ header: 'fired', value: (firing) => firing.fired_at },
|
|
143
|
+
]);
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
const rotate = {
|
|
147
|
+
arguments: '<automation_id>',
|
|
148
|
+
options: YES_OPTION,
|
|
149
|
+
path: ['cloud', 'automations', 'rotate-secret'],
|
|
150
|
+
summary: "Replace a webhook's signing secret; the old one stops at once.",
|
|
151
|
+
async run(context, input) {
|
|
152
|
+
const id = argument(input, 0, 'automation_id');
|
|
153
|
+
await requireConsent(context, flag(input, 'yes'), `The webhook's current signing secret stops working at once; senders need the new one.`);
|
|
154
|
+
const secret = await unwrap(await (await context.client()).POST('/v1/automations/{automation_id}/webhook/rotate_secret', automationPath(id)));
|
|
155
|
+
context.output.result(secret, `New signing secret (shown once): ${secret.webhook_secret}`);
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
function fromFlags(input) {
|
|
159
|
+
const name = stringOption(input, 'name');
|
|
160
|
+
const agentId = stringOption(input, 'agent');
|
|
161
|
+
const message = stringOption(input, 'message');
|
|
162
|
+
if (name === undefined || agentId === undefined || message === undefined)
|
|
163
|
+
throw new UsageError('An automation needs --name, --agent and --message, or --file.');
|
|
164
|
+
const cron = stringOption(input, 'cron');
|
|
165
|
+
const at = stringOption(input, 'at');
|
|
166
|
+
const webhook = flag(input, 'webhook');
|
|
167
|
+
if ([cron !== undefined, at !== undefined, webhook].filter(Boolean).length !== 1)
|
|
168
|
+
throw new UsageError('Pass exactly one of --cron, --at or --webhook.');
|
|
169
|
+
const sessionId = stringOption(input, 'session');
|
|
170
|
+
return {
|
|
171
|
+
name,
|
|
172
|
+
target: {
|
|
173
|
+
agent_id: agentId,
|
|
174
|
+
message,
|
|
175
|
+
...(sessionId === undefined
|
|
176
|
+
? {}
|
|
177
|
+
: { session: { mode: 'fixed', session_id: sessionId } }),
|
|
178
|
+
type: 'agent',
|
|
179
|
+
},
|
|
180
|
+
trigger: webhook
|
|
181
|
+
? { type: 'webhook' }
|
|
182
|
+
: {
|
|
183
|
+
schedule: cron === undefined
|
|
184
|
+
? { run_at: at ?? '', type: 'once' }
|
|
185
|
+
: {
|
|
186
|
+
cron,
|
|
187
|
+
timezone: stringOption(input, 'timezone') ?? 'UTC',
|
|
188
|
+
type: 'recurring',
|
|
189
|
+
},
|
|
190
|
+
type: 'schedule',
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/** The API validates the whole body; the CLI checks only its shape. */
|
|
195
|
+
function isCreateInput(value) {
|
|
196
|
+
return (isJsonObject(value) &&
|
|
197
|
+
typeof value.name === 'string' &&
|
|
198
|
+
isJsonObject(value.target) &&
|
|
199
|
+
isJsonObject(value.trigger));
|
|
200
|
+
}
|
|
201
|
+
function asCreateInput(value) {
|
|
202
|
+
if (!isCreateInput(value))
|
|
203
|
+
throw new UsageError('An automation needs name, and target and trigger objects.');
|
|
204
|
+
return value;
|
|
205
|
+
}
|
|
206
|
+
function isUpdateInput(value) {
|
|
207
|
+
return isJsonObject(value);
|
|
208
|
+
}
|
|
209
|
+
function asUpdateInput(value) {
|
|
210
|
+
if (!isUpdateInput(value))
|
|
211
|
+
throw new UsageError('The changes must be a JSON object.');
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
214
|
+
function describeTrigger(automation) {
|
|
215
|
+
const trigger = automation.trigger;
|
|
216
|
+
if (trigger.type === 'webhook')
|
|
217
|
+
return 'webhook';
|
|
218
|
+
return trigger.schedule.type === 'once'
|
|
219
|
+
? `once ${trigger.schedule.run_at}`
|
|
220
|
+
: `${trigger.schedule.cron} ${trigger.schedule.timezone}`;
|
|
221
|
+
}
|
|
222
|
+
export const automationCommands = [
|
|
223
|
+
list,
|
|
224
|
+
get,
|
|
225
|
+
create,
|
|
226
|
+
update,
|
|
227
|
+
lifecycle('pause', "Stop an automation's schedule."),
|
|
228
|
+
lifecycle('resume', 'Resume a paused automation.'),
|
|
229
|
+
lifecycle('run', 'Fire an automation now, whatever its status.'),
|
|
230
|
+
lifecycle('delete', 'Delete an automation and its firing history.'),
|
|
231
|
+
firings,
|
|
232
|
+
rotate,
|
|
233
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chats.d.ts","sourceRoot":"","sources":["../../../../src/cli/cloud/commands/chats.ts"],"names":[],"mappings":"AAMA,OAAO,EAMH,KAAK,OAAO,EAIf,MAAM,eAAe,CAAC;AAwQvB,eAAO,MAAM,YAAY,EAAE,SAAS,OAAO,EAAyB,CAAC"}
|