@xiashe/cli 0.1.33 → 0.1.35-superconnector.2
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 +88 -1
- package/bin/xiashe.mjs +271 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -57,4 +57,91 @@ Production defaults:
|
|
|
57
57
|
|
|
58
58
|
An Agent must never add `--confirm` before the user has explicitly agreed to the displayed purpose. If the wallet is unavailable, obtain permission before running the official `@alipay/agent-payment` setup, then run `payment doctor` again.
|
|
59
59
|
|
|
60
|
-
For a clean Codex Task, the XiaShe MCP response provides a version-pinned ephemeral command such as `npx -y @xiashe/cli@0.1.
|
|
60
|
+
For a clean Codex Task, the XiaShe MCP response provides a version-pinned ephemeral command such as `npx -y @xiashe/cli@0.1.34 payment bridge-info`. No global `xiashe` installation is required for that path. Do not run preflight before requesting payment confirmation: it is a read-only diagnostic only. After explicit confirmation, ordinary hosts inject `XIASHE_HOST_BUSINESS_SESSION` only into the supplied payment command’s foreground child process. Codex Node REPL uses the private MCP response’s stdin-only adapter because its spawned child does not inherit request metadata. The Agent must inspect bridge JSON instead of suppressing output or guessing status from shell text. Failed attempts include a redacted `diagnosis` object and `userVisible` next step; do not replace them with a generic payment-failed message.
|
|
61
|
+
|
|
62
|
+
## Superconnector runtime preview
|
|
63
|
+
|
|
64
|
+
The `0.1.35-superconnector.2` prerelease includes:
|
|
65
|
+
|
|
66
|
+
- `connectors providers|list|requests|actions|grants`, `connect`, `reconnect`, `disconnect`, and scoped grants. Use `--permissions` with the IDs returned by `connectors providers`.
|
|
67
|
+
- `runtime install|release|releases|publish` for immutable reviewed Registry artifacts.
|
|
68
|
+
- `runtime run` for foreground Docker scripts and `runtime mcp` for a current Agent's stdio MCP session.
|
|
69
|
+
- `runtime hosts|start|host|host-mcp` for explicitly targeted existing Agent connections.
|
|
70
|
+
- `runtime retry-results|retry-host-results` for result delivery only; these commands never rerun business actions.
|
|
71
|
+
- `runs list|show|cancel` for execution state, results and cancellation.
|
|
72
|
+
|
|
73
|
+
Run `xiashe --help` for flags. Sign in through the existing XiaShe profile; never pass SaaS API keys or OAuth app secrets as command-line arguments. Platform configuration and the matching additive backend release are required. Script execution needs Docker and an immutable official Node image already present locally.
|
|
74
|
+
|
|
75
|
+
The repository includes an isolated local backend, simulated provider and end-to-end scripts documented in `docs/superconnector-development.md`. This prerelease has not been published to npm or deployed to production.
|
|
76
|
+
|
|
77
|
+
Hybrid runtime versions use one reviewed package for both entrypoints. `runtime mcp` selects Agent execution, `runtime run` selects script execution, and targeted `runtime start` requires `--mode agent` or `--mode script` for a hybrid version. A request key cannot be reused with a different mode.
|
|
78
|
+
|
|
79
|
+
`runtime publish ... --signature-file proof.json` optionally imports a public BYOA v1 P-256 envelope. Supply only the public proof for the exact filtered delivery package. The CLI does not generate or import private publisher keys. Verified signatures remain subject to existing creator authorization and runtime/Red review.
|
|
80
|
+
|
|
81
|
+
For complete version history, use `runtime releases <registry-entry-id> --limit 20` and repeat with `--cursor <continueCursor>` until `isDone`. Without pagination flags the legacy array response remains capped at 100.
|
|
82
|
+
|
|
83
|
+
After restoring an owning account’s private outbox, `runtime retry-results --outbox-dir <restored-root>` retries saved receipts only. Preserve the matching execution claim records and keep the original worker offline; this command does not restart tasks.
|
|
84
|
+
|
|
85
|
+
`connectors grant-public --actions hackernews.get_top_stories,hackernews.get_item --purpose "Read public headlines" --release <id>` approves reviewed public reads without binding a SaaS account. Only explicitly enabled public actions work; this does not allow direct script networking.
|
|
86
|
+
|
|
87
|
+
## Non-OAuth connections and reusable Skill preparation
|
|
88
|
+
|
|
89
|
+
For operator-enabled providers, inspect the gateway's required fields before creating a private JSON file:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
xiashe connectors credential-setup firecrawl
|
|
93
|
+
# Create credentials.json with the returned field names; keep it outside Skill packages and Git.
|
|
94
|
+
chmod 600 credentials.json
|
|
95
|
+
xiashe connectors connect-credentials firecrawl --auth-type api_key --credential-file credentials.json --request-key <unique-request-key>
|
|
96
|
+
xiashe connectors credential-status <unique-request-key>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The file contains only the field-value object. Use `custom_credential` for providers requiring multiple fields. Values travel through the authenticated credential HTTP endpoint to OpenConnector; they are not runtime inputs. Delete the local file after successful binding when it is no longer needed. If a submission has an unknown outcome, check its status and ask the operator to reconcile it; do not generate another request key to retry.
|
|
100
|
+
|
|
101
|
+
To replace a key, add `--replace <connection-id>` with a new request key. This pauses the old account and invalidates old approvals. Successful replacement creates a new connection and removes the old gateway credential; select and approve the new account for subsequent runs.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
xiashe runtime prepare <release-id>
|
|
105
|
+
xiashe runtime hosts
|
|
106
|
+
xiashe runtime launch <release-id> --config-file launch.json --host <host-id> --request-key <unique-run-key>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`prepare` shows the reviewed requirements and still-valid saved choices without granting access. After the user confirms, `launch.json` may contain `input`, `connections`, `publicActionIds`, `creatorServiceIds`, and `executionMode`. Each connection entry contains `connectionId` and its current `revision`; consult the preparation response for the exact identifiers. Include no SaaS credentials. A hybrid release requires an explicit `agent` or `script` mode. Launch performs permission checks, scoped approval and queueing atomically; it remembers declared parameters and valid account choices only for this user and exact release. Every subsequent run still requires confirmation.
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
## Quick SaaS setup (preview .2)
|
|
113
|
+
|
|
114
|
+
Web and iOS creator analytics offer a three-step setup for a single Agent-mode action:
|
|
115
|
+
choose the action/account source, define scope and call limits, then confirm review.
|
|
116
|
+
The uploaded package and creator services are saved atomically. Store listing remains
|
|
117
|
+
separate. Multi-action contracts, scripts and complex schemas use advanced Web setup.
|
|
118
|
+
Drafts survive step changes and connection handoff while the editor stays mounted;
|
|
119
|
+
closing the app or reloading the page does not provide durable draft storage.
|
|
120
|
+
|
|
121
|
+
CLI users can scaffold the same configuration without logging in:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
xiashe runtime init --action firecrawl.credit_usage_get --account-source creator --out runtime-setup.json
|
|
125
|
+
# Review/edit against the deployed schema: choose your connection, disclosure,
|
|
126
|
+
# fixed resources, allowed output fields and explicitly approved call limits.
|
|
127
|
+
xiashe runtime publish-config <registry-entry-id> --artifact <artifact-id> --version 1.0.1 --config-file runtime-setup.json --confirm
|
|
128
|
+
xiashe runtime doctor --mcp-url https://actions.projectphenix.site/mcp/xiashe
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`consumer` and `public` templates omit creator services. Public actions must also be
|
|
132
|
+
explicitly enabled by the operator. Templates contain no credentials; incomplete
|
|
133
|
+
creator templates cannot be submitted unchanged. The same version and content can
|
|
134
|
+
safely retry an uncertain save. Changing the content requires a new version; it
|
|
135
|
+
never resets usage on the old version. Call limits are not a SaaS monetary budget.
|
|
136
|
+
|
|
137
|
+
Release order after staging acceptance (publisher runs these commands):
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
(cd packages/xiashe-sdk && npm publish --access public --tag superconnector)
|
|
141
|
+
(cd packages/xiashe-cli && npm publish --access public --tag superconnector)
|
|
142
|
+
(cd packages/agentpie-cli && npm publish --access public --tag superconnector)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
All three packages use `0.1.35-superconnector.2`. Deploy the matching additive
|
|
146
|
+
backend before publishing packages. Keep `latest` unchanged. Rollback points users
|
|
147
|
+
to the previous prerelease; do not overwrite immutable versions or delete run data.
|
package/bin/xiashe.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { existsSync } from 'node:fs';
|
|
5
|
-
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
5
|
+
import { readdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
6
6
|
import os from 'node:os';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
|
|
@@ -19,8 +19,18 @@ try {
|
|
|
19
19
|
|
|
20
20
|
const {
|
|
21
21
|
VERSION,
|
|
22
|
+
probeRuntimeGateway,
|
|
23
|
+
runtimeSetupTemplate,
|
|
22
24
|
DEFAULTS,
|
|
23
25
|
XiasheClient,
|
|
26
|
+
installRuntimePackage,
|
|
27
|
+
retryRuntimeResults,
|
|
28
|
+
runRuntimeScript,
|
|
29
|
+
serveRuntimeScriptHost,
|
|
30
|
+
retryRuntimeHostResults,
|
|
31
|
+
createRuntimeAgentSession,
|
|
32
|
+
createRuntimeAgentHost,
|
|
33
|
+
serveRuntimeMcp,
|
|
24
34
|
configPath,
|
|
25
35
|
readConfig,
|
|
26
36
|
updateProfile,
|
|
@@ -57,6 +67,8 @@ const PRODUCT_ENV = COMMAND_NAME === 'agentpie' ? 'global' : 'cn';
|
|
|
57
67
|
// local state, stdout, or a model-visible command argument.
|
|
58
68
|
const PAYMENT_HOST_CONTRACT_VERSION = 'xiashe.payment-host.v1';
|
|
59
69
|
const PAYMENT_HOST_SESSION_ENV = 'XIASHE_HOST_BUSINESS_SESSION';
|
|
70
|
+
const PAYMENT_HOST_STDIN_FLAG = 'host-session-stdin';
|
|
71
|
+
const PAYMENT_HOST_STDIN_MAX_BYTES = 256;
|
|
60
72
|
// These are compatibility adapters for known OpenAI/Codex hosts while their
|
|
61
73
|
// runtimes adopt the portable environment contract. Unknown host variables
|
|
62
74
|
// are deliberately not guessed: other Agents must inject the standard name.
|
|
@@ -79,6 +91,41 @@ Usage:
|
|
|
79
91
|
${c} config path|get|set <key> <value>|use <profile>
|
|
80
92
|
|
|
81
93
|
${c} connections list
|
|
94
|
+
${c} runtime prepare <release-id>
|
|
95
|
+
${c} runtime doctor --mcp-url <https-url> (read-only; no login or SaaS calls)
|
|
96
|
+
${c} runtime init --action <provider.action> --account-source creator|consumer|public --out <json-file>
|
|
97
|
+
${c} runtime publish-config <registry-entry-id> --artifact <id> --version <version> --config-file <json-file> --confirm
|
|
98
|
+
${c} runtime launch <release-id> --config-file <json> --host <host-id> --request-key <key>
|
|
99
|
+
${c} connectors providers|list|requests|actions|grants
|
|
100
|
+
${c} connectors describe <action-id>
|
|
101
|
+
${c} connectors connect <provider> [--permissions repo,workflow] [--request-key <key>]
|
|
102
|
+
${c} connectors credential-setup <provider>
|
|
103
|
+
${c} connectors connect-credentials <provider> --auth-type api_key|custom_credential --credential-file <private-json> --request-key <key> [--replace <connection-id>]
|
|
104
|
+
${c} connectors credential-status <request-key>
|
|
105
|
+
${c} connectors reconnect <connection-id> [--permissions repo,workflow] [--request-key <key>]
|
|
106
|
+
${c} connectors poll|cancel-auth <request-id>
|
|
107
|
+
${c} connectors disconnect <connection-id>
|
|
108
|
+
${c} connectors grant <connection-id> --actions <action,...> --purpose <text> [--duration once|day|month]
|
|
109
|
+
${c} connectors grant-public --actions <action,...> --purpose <text> [--release <release-id>]
|
|
110
|
+
${c} connectors grant-service <service-id> --release <release-id> --actions <action> --purpose <text>
|
|
111
|
+
${c} connectors revoke <grant-id>
|
|
112
|
+
${c} connectors execute <action> --grant <id> --request-key <key> [--input-file <json-file>]
|
|
113
|
+
${c} runs list|show|cancel [run-id]
|
|
114
|
+
${c} runtime install <release-id> [--cache-dir <path>]
|
|
115
|
+
${c} runtime retry-results [--outbox-dir <restored-directory>]
|
|
116
|
+
${c} runtime hosts
|
|
117
|
+
${c} runtime host-mcp
|
|
118
|
+
${c} runtime start <release-id> --host <host-id> --grants <grant-ids> --request-key <key> [--mode agent|script]
|
|
119
|
+
${c} runtime host --image node@sha256:... [--once]
|
|
120
|
+
${c} runtime retry-host-results
|
|
121
|
+
${c} runtime run <release-id> --request-key <key> --image node@sha256:<digest> [--grants <ids>] [--input-file <json-file>]
|
|
122
|
+
${c} runtime mcp <release-id> --request-key <key> [--grants <ids>] [--input-file <json-file>]
|
|
123
|
+
${c} runtime services <release-id>
|
|
124
|
+
${c} runtime service-create <release-id> --config-file <json-file>
|
|
125
|
+
${c} runtime service-revoke <service-id>
|
|
126
|
+
${c} runtime release <release-id>
|
|
127
|
+
${c} runtime releases <registry-entry-id> [--limit <1-50>] [--cursor <cursor>]
|
|
128
|
+
${c} runtime publish <registry-entry-id> --artifact <id> --version <version> --contract-file <json-file> [--signature-file <json-file>]
|
|
82
129
|
${c} claw pair --connection <id-or-name>
|
|
83
130
|
${c} claw repair --connection <id-or-name>
|
|
84
131
|
${c} claw check --connection <id-or-name>
|
|
@@ -278,13 +325,51 @@ function hostSessionContractStatus(resolution = null) {
|
|
|
278
325
|
};
|
|
279
326
|
}
|
|
280
327
|
|
|
281
|
-
function
|
|
328
|
+
async function readPaymentBusinessSessionFromStdin() {
|
|
329
|
+
return await new Promise((resolve) => {
|
|
330
|
+
let received = '';
|
|
331
|
+
let settled = false;
|
|
332
|
+
const finish = (value = null) => {
|
|
333
|
+
if (settled) return;
|
|
334
|
+
settled = true;
|
|
335
|
+
clearTimeout(timeout);
|
|
336
|
+
process.stdin.pause();
|
|
337
|
+
resolve(value);
|
|
338
|
+
};
|
|
339
|
+
const timeout = setTimeout(() => finish(null), 5_000);
|
|
340
|
+
process.stdin.setEncoding('utf8');
|
|
341
|
+
process.stdin.on('data', (chunk) => {
|
|
342
|
+
received += chunk;
|
|
343
|
+
if (Buffer.byteLength(received, 'utf8') > PAYMENT_HOST_STDIN_MAX_BYTES) {
|
|
344
|
+
finish(null);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
process.stdin.once('end', () => finish(received.trim()));
|
|
348
|
+
process.stdin.once('error', () => finish(null));
|
|
349
|
+
process.stdin.resume();
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async function resolvePaymentBusinessSession(flags) {
|
|
282
354
|
// A model-visible command-line session is not an acceptable trust boundary.
|
|
283
355
|
// Hosts that cannot inject the standard environment must implement the v1
|
|
284
356
|
// adapter rather than asking a user or model to provide a replacement.
|
|
285
357
|
if (flags['session-id'] !== undefined || flags.sessionId !== undefined) {
|
|
286
358
|
return { error: 'host_session_override_forbidden' };
|
|
287
359
|
}
|
|
360
|
+
if (flags[PAYMENT_HOST_STDIN_FLAG] !== undefined) {
|
|
361
|
+
if (flags[PAYMENT_HOST_STDIN_FLAG] !== true) {
|
|
362
|
+
return { error: 'host_session_override_forbidden' };
|
|
363
|
+
}
|
|
364
|
+
const candidate = await readPaymentBusinessSessionFromStdin();
|
|
365
|
+
if (HOST_BUSINESS_SESSION_PATTERN.test(String(candidate || '').trim())) {
|
|
366
|
+
return {
|
|
367
|
+
sessionId: String(candidate).trim(),
|
|
368
|
+
provider: 'codex_node_repl_request_metadata'
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
288
373
|
const standardCandidate = String(process.env[PAYMENT_HOST_SESSION_ENV] || '').trim();
|
|
289
374
|
if (HOST_BUSINESS_SESSION_PATTERN.test(standardCandidate)) {
|
|
290
375
|
return {
|
|
@@ -320,8 +405,8 @@ function hostBusinessSessionUnavailableResult() {
|
|
|
320
405
|
};
|
|
321
406
|
}
|
|
322
407
|
|
|
323
|
-
function hostBusinessSessionOverrideForbiddenResult() {
|
|
324
|
-
const hostResolution = resolvePaymentBusinessSession({});
|
|
408
|
+
async function hostBusinessSessionOverrideForbiddenResult() {
|
|
409
|
+
const hostResolution = await resolvePaymentBusinessSession({});
|
|
325
410
|
return {
|
|
326
411
|
ok: false,
|
|
327
412
|
status: 'host_session_override_forbidden',
|
|
@@ -537,6 +622,182 @@ async function cmdConnections(sub, _args, global) {
|
|
|
537
622
|
]);
|
|
538
623
|
}
|
|
539
624
|
|
|
625
|
+
async function cmdConnectors(sub, args, global) {
|
|
626
|
+
const flags = parseFlags(args);
|
|
627
|
+
const { client } = await makeClient(global);
|
|
628
|
+
const id = () => requireArg(flags._[0], 'id');
|
|
629
|
+
let result;
|
|
630
|
+
if (!sub || sub === 'list') result = await client.listSaasConnections();
|
|
631
|
+
else if (sub === 'providers') result = await client.listSaasProviders();
|
|
632
|
+
else if (sub === 'actions') result = await client.listConnectorActions();
|
|
633
|
+
else if (sub === 'describe') {
|
|
634
|
+
result = await client.getConnectorActionDefinition(id());
|
|
635
|
+
}
|
|
636
|
+
else if (sub === 'grants') result = await client.listConnectorGrants();
|
|
637
|
+
else if (sub === 'requests') result = await client.listSaasAuthorizationRequests();
|
|
638
|
+
else if (sub === 'credential-setup') result = await client.getSaasCredentialSetup(id());
|
|
639
|
+
else if (sub === 'credential-status') result = await client.getSaasCredentialStatus(id());
|
|
640
|
+
else if (sub === 'connect-credentials') {
|
|
641
|
+
if (!flags['credential-file'] || !flags['request-key'] || !['api_key', 'custom_credential'].includes(flags['auth-type']))
|
|
642
|
+
fail('Require --credential-file, --request-key and --auth-type api_key|custom_credential. Never pass secrets as command arguments.', EXIT_USAGE);
|
|
643
|
+
const filename = path.resolve(String(flags['credential-file']));
|
|
644
|
+
const info = await stat(filename);
|
|
645
|
+
if (!info.isFile() || info.size > 32768 || process.platform !== 'win32' && (info.mode & 0o077))
|
|
646
|
+
fail('Use a private JSON file of at most 32KB (chmod 600 on Unix).', EXIT_USAGE);
|
|
647
|
+
let values;
|
|
648
|
+
try { values = JSON.parse(await readFile(filename, 'utf8')); } catch { fail('Credential file must contain valid JSON.', EXIT_USAGE); }
|
|
649
|
+
result = await client.connectSaasCredentials(id(), { authType: flags['auth-type'], values, requestKey: flags['request-key'], replaceConnectionId: flags.replace });
|
|
650
|
+
}
|
|
651
|
+
else if (sub === 'connect') result = await client.connectSaas(id(), flags['request-key'] || createIdempotencyKey(), { authorizationOptionIds: flags.permissions ? String(flags.permissions).split(',').filter(Boolean) : [] });
|
|
652
|
+
else if (sub === 'reconnect') result = await client.reauthorizeSaas(id(), { requestKey: flags['request-key'] || createIdempotencyKey(), authorizationOptionIds: flags.permissions ? String(flags.permissions).split(',').filter(Boolean) : [] });
|
|
653
|
+
else if (sub === 'poll') result = await client.pollSaasAuthorization(id());
|
|
654
|
+
else if (sub === 'cancel-auth') result = await client.cancelSaasAuthorization(id());
|
|
655
|
+
else if (sub === 'disconnect') result = await client.disconnectSaas(id());
|
|
656
|
+
else if (sub === 'revoke') result = await client.revokeConnectorGrant(id());
|
|
657
|
+
else if (sub === 'grant' || sub === 'grant-public' || sub === 'grant-service') result = await client.grantConnector({ ...(sub === 'grant-public' ? { publicAccess: true } : sub === 'grant-service' ? { creatorServiceId: id() } : { connectionId: id() }),
|
|
658
|
+
actionIds: String(requireValue('--actions', flags.actions)).split(',').map(value => value.trim()).filter(Boolean),
|
|
659
|
+
purpose: requireValue('--purpose', flags.purpose), duration: flags.duration || 'once', ...(flags.release ? { releaseId: String(flags.release) } : {}) });
|
|
660
|
+
else if (sub === 'execute') {
|
|
661
|
+
let input = {};
|
|
662
|
+
if (flags['input-file']) {
|
|
663
|
+
const filename = path.resolve(String(flags['input-file']));
|
|
664
|
+
if ((await stat(filename)).size > 32768) fail('Input must be at most 32KB.', EXIT_USAGE);
|
|
665
|
+
input = JSON.parse(await readFile(filename, 'utf8'));
|
|
666
|
+
}
|
|
667
|
+
result = await client.executeConnector({ actionId: id(), input,
|
|
668
|
+
grantId: requireValue('--grant', flags.grant), requestKey: requireValue('--request-key', flags['request-key']) });
|
|
669
|
+
} else fail(`Unknown connectors command: ${sub}`, EXIT_USAGE);
|
|
670
|
+
print(result ?? { ok: true }, global);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
async function cmdRuns(sub, args, global) {
|
|
674
|
+
const { client } = await makeClient(global);
|
|
675
|
+
if (!sub || sub === 'list') return print(await client.listSkillRuns(), global);
|
|
676
|
+
const id = requireArg(args[0], 'run-id');
|
|
677
|
+
if (sub === 'show') return print(await client.getSkillRun(id), global);
|
|
678
|
+
if (sub === 'cancel') return print(await client.cancelSkillRun(id) ?? { ok: true }, global);
|
|
679
|
+
fail(`Unknown runs command: ${sub}`, EXIT_USAGE);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
async function cmdRuntime(sub, args, global) {
|
|
683
|
+
const flags = parseFlags(args);
|
|
684
|
+
if (sub === 'doctor') { const report = await probeRuntimeGateway(requireValue('--mcp-url', flags['mcp-url'])); print(report, global); if (!report.ok) process.exitCode = EXIT_RUNTIME; return; }
|
|
685
|
+
if (sub === 'init') {
|
|
686
|
+
const template = runtimeSetupTemplate(requireValue('--action', flags.action), requireValue('--account-source', flags['account-source']));
|
|
687
|
+
const file = path.resolve(String(requireValue('--out', flags.out)));
|
|
688
|
+
await writeFile(file, JSON.stringify(template, null, 2) + '\n', { flag: 'wx', mode: 0o600 });
|
|
689
|
+
return print({ file, nextStep: 'Inspect the deployed action with connectors describe; complete scope, outputs and limits. Never put SaaS keys in this file. Then use runtime publish-config --confirm; this submits for review, not execution.' }, global);
|
|
690
|
+
}
|
|
691
|
+
const { client } = await makeClient(global);
|
|
692
|
+
if (sub === 'publish-config') {
|
|
693
|
+
if (flags.confirm !== true) fail('Review account source, outputs and additional usage, then pass --confirm. No action has been executed.', EXIT_USAGE);
|
|
694
|
+
const file = path.resolve(String(requireValue('--config-file', flags['config-file'])));
|
|
695
|
+
if ((await stat(file)).size > 240000) fail('Setup file must be at most 240KB.', EXIT_USAGE);
|
|
696
|
+
const config = JSON.parse(await readFile(file, 'utf8'));
|
|
697
|
+
if (!['consumer', 'creator', 'public'].includes(config.accountSource) || !Array.isArray(config.services) || !Array.isArray(config.contract?.actionIds) || config.contract.actionIds.length !== 1 ||
|
|
698
|
+
(config.accountSource === 'creator' ? config.services.length !== 1 || config.services[0].actionId !== config.contract.actionIds[0] : config.services.length !== 0)) fail('Use a one-action setup from runtime init. Creator services must cover that action.', EXIT_USAGE);
|
|
699
|
+
const releaseId = await client.createConfiguredRuntimeRelease({ registryEntryId: requireArg(flags._[0], 'registry-entry-id'), artifactId: requireValue('--artifact', flags.artifact), version: requireValue('--version', flags.version), accountSource: config.accountSource, contract: config.contract, services: config.services });
|
|
700
|
+
return print({ releaseId, nextStep: 'Saved atomically for package verification and runtime review. Check runtime release <id>. Store listing remains separate. Retry a lost response with exactly the same version and configuration.' }, global);
|
|
701
|
+
}
|
|
702
|
+
if (sub === 'retry-results') return print(await retryRuntimeResults(client, flags['outbox-dir'] ? { outboxRoot: path.resolve(String(flags['outbox-dir'])) } : {}), global);
|
|
703
|
+
if (sub === 'hosts') return print(await client.listRuntimeHosts(), global);
|
|
704
|
+
if (sub === 'retry-host-results') return print(await retryRuntimeHostResults(client,
|
|
705
|
+
flags['outbox-dir'] ? { outboxRoot: path.resolve(String(flags['outbox-dir'])) } : {}), global);
|
|
706
|
+
if (sub === 'host-mcp') {
|
|
707
|
+
const controller = new AbortController();
|
|
708
|
+
const stop = () => controller.abort();
|
|
709
|
+
process.once('SIGINT', stop); process.once('SIGTERM', stop);
|
|
710
|
+
try {
|
|
711
|
+
const host = await createRuntimeAgentHost(client, {
|
|
712
|
+
...(flags['state-dir'] ? { stateRoot: path.resolve(String(flags['state-dir'])) } : {}),
|
|
713
|
+
...(flags['outbox-dir'] ? { outboxRoot: path.resolve(String(flags['outbox-dir'])) } : {}),
|
|
714
|
+
});
|
|
715
|
+
await serveRuntimeMcp(host, { signal: controller.signal });
|
|
716
|
+
} finally { process.removeListener('SIGINT', stop); process.removeListener('SIGTERM', stop); }
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
if (sub === 'host') {
|
|
720
|
+
const controller = new AbortController();
|
|
721
|
+
const stop = () => controller.abort();
|
|
722
|
+
process.once('SIGINT', stop); process.once('SIGTERM', stop);
|
|
723
|
+
try {
|
|
724
|
+
return print(await serveRuntimeScriptHost(client, { image: requireValue('--image', flags.image), once: flags.once === true },
|
|
725
|
+
{ signal: controller.signal,
|
|
726
|
+
...(flags['state-dir'] ? { stateRoot: path.resolve(String(flags['state-dir'])) } : {}),
|
|
727
|
+
...(flags['outbox-dir'] ? { outboxRoot: path.resolve(String(flags['outbox-dir'])) } : {}),
|
|
728
|
+
onEvent: event => process.stderr.write(JSON.stringify(event) + '\n') }), global);
|
|
729
|
+
} finally { process.removeListener('SIGINT', stop); process.removeListener('SIGTERM', stop); }
|
|
730
|
+
}
|
|
731
|
+
const id = requireArg(flags._[0], 'release or registry entry id');
|
|
732
|
+
if (sub === 'prepare') return print(await client.prepareRuntimeRun(id), global);
|
|
733
|
+
if (sub === 'launch') {
|
|
734
|
+
const filename = path.resolve(String(requireValue('--config-file', flags['config-file'])));
|
|
735
|
+
if ((await stat(filename)).size > 32768) fail('Launch config must be at most 32KB.', EXIT_USAGE);
|
|
736
|
+
const config = JSON.parse(await readFile(filename, 'utf8'));
|
|
737
|
+
return print({ runId: await client.launchRuntimeRun({ ...config, releaseId: id, requestKey: requireValue('--request-key', flags['request-key']), targetAgentConnectionId: requireValue('--host', flags.host) }) }, global);
|
|
738
|
+
}
|
|
739
|
+
if (sub === 'services') return print(await client.listCreatorServices(id), global);
|
|
740
|
+
if (sub === 'service-revoke') return print(await client.revokeCreatorService(id) ?? { ok: true }, global);
|
|
741
|
+
if (sub === 'service-create') {
|
|
742
|
+
const filename = path.resolve(String(requireValue('--config-file', flags['config-file'])));
|
|
743
|
+
if ((await stat(filename)).size > 32768) fail('Service config must be at most 32KB.', EXIT_USAGE);
|
|
744
|
+
const config = JSON.parse(await readFile(filename, 'utf8'));
|
|
745
|
+
return print({ serviceId: await client.createCreatorService({ ...config, releaseId: id }) }, global);
|
|
746
|
+
}
|
|
747
|
+
if (sub === 'run' || sub === 'mcp' || sub === 'start') {
|
|
748
|
+
let input = {};
|
|
749
|
+
if (flags['input-file']) {
|
|
750
|
+
const filename = path.resolve(String(flags['input-file']));
|
|
751
|
+
if ((await stat(filename)).size > 32768) fail('Input must be at most 32KB.', EXIT_USAGE);
|
|
752
|
+
input = JSON.parse(await readFile(filename, 'utf8'));
|
|
753
|
+
}
|
|
754
|
+
if (sub === 'start') return print({ runId: await client.startRuntimeRun({ releaseId: id, input,
|
|
755
|
+
grantIds: flags.grants ? String(flags.grants).split(',').filter(Boolean) : [],
|
|
756
|
+
requestKey: requireValue('--request-key', flags['request-key']), targetAgentConnectionId: requireValue('--host', flags.host), ...(flags.mode ? { executionMode: String(flags.mode) } : {}) }) }, global);
|
|
757
|
+
const controller = new AbortController();
|
|
758
|
+
const stop = () => controller.abort();
|
|
759
|
+
process.once('SIGINT', stop); process.once('SIGTERM', stop);
|
|
760
|
+
try {
|
|
761
|
+
if (sub === 'mcp') {
|
|
762
|
+
const session = await createRuntimeAgentSession(client, { releaseId: id, input,
|
|
763
|
+
grantIds: flags.grants ? String(flags.grants).split(',').filter(Boolean) : [], requestKey: requireValue('--request-key', flags['request-key']) },
|
|
764
|
+
{ ...(flags['state-dir'] ? { stateRoot: path.resolve(String(flags['state-dir'])) } : {}), ...(flags['outbox-dir'] ? { outboxRoot: path.resolve(String(flags['outbox-dir'])) } : {}) });
|
|
765
|
+
await serveRuntimeMcp(session, { signal: controller.signal });
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
return print(await runRuntimeScript(client, { releaseId: id, input,
|
|
769
|
+
grantIds: flags.grants ? String(flags.grants).split(',').filter(Boolean) : [],
|
|
770
|
+
requestKey: requireValue('--request-key', flags['request-key']), image: requireValue('--image', flags.image) },
|
|
771
|
+
{ signal: controller.signal }), global);
|
|
772
|
+
} finally { process.removeListener('SIGINT', stop); process.removeListener('SIGTERM', stop); }
|
|
773
|
+
}
|
|
774
|
+
if (sub === 'install') {
|
|
775
|
+
const installed = await installRuntimePackage(client, id, flags['cache-dir'] ? { cacheRoot: path.resolve(String(flags['cache-dir'])) } : {});
|
|
776
|
+
return print({ directory: installed.directory, releaseId: installed.release.id, version: installed.release.version,
|
|
777
|
+
artifactSha256: installed.release.artifactSha256, mode: installed.contract.mode, entry: installed.contract.entry }, global);
|
|
778
|
+
}
|
|
779
|
+
if (sub === 'release') return print(await client.getRuntimeRelease(id), global);
|
|
780
|
+
if (sub === 'releases') return print(flags.limit !== undefined || flags.cursor !== undefined
|
|
781
|
+
? await client.listRuntimeReleasePage(id, { limit: Number(flags.limit ?? 20), cursor: flags.cursor === undefined ? null : String(flags.cursor) })
|
|
782
|
+
: await client.listRuntimeReleases(id), global);
|
|
783
|
+
if (sub === 'publish') {
|
|
784
|
+
const filename = path.resolve(String(requireValue('--contract-file', flags['contract-file'])));
|
|
785
|
+
if ((await stat(filename)).size > 32768) fail('Contract must be at most 32KB.', EXIT_USAGE);
|
|
786
|
+
const contract = JSON.parse(await readFile(filename, 'utf8'));
|
|
787
|
+
let signature;
|
|
788
|
+
if (flags['signature-file']) {
|
|
789
|
+
const signatureFile = path.resolve(String(flags['signature-file']));
|
|
790
|
+
if ((await stat(signatureFile)).size > 200000) fail('Signature envelope must be at most 200KB.', EXIT_USAGE);
|
|
791
|
+
signature = JSON.parse(await readFile(signatureFile, 'utf8'));
|
|
792
|
+
const publicKey = JSON.parse(signature.publicJwk);
|
|
793
|
+
if (publicKey.d || signature.privateJwk || signature.privateKey) fail('Provide a public signature envelope without private keys.', EXIT_USAGE);
|
|
794
|
+
}
|
|
795
|
+
return print(await client.createRuntimeRelease({ registryEntryId: id, artifactId: requireValue('--artifact', flags.artifact),
|
|
796
|
+
version: requireValue('--version', flags.version), contract, signature }), global);
|
|
797
|
+
}
|
|
798
|
+
fail(`Unknown runtime command: ${sub}`, EXIT_USAGE);
|
|
799
|
+
}
|
|
800
|
+
|
|
540
801
|
async function cmdClaw(sub, args, global) {
|
|
541
802
|
const flags = parseFlags(args);
|
|
542
803
|
const { client } = await makeClient(global);
|
|
@@ -1270,7 +1531,7 @@ async function cmdPayment(sub, args, global) {
|
|
|
1270
1531
|
const flags = parseFlags(args);
|
|
1271
1532
|
if (sub === 'bridge-info' || sub === 'bridge' || sub === 'prepare') {
|
|
1272
1533
|
const result = await getAlipayWalletBridgeInfo({ timeoutMs: global.timeoutMs });
|
|
1273
|
-
const businessSession = resolvePaymentBusinessSession({});
|
|
1534
|
+
const businessSession = await resolvePaymentBusinessSession({});
|
|
1274
1535
|
print({
|
|
1275
1536
|
...result,
|
|
1276
1537
|
hostSessionContract: hostSessionContractStatus(businessSession?.error ? null : businessSession)
|
|
@@ -1298,9 +1559,9 @@ async function cmdPayment(sub, args, global) {
|
|
|
1298
1559
|
if (sub === 'pay') {
|
|
1299
1560
|
const resourceUrl = requireArg(flags['resource-url'] || flags.resourceUrl || flags.r, '--resource-url');
|
|
1300
1561
|
const intentSummary = requireArg(flags['intent-summary'] || flags.intentSummary || flags.i, '--intent-summary');
|
|
1301
|
-
const businessSession = resolvePaymentBusinessSession(flags);
|
|
1562
|
+
const businessSession = await resolvePaymentBusinessSession(flags);
|
|
1302
1563
|
if (businessSession?.error === 'host_session_override_forbidden') {
|
|
1303
|
-
print(hostBusinessSessionOverrideForbiddenResult(), global);
|
|
1564
|
+
print(await hostBusinessSessionOverrideForbiddenResult(), global);
|
|
1304
1565
|
process.exitCode = EXIT_RUNTIME;
|
|
1305
1566
|
return;
|
|
1306
1567
|
}
|
|
@@ -1561,6 +1822,9 @@ async function main() {
|
|
|
1561
1822
|
if (command === 'whoami') return await cmdWhoami(global);
|
|
1562
1823
|
if (command === 'logout') return await cmdLogout(global);
|
|
1563
1824
|
if (command === 'connections' || command === 'connection') return await cmdConnections(sub, args, global);
|
|
1825
|
+
if (command === 'connectors') return await cmdConnectors(sub, args, global);
|
|
1826
|
+
if (command === 'runs') return await cmdRuns(sub, args, global);
|
|
1827
|
+
if (command === 'runtime') return await cmdRuntime(sub, args, global);
|
|
1564
1828
|
if (command === 'claw') return await cmdClaw(sub, args, global);
|
|
1565
1829
|
if (command === 'skills' || command === 'skill') return await cmdSkills(sub, args, global);
|
|
1566
1830
|
if (command === 'agent' || command === 'agents') return await cmdAgent(sub, args, global);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xiashe/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35-superconnector.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"xiashe": "bin/xiashe.mjs"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"README.md"
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@xiashe/sdk": "0.1.
|
|
13
|
+
"@xiashe/sdk": "0.1.35-superconnector.2"
|
|
14
14
|
},
|
|
15
15
|
"engines": {
|
|
16
16
|
"node": ">=20"
|