@xiashe/cli 0.1.34 → 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.
Files changed (3) hide show
  1. package/README.md +87 -0
  2. package/bin/xiashe.mjs +225 -1
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -58,3 +58,90 @@ Production defaults:
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
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,
@@ -81,6 +91,41 @@ Usage:
81
91
  ${c} config path|get|set <key> <value>|use <profile>
82
92
 
83
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>]
84
129
  ${c} claw pair --connection <id-or-name>
85
130
  ${c} claw repair --connection <id-or-name>
86
131
  ${c} claw check --connection <id-or-name>
@@ -577,6 +622,182 @@ async function cmdConnections(sub, _args, global) {
577
622
  ]);
578
623
  }
579
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
+
580
801
  async function cmdClaw(sub, args, global) {
581
802
  const flags = parseFlags(args);
582
803
  const { client } = await makeClient(global);
@@ -1601,6 +1822,9 @@ async function main() {
1601
1822
  if (command === 'whoami') return await cmdWhoami(global);
1602
1823
  if (command === 'logout') return await cmdLogout(global);
1603
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);
1604
1828
  if (command === 'claw') return await cmdClaw(sub, args, global);
1605
1829
  if (command === 'skills' || command === 'skill') return await cmdSkills(sub, args, global);
1606
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.34",
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.34"
13
+ "@xiashe/sdk": "0.1.35-superconnector.2"
14
14
  },
15
15
  "engines": {
16
16
  "node": ">=20"