@wayai/cli 0.3.135 → 0.3.136
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/index.js +1522 -71
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7546,6 +7546,20 @@ var init_contracts = __esm({
|
|
|
7546
7546
|
production_bases: external_exports.boolean(),
|
|
7547
7547
|
/** Opaque to Rekor; compared for equality only, to reset `usage:` counters (§2.3). */
|
|
7548
7548
|
window_key: external_exports.string().min(1),
|
|
7549
|
+
/**
|
|
7550
|
+
* The window's TRUE lower bound, for the reconcile's `operations_log` sum (§2.2).
|
|
7551
|
+
*
|
|
7552
|
+
* OPTIONAL, and that is not a rollout convenience — it is what "never gates" means
|
|
7553
|
+
* on the writer's side. The tier sources can be absent (a paid row carrying
|
|
7554
|
+
* `current_period_end` with no `current_period_start`) and inverted pairs are a
|
|
7555
|
+
* §2.2 diagnostic, so requiring it here would let an inert field throw the strict
|
|
7556
|
+
* parse and leave the org with NO projection — permanently stale under §2.3, with
|
|
7557
|
+
* §2.5's fail-closed gates refusing base creation and 503-ing every import. The
|
|
7558
|
+
* writer emits it whenever it has a sound value and omits it otherwise; Rekor's
|
|
7559
|
+
* observed-flip fallback covers the gap, and rollout step 3 keeps that fallback
|
|
7560
|
+
* for exactly this reason.
|
|
7561
|
+
*/
|
|
7562
|
+
window_start: external_exports.string().datetime().optional(),
|
|
7549
7563
|
/** The sole staleness authority (§2.3). Never triggers a counter reset. */
|
|
7550
7564
|
window_resets_at: external_exports.string().datetime()
|
|
7551
7565
|
}).strict();
|
|
@@ -8700,7 +8714,8 @@ __export(api_client_exports, {
|
|
|
8700
8714
|
ApiClient: () => ApiClient,
|
|
8701
8715
|
ApiError: () => ApiError,
|
|
8702
8716
|
dataErrorMessage: () => dataErrorMessage,
|
|
8703
|
-
toDataProxyPath: () => toDataProxyPath
|
|
8717
|
+
toDataProxyPath: () => toDataProxyPath,
|
|
8718
|
+
withOrgSelector: () => withOrgSelector
|
|
8704
8719
|
});
|
|
8705
8720
|
function isRetryableErrorBody(body) {
|
|
8706
8721
|
try {
|
|
@@ -8716,6 +8731,11 @@ function toDataProxyPath(v1Path) {
|
|
|
8716
8731
|
}
|
|
8717
8732
|
return `${DATA_PROXY_PREFIX}${v1Path.slice(REKOR_V1_PREFIX.length)}`;
|
|
8718
8733
|
}
|
|
8734
|
+
function withOrgSelector(path31, orgId) {
|
|
8735
|
+
if (!orgId) return path31;
|
|
8736
|
+
const separator = path31.includes("?") ? "&" : "?";
|
|
8737
|
+
return `${path31}${separator}${DATA_PROXY_ORG_QUERY_PARAM}=${encodeURIComponent(orgId)}`;
|
|
8738
|
+
}
|
|
8719
8739
|
function dataErrorMessage(err) {
|
|
8720
8740
|
if (!(err instanceof ApiError)) return null;
|
|
8721
8741
|
let parsed;
|
|
@@ -9328,12 +9348,12 @@ var init_api_client = __esm({
|
|
|
9328
9348
|
`/api/admin/data-explorer/debug/observability/${encodeURIComponent(hubId)}/conversations/${encodeURIComponent(conversationId)}${qs}`
|
|
9329
9349
|
);
|
|
9330
9350
|
}
|
|
9331
|
-
async request(method, path31, body) {
|
|
9351
|
+
async request(method, path31, body, extraHeaders, contentType) {
|
|
9332
9352
|
addApiBreadcrumb(method, path31);
|
|
9333
9353
|
const url = `${this.apiUrl}${path31}`;
|
|
9334
9354
|
let refreshedOn401 = false;
|
|
9335
9355
|
for (let retry = 0; ; retry++) {
|
|
9336
|
-
let response = await this.send(url, method, body);
|
|
9356
|
+
let response = await this.send(url, method, body, extraHeaders, contentType);
|
|
9337
9357
|
if (response.status === 401 && this.onUnauthorized && !refreshedOn401) {
|
|
9338
9358
|
refreshedOn401 = true;
|
|
9339
9359
|
let refreshed;
|
|
@@ -9343,7 +9363,7 @@ var init_api_client = __esm({
|
|
|
9343
9363
|
}
|
|
9344
9364
|
if (refreshed) {
|
|
9345
9365
|
this.accessToken = refreshed;
|
|
9346
|
-
response = await this.send(url, method, body);
|
|
9366
|
+
response = await this.send(url, method, body, extraHeaders, contentType);
|
|
9347
9367
|
}
|
|
9348
9368
|
}
|
|
9349
9369
|
if (response.ok) {
|
|
@@ -9384,30 +9404,98 @@ var init_api_client = __esm({
|
|
|
9384
9404
|
* since it is WayAI's selector and not an input Rekor sees.
|
|
9385
9405
|
*/
|
|
9386
9406
|
async dataRequest(method, v1Path, body, orgId) {
|
|
9387
|
-
const separator = v1Path.includes("?") ? "&" : "?";
|
|
9388
|
-
const orgQuery = orgId ? `${separator}${DATA_PROXY_ORG_QUERY_PARAM}=${encodeURIComponent(orgId)}` : "";
|
|
9389
9407
|
const envelope = await this.request(
|
|
9390
9408
|
method,
|
|
9391
|
-
|
|
9409
|
+
withOrgSelector(toDataProxyPath(v1Path), orgId),
|
|
9392
9410
|
body
|
|
9393
9411
|
);
|
|
9394
9412
|
return envelope ?? {};
|
|
9395
9413
|
}
|
|
9414
|
+
/**
|
|
9415
|
+
* Upload raw bytes to a Data `/v1` path — file content and record
|
|
9416
|
+
* attachments, the two places that surface takes a body which is not JSON.
|
|
9417
|
+
* `extraHeaders` carries the surface's own metadata headers, which are
|
|
9418
|
+
* caller-supplied and so cannot displace the org selector or anything `send`
|
|
9419
|
+
* pins.
|
|
9420
|
+
*/
|
|
9421
|
+
async dataUpload(v1Path, bytes, contentType, orgId, extraHeaders) {
|
|
9422
|
+
const envelope = await this.request(
|
|
9423
|
+
"PUT",
|
|
9424
|
+
withOrgSelector(toDataProxyPath(v1Path), orgId),
|
|
9425
|
+
bytes,
|
|
9426
|
+
extraHeaders,
|
|
9427
|
+
// NOT a header on the map above: `send` pins the content type out of
|
|
9428
|
+
// caller reach, and takes it here so it always describes the real body.
|
|
9429
|
+
contentType
|
|
9430
|
+
);
|
|
9431
|
+
return envelope ?? {};
|
|
9432
|
+
}
|
|
9433
|
+
/**
|
|
9434
|
+
* Download a Data `/v1` path's raw bytes. Distinct from `dataRequest`, which
|
|
9435
|
+
* parses the JSON envelope: the response here is the stored blob itself, so
|
|
9436
|
+
* this reads `arrayBuffer()`. Single-refresh-on-401 like `request`, but no
|
|
9437
|
+
* transient-retry loop — re-streaming a blob is not worth a cold-start probe.
|
|
9438
|
+
*/
|
|
9439
|
+
async dataDownload(v1Path, orgId) {
|
|
9440
|
+
const path31 = withOrgSelector(toDataProxyPath(v1Path), orgId);
|
|
9441
|
+
addApiBreadcrumb("GET", path31);
|
|
9442
|
+
const url = `${this.apiUrl}${path31}`;
|
|
9443
|
+
let response = await this.send(url, "GET");
|
|
9444
|
+
if (response.status === 401 && this.onUnauthorized) {
|
|
9445
|
+
let refreshed;
|
|
9446
|
+
try {
|
|
9447
|
+
refreshed = await this.onUnauthorized();
|
|
9448
|
+
} catch {
|
|
9449
|
+
}
|
|
9450
|
+
if (refreshed) {
|
|
9451
|
+
this.accessToken = refreshed;
|
|
9452
|
+
response = await this.send(url, "GET");
|
|
9453
|
+
}
|
|
9454
|
+
}
|
|
9455
|
+
if (!response.ok) {
|
|
9456
|
+
throw new ApiError("GET", path31, response.status, await response.text());
|
|
9457
|
+
}
|
|
9458
|
+
return {
|
|
9459
|
+
bytes: new Uint8Array(await response.arrayBuffer()),
|
|
9460
|
+
contentType: response.headers.get("Content-Type") ?? "application/octet-stream"
|
|
9461
|
+
};
|
|
9462
|
+
}
|
|
9463
|
+
/**
|
|
9464
|
+
* The absolute URL of a Data `/v1` path, for handing the user a link they can
|
|
9465
|
+
* fetch themselves. Only the address — every request the CLI issues goes
|
|
9466
|
+
* through the methods above, which carry the session.
|
|
9467
|
+
*/
|
|
9468
|
+
dataUrl(v1Path, orgId) {
|
|
9469
|
+
return `${this.apiUrl}${withOrgSelector(toDataProxyPath(v1Path), orgId)}`;
|
|
9470
|
+
}
|
|
9396
9471
|
/** Issue a single authenticated request with the client's current token. */
|
|
9397
|
-
send(url, method, body) {
|
|
9472
|
+
send(url, method, body, extraHeaders, contentType) {
|
|
9398
9473
|
return fetch(url, {
|
|
9399
9474
|
method,
|
|
9400
9475
|
headers: {
|
|
9476
|
+
// Caller-supplied FIRST, so everything pinned below is out of their
|
|
9477
|
+
// reach: a metadata header cannot restate the credential or mislabel
|
|
9478
|
+
// the body.
|
|
9479
|
+
...extraHeaders,
|
|
9401
9480
|
Authorization: `Bearer ${this.accessToken}`,
|
|
9402
|
-
|
|
9403
|
-
//
|
|
9481
|
+
// The content type describes THIS body, so it is derived from the body
|
|
9482
|
+
// rather than accepted from `extraHeaders` — which is pinned out above,
|
|
9483
|
+
// and would otherwise be the one way to mislabel a JSON request.
|
|
9484
|
+
// `||`, not `??`: an empty content type is not a content type, and an
|
|
9485
|
+
// unlabelled body should fall back rather than announce nothing.
|
|
9486
|
+
"Content-Type": body instanceof Uint8Array ? contentType || "application/octet-stream" : "application/json",
|
|
9487
|
+
// Names the calling surface for the Data Worker's audit rows, which
|
|
9488
|
+
// record `cli` vs `api` vs `mcp` (contracts §1.4). A HINT, not an
|
|
9404
9489
|
// authorization input: any client can send it, so the backend must
|
|
9405
9490
|
// normalize it against what it knows about its own ingress rather than
|
|
9406
9491
|
// trust it. Nothing is granted or denied on its value; the Data Worker's
|
|
9407
9492
|
// audit rows are its consumer (contracts §1.4).
|
|
9408
9493
|
"X-WayAI-Client": "cli"
|
|
9409
9494
|
},
|
|
9410
|
-
|
|
9495
|
+
// Bytes go on the wire verbatim (file content, attachments); everything
|
|
9496
|
+
// else is JSON. Encoding a Uint8Array through JSON.stringify would send
|
|
9497
|
+
// `{"0":137,…}` — a corrupt upload rather than a failed one.
|
|
9498
|
+
body: !body ? void 0 : body instanceof Uint8Array ? body : JSON.stringify(body)
|
|
9411
9499
|
});
|
|
9412
9500
|
}
|
|
9413
9501
|
};
|
|
@@ -12849,6 +12937,20 @@ var init_dist = __esm({
|
|
|
12849
12937
|
production_bases: external_exports.boolean(),
|
|
12850
12938
|
/** Opaque to Rekor; compared for equality only, to reset `usage:` counters (§2.3). */
|
|
12851
12939
|
window_key: external_exports.string().min(1),
|
|
12940
|
+
/**
|
|
12941
|
+
* The window's TRUE lower bound, for the reconcile's `operations_log` sum (§2.2).
|
|
12942
|
+
*
|
|
12943
|
+
* OPTIONAL, and that is not a rollout convenience — it is what "never gates" means
|
|
12944
|
+
* on the writer's side. The tier sources can be absent (a paid row carrying
|
|
12945
|
+
* `current_period_end` with no `current_period_start`) and inverted pairs are a
|
|
12946
|
+
* §2.2 diagnostic, so requiring it here would let an inert field throw the strict
|
|
12947
|
+
* parse and leave the org with NO projection — permanently stale under §2.3, with
|
|
12948
|
+
* §2.5's fail-closed gates refusing base creation and 503-ing every import. The
|
|
12949
|
+
* writer emits it whenever it has a sound value and omits it otherwise; Rekor's
|
|
12950
|
+
* observed-flip fallback covers the gap, and rollout step 3 keeps that fallback
|
|
12951
|
+
* for exactly this reason.
|
|
12952
|
+
*/
|
|
12953
|
+
window_start: external_exports.string().datetime().optional(),
|
|
12852
12954
|
/** The sole staleness authority (§2.3). Never triggers a counter reset. */
|
|
12853
12955
|
window_resets_at: external_exports.string().datetime()
|
|
12854
12956
|
}).strict();
|
|
@@ -13979,6 +14081,18 @@ var init_dist = __esm({
|
|
|
13979
14081
|
}
|
|
13980
14082
|
});
|
|
13981
14083
|
|
|
14084
|
+
// src/lib/expected.ts
|
|
14085
|
+
function expected(message) {
|
|
14086
|
+
const err = new Error(message);
|
|
14087
|
+
err.isExpected = true;
|
|
14088
|
+
return err;
|
|
14089
|
+
}
|
|
14090
|
+
var init_expected = __esm({
|
|
14091
|
+
"src/lib/expected.ts"() {
|
|
14092
|
+
"use strict";
|
|
14093
|
+
}
|
|
14094
|
+
});
|
|
14095
|
+
|
|
13982
14096
|
// src/lib/layout.ts
|
|
13983
14097
|
import * as fs from "fs";
|
|
13984
14098
|
import * as path from "path";
|
|
@@ -14700,11 +14814,31 @@ function isNewerVersion(latest, current) {
|
|
|
14700
14814
|
}
|
|
14701
14815
|
return false;
|
|
14702
14816
|
}
|
|
14817
|
+
function resolveSecretSource(source) {
|
|
14818
|
+
if (source.stdin && source.prompt) {
|
|
14819
|
+
throw expected(`${source.stdinFlag} and ${source.promptHint} are mutually exclusive \u2014 pass one.`);
|
|
14820
|
+
}
|
|
14821
|
+
if (source.stdin) {
|
|
14822
|
+
if (process.stdin.isTTY) {
|
|
14823
|
+
throw expected(
|
|
14824
|
+
`${source.stdinFlag} needs piped input. Pipe it \u2014 printf %s "$SECRET" | wayai \u2026 ${source.stdinFlag} \u2014 or ${source.promptHint}.`
|
|
14825
|
+
);
|
|
14826
|
+
}
|
|
14827
|
+
return "stdin";
|
|
14828
|
+
}
|
|
14829
|
+
if (!process.stdin.isTTY) {
|
|
14830
|
+
throw expected(
|
|
14831
|
+
`A secret cannot be prompted for when stdin is not a terminal. Pipe it instead: printf %s "$SECRET" | wayai \u2026 ${source.stdinFlag}`
|
|
14832
|
+
);
|
|
14833
|
+
}
|
|
14834
|
+
return "prompt";
|
|
14835
|
+
}
|
|
14703
14836
|
var UUID_RE2, slugify, OWN_HELP_COMMANDS;
|
|
14704
14837
|
var init_utils = __esm({
|
|
14705
14838
|
"src/lib/utils.ts"() {
|
|
14706
14839
|
"use strict";
|
|
14707
14840
|
init_dist();
|
|
14841
|
+
init_expected();
|
|
14708
14842
|
UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14709
14843
|
slugify = slugifySkillName;
|
|
14710
14844
|
OWN_HELP_COMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -14789,7 +14923,7 @@ var init_registry = __esm({
|
|
|
14789
14923
|
disposition: "top-level",
|
|
14790
14924
|
surviving: "records",
|
|
14791
14925
|
clause: 2,
|
|
14792
|
-
shipped:
|
|
14926
|
+
shipped: true,
|
|
14793
14927
|
reason: "Ontology entity. No WayAI command of this name."
|
|
14794
14928
|
},
|
|
14795
14929
|
{
|
|
@@ -14797,7 +14931,7 @@ var init_registry = __esm({
|
|
|
14797
14931
|
disposition: "top-level",
|
|
14798
14932
|
surviving: "record-types",
|
|
14799
14933
|
clause: 2,
|
|
14800
|
-
shipped:
|
|
14934
|
+
shipped: true,
|
|
14801
14935
|
reason: "Ontology entity."
|
|
14802
14936
|
},
|
|
14803
14937
|
{
|
|
@@ -14805,7 +14939,7 @@ var init_registry = __esm({
|
|
|
14805
14939
|
disposition: "top-level",
|
|
14806
14940
|
surviving: "relationships",
|
|
14807
14941
|
clause: 2,
|
|
14808
|
-
shipped:
|
|
14942
|
+
shipped: true,
|
|
14809
14943
|
reason: "Ontology entity."
|
|
14810
14944
|
},
|
|
14811
14945
|
{
|
|
@@ -14813,7 +14947,7 @@ var init_registry = __esm({
|
|
|
14813
14947
|
disposition: "top-level",
|
|
14814
14948
|
surviving: "relationship-types",
|
|
14815
14949
|
clause: 2,
|
|
14816
|
-
shipped:
|
|
14950
|
+
shipped: true,
|
|
14817
14951
|
reason: "Ontology entity."
|
|
14818
14952
|
},
|
|
14819
14953
|
{
|
|
@@ -14821,7 +14955,7 @@ var init_registry = __esm({
|
|
|
14821
14955
|
disposition: "top-level",
|
|
14822
14956
|
surviving: "query-relationships",
|
|
14823
14957
|
clause: 2,
|
|
14824
|
-
shipped:
|
|
14958
|
+
shipped: true,
|
|
14825
14959
|
reason: "Ontology traversal over relationships."
|
|
14826
14960
|
},
|
|
14827
14961
|
{
|
|
@@ -14829,7 +14963,7 @@ var init_registry = __esm({
|
|
|
14829
14963
|
disposition: "top-level",
|
|
14830
14964
|
surviving: "files",
|
|
14831
14965
|
clause: 2,
|
|
14832
|
-
shipped:
|
|
14966
|
+
shipped: true,
|
|
14833
14967
|
reason: "Unambiguous: WayAI has no `files` command \u2014 hub-local resource files are reached through hub config-as-code, and the two file surfaces stay deliberately separate."
|
|
14834
14968
|
},
|
|
14835
14969
|
{
|
|
@@ -14837,7 +14971,7 @@ var init_registry = __esm({
|
|
|
14837
14971
|
disposition: "top-level",
|
|
14838
14972
|
surviving: "file-types",
|
|
14839
14973
|
clause: 2,
|
|
14840
|
-
shipped:
|
|
14974
|
+
shipped: true,
|
|
14841
14975
|
reason: "Ontology entity."
|
|
14842
14976
|
},
|
|
14843
14977
|
{
|
|
@@ -14845,7 +14979,7 @@ var init_registry = __esm({
|
|
|
14845
14979
|
disposition: "top-level",
|
|
14846
14980
|
surviving: "attachments",
|
|
14847
14981
|
clause: 2,
|
|
14848
|
-
shipped:
|
|
14982
|
+
shipped: true,
|
|
14849
14983
|
reason: "Ontology entity."
|
|
14850
14984
|
},
|
|
14851
14985
|
{
|
|
@@ -14853,7 +14987,7 @@ var init_registry = __esm({
|
|
|
14853
14987
|
disposition: "top-level",
|
|
14854
14988
|
surviving: "toolsets",
|
|
14855
14989
|
clause: 2,
|
|
14856
|
-
shipped:
|
|
14990
|
+
shipped: true,
|
|
14857
14991
|
reason: "Ontology entity."
|
|
14858
14992
|
},
|
|
14859
14993
|
{
|
|
@@ -14861,7 +14995,7 @@ var init_registry = __esm({
|
|
|
14861
14995
|
disposition: "top-level",
|
|
14862
14996
|
surviving: "actions",
|
|
14863
14997
|
clause: 2,
|
|
14864
|
-
shipped:
|
|
14998
|
+
shipped: true,
|
|
14865
14999
|
reason: "Ontology entity."
|
|
14866
15000
|
},
|
|
14867
15001
|
{
|
|
@@ -14869,7 +15003,7 @@ var init_registry = __esm({
|
|
|
14869
15003
|
disposition: "top-level",
|
|
14870
15004
|
surviving: "triggers",
|
|
14871
15005
|
clause: 2,
|
|
14872
|
-
shipped:
|
|
15006
|
+
shipped: true,
|
|
14873
15007
|
reason: "Ontology entity."
|
|
14874
15008
|
},
|
|
14875
15009
|
{
|
|
@@ -14877,7 +15011,7 @@ var init_registry = __esm({
|
|
|
14877
15011
|
disposition: "top-level",
|
|
14878
15012
|
surviving: "inbound-webhooks",
|
|
14879
15013
|
clause: 2,
|
|
14880
|
-
shipped:
|
|
15014
|
+
shipped: true,
|
|
14881
15015
|
reason: "Ontology entity."
|
|
14882
15016
|
},
|
|
14883
15017
|
{
|
|
@@ -14885,7 +15019,7 @@ var init_registry = __esm({
|
|
|
14885
15019
|
disposition: "top-level",
|
|
14886
15020
|
surviving: "seed",
|
|
14887
15021
|
clause: 2,
|
|
14888
|
-
shipped:
|
|
15022
|
+
shipped: true,
|
|
14889
15023
|
reason: "Ontology entity. `wayai status` vs `wayai seed lease status` differ by depth, not by word."
|
|
14890
15024
|
},
|
|
14891
15025
|
// --- Clause 3: namespaced. ---
|
|
@@ -15457,18 +15591,6 @@ var init_token_store = __esm({
|
|
|
15457
15591
|
}
|
|
15458
15592
|
});
|
|
15459
15593
|
|
|
15460
|
-
// src/lib/expected.ts
|
|
15461
|
-
function expected(message) {
|
|
15462
|
-
const err = new Error(message);
|
|
15463
|
-
err.isExpected = true;
|
|
15464
|
-
return err;
|
|
15465
|
-
}
|
|
15466
|
-
var init_expected = __esm({
|
|
15467
|
-
"src/lib/expected.ts"() {
|
|
15468
|
-
"use strict";
|
|
15469
|
-
}
|
|
15470
|
-
});
|
|
15471
|
-
|
|
15472
15594
|
// src/lib/auth.ts
|
|
15473
15595
|
var auth_exports = {};
|
|
15474
15596
|
__export(auth_exports, {
|
|
@@ -17011,7 +17133,7 @@ function rewriteEvalAttachmentsToLocalPaths(payload) {
|
|
|
17011
17133
|
return base === "" || base === "." || base === ".." ? ref.hash.slice(0, 16) : base;
|
|
17012
17134
|
};
|
|
17013
17135
|
const hashesByName = /* @__PURE__ */ new Map();
|
|
17014
|
-
const
|
|
17136
|
+
const collect2 = (turn) => {
|
|
17015
17137
|
if (!Array.isArray(turn.attachments)) return;
|
|
17016
17138
|
for (const ref of turn.attachments) {
|
|
17017
17139
|
if (!ref?.hash || !ref.file_name) continue;
|
|
@@ -17024,7 +17146,7 @@ function rewriteEvalAttachmentsToLocalPaths(payload) {
|
|
|
17024
17146
|
set.add(ref.hash);
|
|
17025
17147
|
}
|
|
17026
17148
|
};
|
|
17027
|
-
forEachAttachableTurn(payload,
|
|
17149
|
+
forEachAttachableTurn(payload, collect2);
|
|
17028
17150
|
const pathByKey = /* @__PURE__ */ new Map();
|
|
17029
17151
|
const usedLower = /* @__PURE__ */ new Set();
|
|
17030
17152
|
const localPathFor = (ref) => {
|
|
@@ -22512,11 +22634,19 @@ async function updateCredentialCommand(args2) {
|
|
|
22512
22634
|
const body = {};
|
|
22513
22635
|
if (wantsSecret) {
|
|
22514
22636
|
let input;
|
|
22515
|
-
|
|
22516
|
-
|
|
22517
|
-
|
|
22518
|
-
|
|
22519
|
-
|
|
22637
|
+
let secretSource;
|
|
22638
|
+
try {
|
|
22639
|
+
secretSource = resolveSecretSource({
|
|
22640
|
+
stdin: parsed.stdin,
|
|
22641
|
+
prompt: parsed.secretPrompt,
|
|
22642
|
+
stdinFlag: "--stdin",
|
|
22643
|
+
promptHint: "use --secret for an interactive masked prompt"
|
|
22644
|
+
});
|
|
22645
|
+
} catch (err) {
|
|
22646
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
22647
|
+
process.exit(1);
|
|
22648
|
+
}
|
|
22649
|
+
if (secretSource === "stdin") {
|
|
22520
22650
|
input = await readStdin();
|
|
22521
22651
|
} else if (authType === "basic_auth") {
|
|
22522
22652
|
const username = await prompt("Enter username: ");
|
|
@@ -24868,6 +24998,16 @@ async function createDataClient(orgId) {
|
|
|
24868
24998
|
seen.add(cursor);
|
|
24869
24999
|
}
|
|
24870
25000
|
return all;
|
|
25001
|
+
},
|
|
25002
|
+
async upload(v1Path, bytes, contentType, headers) {
|
|
25003
|
+
const envelope = await api.dataUpload(v1Path, bytes, contentType, org, headers);
|
|
25004
|
+
return envelope.data;
|
|
25005
|
+
},
|
|
25006
|
+
download(v1Path) {
|
|
25007
|
+
return api.dataDownload(v1Path, org);
|
|
25008
|
+
},
|
|
25009
|
+
url(v1Path) {
|
|
25010
|
+
return api.dataUrl(v1Path, org);
|
|
24871
25011
|
}
|
|
24872
25012
|
};
|
|
24873
25013
|
}
|
|
@@ -24977,29 +25117,249 @@ function pathSegment(id, label = "id") {
|
|
|
24977
25117
|
}
|
|
24978
25118
|
return encodeURIComponent(id);
|
|
24979
25119
|
}
|
|
25120
|
+
function foreignSegment(value, label = "id") {
|
|
25121
|
+
if (value === "." || value === "..") {
|
|
25122
|
+
throw expected(`Invalid ${label}: ${JSON.stringify(value)} is a path traversal segment.`);
|
|
25123
|
+
}
|
|
25124
|
+
return encodeURIComponent(value);
|
|
25125
|
+
}
|
|
25126
|
+
function pathSegments(value, label = "path") {
|
|
25127
|
+
return value.split("/").map((segment) => foreignSegment(segment, label)).join("/");
|
|
25128
|
+
}
|
|
24980
25129
|
function parseData(data) {
|
|
24981
25130
|
if (data.startsWith("@")) {
|
|
24982
25131
|
return JSON.parse(readFileSync19(data.slice(1), "utf-8"));
|
|
24983
25132
|
}
|
|
24984
25133
|
return JSON.parse(data);
|
|
24985
25134
|
}
|
|
25135
|
+
function toolsetMcpUrl(slug) {
|
|
25136
|
+
return `https://data-mcp.wayai.pro/t/${slug}/mcp`;
|
|
25137
|
+
}
|
|
24986
25138
|
function globals(cmd) {
|
|
24987
25139
|
let namespace = cmd;
|
|
24988
25140
|
while (namespace.parent?.parent) namespace = namespace.parent;
|
|
24989
25141
|
return namespace.opts();
|
|
24990
25142
|
}
|
|
25143
|
+
function findBase(cmd) {
|
|
25144
|
+
return globals(cmd).base;
|
|
25145
|
+
}
|
|
25146
|
+
function requireBase(cmd) {
|
|
25147
|
+
const base = findBase(cmd) ?? process.env.WAYAI_BASE ?? "";
|
|
25148
|
+
if (base) return base;
|
|
25149
|
+
console.error("Error: --base is required (or set WAYAI_BASE)");
|
|
25150
|
+
return process.exit(1);
|
|
25151
|
+
}
|
|
24991
25152
|
function outputFormat(cmd) {
|
|
24992
25153
|
const opts = globals(cmd);
|
|
24993
25154
|
return opts.json || opts.output === "json" ? "json" : "table";
|
|
24994
25155
|
}
|
|
25156
|
+
function historyQuery(opts) {
|
|
25157
|
+
const qs = new URLSearchParams();
|
|
25158
|
+
if (opts.limit) qs.set("limit", opts.limit);
|
|
25159
|
+
if (opts.offset) qs.set("offset", opts.offset);
|
|
25160
|
+
if (opts.diff) qs.set("diff", "true");
|
|
25161
|
+
const q = qs.toString();
|
|
25162
|
+
return q ? `?${q}` : "";
|
|
25163
|
+
}
|
|
24995
25164
|
function splitList(value) {
|
|
24996
25165
|
return value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
24997
25166
|
}
|
|
25167
|
+
function parseByteCount(flag, value) {
|
|
25168
|
+
const n = Number(value);
|
|
25169
|
+
if (!Number.isInteger(n) || n < 0) {
|
|
25170
|
+
throw expected(`${flag} must be a whole number of bytes (0 = unlimited), not ${JSON.stringify(value)}.`);
|
|
25171
|
+
}
|
|
25172
|
+
return n;
|
|
25173
|
+
}
|
|
25174
|
+
async function readSecret(source, label) {
|
|
25175
|
+
const value = resolveSecretSource(source) === "stdin" ? (await readStdin()).trim() : (await promptSecret(`${label}: `)).trim();
|
|
25176
|
+
if (!value) throw expected(`${label} is required.`);
|
|
25177
|
+
return value;
|
|
25178
|
+
}
|
|
24998
25179
|
var init_helpers = __esm({
|
|
24999
25180
|
"src/data/helpers.ts"() {
|
|
25000
25181
|
"use strict";
|
|
25001
25182
|
init_base_id();
|
|
25002
25183
|
init_expected();
|
|
25184
|
+
init_utils();
|
|
25185
|
+
}
|
|
25186
|
+
});
|
|
25187
|
+
|
|
25188
|
+
// src/data/commands/actions.ts
|
|
25189
|
+
import { Command } from "commander";
|
|
25190
|
+
function buildActionsCommand() {
|
|
25191
|
+
const actions = new Command("actions").description(
|
|
25192
|
+
"Manage Actions \u2014 reusable, named definitions: one record_type + one operation, or a composite of atomic write steps (--config with `steps`)"
|
|
25193
|
+
);
|
|
25194
|
+
actions.command("upsert <id>").description(
|
|
25195
|
+
"Create or update an Action \u2014 one record_type + one operation, or a composite (--config with `steps`)"
|
|
25196
|
+
).option(
|
|
25197
|
+
"--record-type <record_type>",
|
|
25198
|
+
"The record_type this action operates over (single-op; omit for a composite)"
|
|
25199
|
+
).option(
|
|
25200
|
+
"--operation <op>",
|
|
25201
|
+
"The operation: create | get | list | update | delete (single-op; omit for a composite)"
|
|
25202
|
+
).option("--description <desc>", "Agent-facing description").option(
|
|
25203
|
+
"--config <json>",
|
|
25204
|
+
'Full Action config as JSON. Single-op: writable_fields, filterable_fields (per field: field (required), param, match, enum, pattern, optional, description \u2014 a declared field generates a required param unless optional: true; a range match is always optional), base_filter (a Filter DSL predicate merged server-side into every list call, invisible to the agent; list only, over a native record_type or a source-backed one whose list endpoint declares local_filters; the value "$now" resolves to the instant of each call, on a date-time field with a range op), precondition, binding, external_source, expose_*/default_* (machinery params are hidden unless expose_<param>: true). Composite: `steps` \u2014 an ordered list of atomic write steps ({key, record_type|rel_type, operation, writable_fields?, precondition?}) run in one transaction. Use @file.json to read from file.'
|
|
25205
|
+
).action(async function(id, opts) {
|
|
25206
|
+
let body;
|
|
25207
|
+
if (opts.config) {
|
|
25208
|
+
body = parseData(opts.config);
|
|
25209
|
+
if (opts.recordType) body.record_type = opts.recordType;
|
|
25210
|
+
if (opts.operation) body.operation = opts.operation;
|
|
25211
|
+
if (opts.description) body.description = opts.description;
|
|
25212
|
+
} else {
|
|
25213
|
+
if (!opts.recordType || !opts.operation) {
|
|
25214
|
+
throw expected("Provide --record-type and --operation (or --config <json>).");
|
|
25215
|
+
}
|
|
25216
|
+
body = { record_type: opts.recordType, operation: opts.operation };
|
|
25217
|
+
if (opts.description) body.description = opts.description;
|
|
25218
|
+
}
|
|
25219
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25220
|
+
const client = await createDataClient();
|
|
25221
|
+
printOutput(
|
|
25222
|
+
await client.request("PUT", `/v1/${base}/actions/${pathSegment(id, "action id")}`, body),
|
|
25223
|
+
outputFormat(this)
|
|
25224
|
+
);
|
|
25225
|
+
});
|
|
25226
|
+
actions.command("get <id>").description("Get an Action by id").action(async function(id) {
|
|
25227
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25228
|
+
const client = await createDataClient();
|
|
25229
|
+
printOutput(await client.request("GET", `/v1/${base}/actions/${pathSegment(id, "action id")}`), outputFormat(this));
|
|
25230
|
+
});
|
|
25231
|
+
actions.command("list").description("List Actions in this base").action(async function() {
|
|
25232
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25233
|
+
const client = await createDataClient();
|
|
25234
|
+
printOutput(await client.request("GET", `/v1/${base}/actions`), outputFormat(this));
|
|
25235
|
+
});
|
|
25236
|
+
actions.command("delete <id>").description("Delete an Action").option("-y, --yes", "Skip confirmation").action(async function(id, opts) {
|
|
25237
|
+
if (!opts.yes && !await confirm(`Delete action ${id}? This cannot be undone.`)) {
|
|
25238
|
+
console.log("Aborted.");
|
|
25239
|
+
return;
|
|
25240
|
+
}
|
|
25241
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25242
|
+
const client = await createDataClient();
|
|
25243
|
+
await client.request("DELETE", `/v1/${base}/actions/${pathSegment(id, "action id")}`);
|
|
25244
|
+
console.log(`Deleted action ${id}`);
|
|
25245
|
+
});
|
|
25246
|
+
return actions;
|
|
25247
|
+
}
|
|
25248
|
+
var init_actions = __esm({
|
|
25249
|
+
"src/data/commands/actions.ts"() {
|
|
25250
|
+
"use strict";
|
|
25251
|
+
init_expected();
|
|
25252
|
+
init_client();
|
|
25253
|
+
init_output();
|
|
25254
|
+
init_helpers();
|
|
25255
|
+
init_utils();
|
|
25256
|
+
}
|
|
25257
|
+
});
|
|
25258
|
+
|
|
25259
|
+
// src/data/commands/attachments.ts
|
|
25260
|
+
import { Command as Command2 } from "commander";
|
|
25261
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
25262
|
+
function findAttachmentByFilename(attachments, filename) {
|
|
25263
|
+
return attachments.find((a) => a.key.endsWith(`/${filename}`)) ?? null;
|
|
25264
|
+
}
|
|
25265
|
+
function uploadPathFrom(uploadUrl) {
|
|
25266
|
+
if (typeof uploadUrl !== "string") {
|
|
25267
|
+
throw expected(
|
|
25268
|
+
`The server returned an upload target this CLI will not send credentials to: ${String(uploadUrl)}`
|
|
25269
|
+
);
|
|
25270
|
+
}
|
|
25271
|
+
let resolved;
|
|
25272
|
+
try {
|
|
25273
|
+
resolved = new URL(toDataProxyPath(uploadUrl), CONTAINMENT_ORIGIN);
|
|
25274
|
+
} catch {
|
|
25275
|
+
throw expected(
|
|
25276
|
+
`The server returned an upload target this CLI will not send credentials to: ${uploadUrl}`
|
|
25277
|
+
);
|
|
25278
|
+
}
|
|
25279
|
+
if (resolved.origin !== CONTAINMENT_ORIGIN || !resolved.pathname.startsWith(`${DATA_PROXY_PREFIX}/`)) {
|
|
25280
|
+
throw expected(
|
|
25281
|
+
`The server returned an upload target this CLI will not send credentials to: ${uploadUrl}`
|
|
25282
|
+
);
|
|
25283
|
+
}
|
|
25284
|
+
return uploadUrl;
|
|
25285
|
+
}
|
|
25286
|
+
function buildAttachmentsCommand() {
|
|
25287
|
+
const attachments = new Command2("attachments").description("Manage record attachments");
|
|
25288
|
+
attachments.command("upload <record_type> <id>").description(
|
|
25289
|
+
"Get a presigned upload URL for a record attachment. With --file, uploads the file content in one step."
|
|
25290
|
+
).requiredOption("--filename <name>", "File name or path (e.g. docs/guide.md)").option("--content-type <type>", "MIME type", "application/octet-stream").option("--file <path>", "Local file to upload (skips presigned URL output, uploads directly)").action(async function(recordType2, id, opts) {
|
|
25291
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25292
|
+
const client = await createDataClient();
|
|
25293
|
+
const data = await client.request(
|
|
25294
|
+
"POST",
|
|
25295
|
+
`/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${pathSegment(id, "record id")}/attachments`,
|
|
25296
|
+
{ filename: opts.filename, content_type: opts.contentType }
|
|
25297
|
+
);
|
|
25298
|
+
if (!opts.file) {
|
|
25299
|
+
printOutput(data, outputFormat(this));
|
|
25300
|
+
return;
|
|
25301
|
+
}
|
|
25302
|
+
const body = readFileSync20(opts.file);
|
|
25303
|
+
await client.upload(uploadPathFrom(data?.upload_url), body, opts.contentType);
|
|
25304
|
+
printOutput({ ...data, uploaded: true }, outputFormat(this));
|
|
25305
|
+
});
|
|
25306
|
+
attachments.command("url <record_type> <id>").description("Get a download URL for an attachment by filename").requiredOption("--filename <name>", "File name or path (e.g. docs/guide.md)").action(async function(recordType2, id, opts) {
|
|
25307
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25308
|
+
const client = await createDataClient();
|
|
25309
|
+
const rows = await client.request(
|
|
25310
|
+
"GET",
|
|
25311
|
+
`/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${pathSegment(id, "record id")}/attachments`
|
|
25312
|
+
);
|
|
25313
|
+
const match = findAttachmentByFilename(rows ?? [], opts.filename);
|
|
25314
|
+
if (!match) {
|
|
25315
|
+
throw expected(`Attachment "${opts.filename}" not found`);
|
|
25316
|
+
}
|
|
25317
|
+
printOutput(
|
|
25318
|
+
{ download_url: client.url(`/v1/${base}/attachments/${pathSegments(match.key, "attachment key")}`), ...match },
|
|
25319
|
+
outputFormat(this)
|
|
25320
|
+
);
|
|
25321
|
+
});
|
|
25322
|
+
attachments.command("list <record_type> <id>").description("List attachments for a record").option("--prefix <path>", "Filter by path prefix (e.g. docs/)").action(async function(recordType2, id, opts) {
|
|
25323
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25324
|
+
const client = await createDataClient();
|
|
25325
|
+
const query = opts.prefix ? `?prefix=${encodeURIComponent(opts.prefix)}` : "";
|
|
25326
|
+
printOutput(
|
|
25327
|
+
await client.request(
|
|
25328
|
+
"GET",
|
|
25329
|
+
`/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${pathSegment(id, "record id")}/attachments${query}`
|
|
25330
|
+
),
|
|
25331
|
+
outputFormat(this)
|
|
25332
|
+
);
|
|
25333
|
+
});
|
|
25334
|
+
attachments.command("delete <record_type> <id> <attachment-id>").description("Delete an attachment").option("-y, --yes", "Skip confirmation prompt").action(async function(recordType2, id, attachmentId, opts) {
|
|
25335
|
+
if (!opts.yes && !await confirm(
|
|
25336
|
+
`Delete attachment ${attachmentId} on ${recordType2}/${id}? This cannot be undone.`
|
|
25337
|
+
)) {
|
|
25338
|
+
console.log("Aborted");
|
|
25339
|
+
return;
|
|
25340
|
+
}
|
|
25341
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25342
|
+
const client = await createDataClient();
|
|
25343
|
+
await client.request(
|
|
25344
|
+
"DELETE",
|
|
25345
|
+
`/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${pathSegment(id, "record id")}/attachments/${pathSegment(attachmentId, "attachment id")}`
|
|
25346
|
+
);
|
|
25347
|
+
console.log("Deleted");
|
|
25348
|
+
});
|
|
25349
|
+
return attachments;
|
|
25350
|
+
}
|
|
25351
|
+
var CONTAINMENT_ORIGIN;
|
|
25352
|
+
var init_attachments = __esm({
|
|
25353
|
+
"src/data/commands/attachments.ts"() {
|
|
25354
|
+
"use strict";
|
|
25355
|
+
init_expected();
|
|
25356
|
+
init_contracts();
|
|
25357
|
+
init_api_client();
|
|
25358
|
+
init_client();
|
|
25359
|
+
init_output();
|
|
25360
|
+
init_helpers();
|
|
25361
|
+
init_utils();
|
|
25362
|
+
CONTAINMENT_ORIGIN = "https://containment.invalid";
|
|
25003
25363
|
}
|
|
25004
25364
|
});
|
|
25005
25365
|
|
|
@@ -25029,7 +25389,7 @@ var init_base_binding = __esm({
|
|
|
25029
25389
|
});
|
|
25030
25390
|
|
|
25031
25391
|
// src/data/commands/bases.ts
|
|
25032
|
-
import { Command } from "commander";
|
|
25392
|
+
import { Command as Command3 } from "commander";
|
|
25033
25393
|
import * as fs24 from "fs";
|
|
25034
25394
|
import * as path30 from "path";
|
|
25035
25395
|
import * as yaml9 from "js-yaml";
|
|
@@ -25045,7 +25405,7 @@ function parseEnum(flag, value, allowed) {
|
|
|
25045
25405
|
return value;
|
|
25046
25406
|
}
|
|
25047
25407
|
function buildBasesCommand() {
|
|
25048
|
-
const bases = new
|
|
25408
|
+
const bases = new Command3("bases").description("Manage bases");
|
|
25049
25409
|
bases.command("list").description("List all bases").option("--tag <tag>", "Filter by tag").action(async function(opts) {
|
|
25050
25410
|
const client = await createDataClient();
|
|
25051
25411
|
const qs = opts.tag ? `?tag=${encodeURIComponent(opts.tag)}` : "";
|
|
@@ -25287,32 +25647,1105 @@ var init_bases = __esm({
|
|
|
25287
25647
|
}
|
|
25288
25648
|
});
|
|
25289
25649
|
|
|
25290
|
-
// src/data/
|
|
25291
|
-
|
|
25292
|
-
|
|
25293
|
-
|
|
25294
|
-
|
|
25295
|
-
|
|
25296
|
-
|
|
25297
|
-
|
|
25298
|
-
|
|
25650
|
+
// src/data/commands/file-types.ts
|
|
25651
|
+
import { Command as Command4 } from "commander";
|
|
25652
|
+
function buildFileTypesCommand() {
|
|
25653
|
+
const fileTypes = new Command4("file-types").description(
|
|
25654
|
+
"Manage file types (Buckets) \u2014 storage policy + optional metadata schema for files"
|
|
25655
|
+
);
|
|
25656
|
+
fileTypes.command("list").description("List all file types in a base").action(async function() {
|
|
25657
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25658
|
+
const client = await createDataClient();
|
|
25659
|
+
printOutput(await client.request("GET", `/v1/${base}/file-types`), outputFormat(this));
|
|
25660
|
+
});
|
|
25661
|
+
fileTypes.command("get <id>").description("Get a file type").action(async function(id) {
|
|
25662
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25663
|
+
const client = await createDataClient();
|
|
25664
|
+
printOutput(await client.request("GET", `/v1/${base}/file-types/${pathSegment(id, "file_type")}`), outputFormat(this));
|
|
25665
|
+
});
|
|
25666
|
+
fileTypes.command("upsert <id>").description("Create or update a file type (preview bases only)").requiredOption("--name <name>", "File type name").option("--description <desc>", "Description").option("--max-size <bytes>", "Max bytes per file (0 = unlimited)").option(
|
|
25667
|
+
"--allowed-content-types <json>",
|
|
25668
|
+
"Allowed content-types, JSON array (inline or @filename)"
|
|
25669
|
+
).option("--metadata-schema <json>", "JSON Schema for file metadata (inline JSON or @filename)").action(async function(id, opts) {
|
|
25670
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25671
|
+
const client = await createDataClient();
|
|
25672
|
+
const body = { name: opts.name };
|
|
25673
|
+
if (opts.description) body.description = opts.description;
|
|
25674
|
+
if (opts.maxSize !== void 0) body.max_size = parseByteCount("--max-size", opts.maxSize);
|
|
25675
|
+
if (opts.allowedContentTypes) {
|
|
25676
|
+
body.allowed_content_types = parseData(opts.allowedContentTypes);
|
|
25677
|
+
}
|
|
25678
|
+
if (opts.metadataSchema) body.metadata_schema = parseData(opts.metadataSchema);
|
|
25679
|
+
printOutput(
|
|
25680
|
+
await client.request("PUT", `/v1/${base}/file-types/${pathSegment(id, "file_type")}`, body),
|
|
25681
|
+
outputFormat(this)
|
|
25682
|
+
);
|
|
25683
|
+
});
|
|
25684
|
+
fileTypes.command("delete <id>").description("Delete a file type (cascades its files)").option("-y, --yes", "Skip confirmation prompt").action(async function(id, opts) {
|
|
25685
|
+
if (!opts.yes && !await confirm(
|
|
25686
|
+
`Delete file type "${id}"? This cascades its files and cannot be undone.`
|
|
25687
|
+
)) {
|
|
25688
|
+
console.log("Aborted");
|
|
25689
|
+
return;
|
|
25690
|
+
}
|
|
25691
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25692
|
+
const client = await createDataClient();
|
|
25693
|
+
await client.request("DELETE", `/v1/${base}/file-types/${pathSegment(id, "file_type")}`);
|
|
25694
|
+
console.log("Deleted");
|
|
25695
|
+
});
|
|
25696
|
+
return fileTypes;
|
|
25697
|
+
}
|
|
25698
|
+
var init_file_types = __esm({
|
|
25699
|
+
"src/data/commands/file-types.ts"() {
|
|
25700
|
+
"use strict";
|
|
25701
|
+
init_client();
|
|
25702
|
+
init_output();
|
|
25703
|
+
init_helpers();
|
|
25704
|
+
init_utils();
|
|
25705
|
+
}
|
|
25299
25706
|
});
|
|
25300
|
-
|
|
25301
|
-
|
|
25302
|
-
|
|
25707
|
+
|
|
25708
|
+
// src/data/commands/files.ts
|
|
25709
|
+
import { Command as Command5 } from "commander";
|
|
25710
|
+
import { readFileSync as readFileSync22, writeFileSync as writeFileSync15 } from "fs";
|
|
25711
|
+
import { basename as basename14 } from "path";
|
|
25712
|
+
function renderFileDiff(fileType, filePath, from, to, d) {
|
|
25713
|
+
console.log(sanitizeTerminalText(`${fileType}/${filePath}: v${from} \u2192 v${to}`));
|
|
25714
|
+
const md = d.metadata_delta;
|
|
25715
|
+
if (md) {
|
|
25716
|
+
for (const f of ["path", "size", "content_type", "label"]) {
|
|
25717
|
+
const change = md[f];
|
|
25718
|
+
if (change) console.log(sanitizeTerminalText(` ${f}: ${JSON.stringify(change.from)} \u2192 ${JSON.stringify(change.to)}`));
|
|
25719
|
+
}
|
|
25720
|
+
const meta = md.metadata;
|
|
25721
|
+
for (const [k, v] of Object.entries(meta?.added ?? {})) {
|
|
25722
|
+
console.log(sanitizeTerminalText(` metadata + ${k}: ${JSON.stringify(v)}`));
|
|
25723
|
+
}
|
|
25724
|
+
for (const k of Object.keys(meta?.removed ?? {})) console.log(sanitizeTerminalText(` metadata - ${k}`));
|
|
25725
|
+
for (const [k, v] of Object.entries(meta?.changed ?? {})) {
|
|
25726
|
+
console.log(sanitizeTerminalText(` metadata ~ ${k}: ${JSON.stringify(v.from)} \u2192 ${JSON.stringify(v.to)}`));
|
|
25727
|
+
}
|
|
25728
|
+
}
|
|
25729
|
+
const content = d.content;
|
|
25730
|
+
if (!content?.changed) {
|
|
25731
|
+
console.log(" content: unchanged");
|
|
25732
|
+
return;
|
|
25733
|
+
}
|
|
25734
|
+
if (content.kind === "text" && content.lines) {
|
|
25735
|
+
console.log("");
|
|
25736
|
+
for (const l of content.lines) console.log(sanitizeTerminalText(`${l.op} ${l.text}`));
|
|
25737
|
+
} else {
|
|
25738
|
+
console.log(sanitizeTerminalText(` content: changed (${content.kind})`));
|
|
25739
|
+
}
|
|
25303
25740
|
}
|
|
25304
|
-
function
|
|
25305
|
-
|
|
25741
|
+
function downloadTarget(remotePath, to) {
|
|
25742
|
+
if (to) return to;
|
|
25743
|
+
const derived = basename14(remotePath);
|
|
25744
|
+
if (derived === "" || derived === "." || derived === "..") {
|
|
25745
|
+
throw expected(
|
|
25746
|
+
`Cannot derive a local filename from "${remotePath}" \u2014 pass --to <local> to name it.`
|
|
25747
|
+
);
|
|
25748
|
+
}
|
|
25749
|
+
return derived;
|
|
25306
25750
|
}
|
|
25307
|
-
function
|
|
25308
|
-
|
|
25751
|
+
function buildFilesCommand() {
|
|
25752
|
+
const files = new Command5("files").description(
|
|
25753
|
+
"Manage files (path-addressed, versioned content) within a file type"
|
|
25754
|
+
);
|
|
25755
|
+
files.command("put <file_type> <path>").description(
|
|
25756
|
+
"Upload a local file to a path (e.g. wayai files put reports q3/summary.pdf --file ./summary.pdf)"
|
|
25757
|
+
).requiredOption("--file <local>", "Local file to upload").option("--content-type <type>", "MIME type", "application/octet-stream").action(async function(fileType, filePath, opts) {
|
|
25758
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25759
|
+
const body = readFileSync22(opts.file);
|
|
25760
|
+
const client = await createDataClient();
|
|
25761
|
+
printOutput(
|
|
25762
|
+
await client.upload(
|
|
25763
|
+
`/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath)}`,
|
|
25764
|
+
body,
|
|
25765
|
+
opts.contentType
|
|
25766
|
+
),
|
|
25767
|
+
outputFormat(this)
|
|
25768
|
+
);
|
|
25769
|
+
});
|
|
25770
|
+
files.command("get <file_type> <path>").description(
|
|
25771
|
+
"Download a file (or --meta for metadata only). --version N reads a specific retained content version."
|
|
25772
|
+
).option("--to <local>", "Local file to save to (defaults to the file basename)").option("--meta", "Print metadata JSON instead of downloading the content").option("--version <n>", "Read a specific content version (default: latest)").action(async function(fileType, filePath, opts) {
|
|
25773
|
+
const encoded = pathSegments(filePath);
|
|
25774
|
+
const versionQs = opts.version !== void 0 ? `version=${encodeURIComponent(opts.version)}` : "";
|
|
25775
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25776
|
+
if (opts.meta) {
|
|
25777
|
+
const qs = ["meta=1", versionQs].filter(Boolean).join("&");
|
|
25778
|
+
const client2 = await createDataClient();
|
|
25779
|
+
printOutput(
|
|
25780
|
+
await client2.request("GET", `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${encoded}?${qs}`),
|
|
25781
|
+
outputFormat(this)
|
|
25782
|
+
);
|
|
25783
|
+
return;
|
|
25784
|
+
}
|
|
25785
|
+
const out = downloadTarget(filePath, opts.to);
|
|
25786
|
+
const client = await createDataClient();
|
|
25787
|
+
const { bytes } = await client.download(
|
|
25788
|
+
`/v1/${base}/files/${pathSegment(fileType, "file_type")}/${encoded}${versionQs ? `?${versionQs}` : ""}`
|
|
25789
|
+
);
|
|
25790
|
+
writeFileSync15(out, bytes);
|
|
25791
|
+
console.log(`Downloaded to ${out}`);
|
|
25792
|
+
});
|
|
25793
|
+
files.command("history <file_type> <path>").description("List the content versions of a file (newest first)").option("--limit <n>", "Max versions to return").option("--offset <n>", "Pagination offset").action(async function(fileType, filePath, opts) {
|
|
25794
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25795
|
+
const client = await createDataClient();
|
|
25796
|
+
const qs = new URLSearchParams({ history: "1" });
|
|
25797
|
+
if (opts.limit) qs.set("limit", opts.limit);
|
|
25798
|
+
if (opts.offset) qs.set("offset", opts.offset);
|
|
25799
|
+
printOutput(
|
|
25800
|
+
await client.request(
|
|
25801
|
+
"GET",
|
|
25802
|
+
`/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath)}?${qs}`
|
|
25803
|
+
),
|
|
25804
|
+
outputFormat(this)
|
|
25805
|
+
);
|
|
25806
|
+
});
|
|
25807
|
+
files.command("diff <file_type> <path>").description("Diff two content versions of a file \u2014 metadata delta plus a text content diff").requiredOption("--from <n>", "Base version number").requiredOption("--to <n>", "Target version number").action(async function(fileType, filePath, opts) {
|
|
25808
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25809
|
+
const client = await createDataClient();
|
|
25810
|
+
const qs = new URLSearchParams({ diff: "1", from: opts.from, to: opts.to });
|
|
25811
|
+
const data = await client.request(
|
|
25812
|
+
"GET",
|
|
25813
|
+
`/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath)}?${qs}`
|
|
25814
|
+
);
|
|
25815
|
+
if (outputFormat(this) === "json") {
|
|
25816
|
+
printOutput(data, "json");
|
|
25817
|
+
return;
|
|
25818
|
+
}
|
|
25819
|
+
renderFileDiff(fileType, filePath, opts.from, opts.to, data);
|
|
25820
|
+
});
|
|
25821
|
+
files.command("list <file_type>").description("List files by path prefix").option("--prefix <path>", "Path prefix filter (e.g. q3/)").option("--depth <n>", "Max folder depth below the prefix (1 = immediate children)").option("--limit <n>", "Max results").option("--offset <n>", "Pagination offset").action(async function(fileType, opts) {
|
|
25822
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25823
|
+
const client = await createDataClient();
|
|
25824
|
+
const qs = new URLSearchParams();
|
|
25825
|
+
if (opts.prefix) qs.set("prefix", opts.prefix);
|
|
25826
|
+
if (opts.depth) qs.set("depth", opts.depth);
|
|
25827
|
+
if (opts.limit) qs.set("limit", opts.limit);
|
|
25828
|
+
if (opts.offset) qs.set("offset", opts.offset);
|
|
25829
|
+
const q = qs.toString();
|
|
25830
|
+
printOutput(
|
|
25831
|
+
await client.request("GET", `/v1/${base}/files/${pathSegment(fileType, "file_type")}${q ? `?${q}` : ""}`),
|
|
25832
|
+
outputFormat(this)
|
|
25833
|
+
);
|
|
25834
|
+
});
|
|
25835
|
+
files.command("mv <file_type> <from> <to>").description("Rename/move a file (the blob is untouched)").action(async function(fileType, from, to) {
|
|
25836
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25837
|
+
const client = await createDataClient();
|
|
25838
|
+
printOutput(
|
|
25839
|
+
await client.request("PATCH", `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(from)}`, {
|
|
25840
|
+
new_path: to
|
|
25841
|
+
}),
|
|
25842
|
+
outputFormat(this)
|
|
25843
|
+
);
|
|
25844
|
+
});
|
|
25845
|
+
files.command("rm <file_type> <path>").description("Delete a file").option("-y, --yes", "Skip confirmation prompt").action(async function(fileType, filePath, opts) {
|
|
25846
|
+
if (!opts.yes && !await confirm(`Delete file "${fileType}/${filePath}"? This cannot be undone.`)) {
|
|
25847
|
+
console.log("Aborted");
|
|
25848
|
+
return;
|
|
25849
|
+
}
|
|
25850
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25851
|
+
const client = await createDataClient();
|
|
25852
|
+
await client.request("DELETE", `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath)}`);
|
|
25853
|
+
console.log("Deleted");
|
|
25854
|
+
});
|
|
25855
|
+
files.command("mount <file_type>").description(
|
|
25856
|
+
"Mint an S3 credential so any harness can mount this file type as a filesystem (s3fs, cloud mount SDKs). Read-only by default; the secret is shown once."
|
|
25857
|
+
).option("--expires-in <seconds>", "Credential lifetime in seconds (default 30 days, max 90)").option(
|
|
25858
|
+
"--mode <mode>",
|
|
25859
|
+
"read_only (default) or read_write \u2014 the whole-bucket mode when no --path is given"
|
|
25860
|
+
).option(
|
|
25861
|
+
"--path <prefix>",
|
|
25862
|
+
"Confine to a path prefix (repeatable); optionally suffix :read_only|:read_write per prefix (e.g. drafts/:read_write)",
|
|
25863
|
+
(v, acc) => {
|
|
25864
|
+
acc.push(v);
|
|
25865
|
+
return acc;
|
|
25866
|
+
},
|
|
25867
|
+
[]
|
|
25868
|
+
).action(async function(fileType, opts) {
|
|
25869
|
+
const body = { file_type: fileType };
|
|
25870
|
+
if (opts.mode) {
|
|
25871
|
+
if (opts.mode !== "read_only" && opts.mode !== "read_write") {
|
|
25872
|
+
throw expected("--mode must be 'read_only' or 'read_write'.");
|
|
25873
|
+
}
|
|
25874
|
+
body.mode = opts.mode;
|
|
25875
|
+
}
|
|
25876
|
+
if (opts.path.length > 0) {
|
|
25877
|
+
body.paths = opts.path.map((p) => {
|
|
25878
|
+
const m = /^(.*):(read_only|read_write)$/.exec(p);
|
|
25879
|
+
return m ? { prefix: m[1], mode: m[2] } : { prefix: p, mode: opts.mode ?? "read_only" };
|
|
25880
|
+
});
|
|
25881
|
+
}
|
|
25882
|
+
if (opts.expiresIn !== void 0) {
|
|
25883
|
+
const n = Number(opts.expiresIn);
|
|
25884
|
+
if (!Number.isFinite(n)) {
|
|
25885
|
+
throw expected("--expires-in must be a number of seconds.");
|
|
25886
|
+
}
|
|
25887
|
+
body.expires_in = n;
|
|
25888
|
+
}
|
|
25889
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25890
|
+
const client = await createDataClient();
|
|
25891
|
+
printOutput(
|
|
25892
|
+
await client.request("POST", `/v1/${base}/s3-credentials`, body),
|
|
25893
|
+
outputFormat(this)
|
|
25894
|
+
);
|
|
25895
|
+
});
|
|
25896
|
+
return files;
|
|
25897
|
+
}
|
|
25898
|
+
var init_files = __esm({
|
|
25899
|
+
"src/data/commands/files.ts"() {
|
|
25900
|
+
"use strict";
|
|
25901
|
+
init_expected();
|
|
25902
|
+
init_client();
|
|
25903
|
+
init_output();
|
|
25904
|
+
init_helpers();
|
|
25905
|
+
init_utils();
|
|
25906
|
+
init_terminal_output();
|
|
25907
|
+
}
|
|
25908
|
+
});
|
|
25909
|
+
|
|
25910
|
+
// src/data/commands/inbound-webhooks.ts
|
|
25911
|
+
import { randomUUID } from "crypto";
|
|
25912
|
+
import { Command as Command6 } from "commander";
|
|
25913
|
+
function buildInboundWebhooksCommand() {
|
|
25914
|
+
const inboundWebhooks = new Command6("inbound-webhooks").description(
|
|
25915
|
+
"Manage inbound webhook endpoints"
|
|
25916
|
+
);
|
|
25917
|
+
inboundWebhooks.command("create").description("Create a new inbound webhook").requiredOption("--name <name>", "Inbound webhook name").option("--secret-stdin", "Read the HMAC shared secret from stdin (recommended for CI)").option("--id <id>", "Inbound webhook ID (auto-generated if omitted)").option("--record-type-scope <record_types>", "Comma-separated record_type scope").option(
|
|
25918
|
+
"--field-mapping <json>",
|
|
25919
|
+
'Inline mapping applied to the payload before write \u2014 a field_mapping JSON, e.g. {"to_external":{"status":"state"}} (to_external renames auto-invert on read); an explicit inbound-rename block and {"computed":{...}} are also accepted. Mutually exclusive with --source-binding.'
|
|
25920
|
+
).option(
|
|
25921
|
+
"--source-binding <json>",
|
|
25922
|
+
`Reuse a record_type source's field_mapping for the inbound translation \u2014 {"record_type":"<id>","source":"<name>"}. Mutually exclusive with --field-mapping.`
|
|
25923
|
+
).option(
|
|
25924
|
+
"--ingest-auth <json>",
|
|
25925
|
+
'Inbound auth scheme. Default (omitted) = HMAC signature. Static-header senders: {"type":"static_header","header":"X-Account-Key"} \u2014 the configured header is compared to the shared secret (constant-time) instead of an HMAC.'
|
|
25926
|
+
).option(
|
|
25927
|
+
"--hydration <json>",
|
|
25928
|
+
`Make this a reference-style ("notification + fetch") webhook: a thin delivery names a record id; the base fetches the full record via the bound source's read endpoint and stores it. Requires --source-binding and a single native --record-type-scope. JSON: {"id_path":"record_id","event_path":"event","event_map":{"ResourceDeleted":"delete"},"default_op":"upsert","merge":true}. Set "merge":true to refresh only the mapped (upstream-owned) fields on re-sync and preserve the locally-owned fields (status/tags/scores) on the same record.`
|
|
25929
|
+
).action(async function(opts) {
|
|
25930
|
+
const secret = await readSecret(
|
|
25931
|
+
{
|
|
25932
|
+
stdin: opts.secretStdin,
|
|
25933
|
+
// No prompt flag here — the prompt is this command's default.
|
|
25934
|
+
prompt: void 0,
|
|
25935
|
+
stdinFlag: "--secret-stdin",
|
|
25936
|
+
promptHint: "omit --secret-stdin to be prompted"
|
|
25937
|
+
},
|
|
25938
|
+
"HMAC shared secret"
|
|
25939
|
+
);
|
|
25940
|
+
const body = {
|
|
25941
|
+
name: opts.name,
|
|
25942
|
+
secret,
|
|
25943
|
+
enabled: true
|
|
25944
|
+
};
|
|
25945
|
+
if (opts.recordTypeScope) body.record_type_scope = splitList(opts.recordTypeScope);
|
|
25946
|
+
if (opts.fieldMapping) body.field_mapping = parseData(opts.fieldMapping);
|
|
25947
|
+
if (opts.sourceBinding) body.source_binding = parseData(opts.sourceBinding);
|
|
25948
|
+
if (opts.ingestAuth) body.ingest_auth = parseData(opts.ingestAuth);
|
|
25949
|
+
if (opts.hydration) body.hydration = parseData(opts.hydration);
|
|
25950
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25951
|
+
const client = await createDataClient();
|
|
25952
|
+
const inboundWebhookId = opts.id ?? randomUUID();
|
|
25953
|
+
printOutput(
|
|
25954
|
+
await client.request(
|
|
25955
|
+
"PUT",
|
|
25956
|
+
`/v1/${base}/inbound-webhooks/${pathSegment(inboundWebhookId, "--id")}`,
|
|
25957
|
+
body
|
|
25958
|
+
),
|
|
25959
|
+
outputFormat(this)
|
|
25960
|
+
);
|
|
25961
|
+
});
|
|
25962
|
+
inboundWebhooks.command("get <id>").description("Get an inbound webhook").action(async function(id) {
|
|
25963
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25964
|
+
const client = await createDataClient();
|
|
25965
|
+
printOutput(
|
|
25966
|
+
await client.request("GET", `/v1/${base}/inbound-webhooks/${pathSegment(id, "inbound webhook id")}`),
|
|
25967
|
+
outputFormat(this)
|
|
25968
|
+
);
|
|
25969
|
+
});
|
|
25970
|
+
inboundWebhooks.command("list").description("List all inbound webhooks").action(async function() {
|
|
25971
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25972
|
+
const client = await createDataClient();
|
|
25973
|
+
printOutput(await client.request("GET", `/v1/${base}/inbound-webhooks`), outputFormat(this));
|
|
25974
|
+
});
|
|
25975
|
+
inboundWebhooks.command("deliveries").description(
|
|
25976
|
+
'List hydration delivery status for reference-style ("notification + fetch") webhooks'
|
|
25977
|
+
).option("--status <status>", "Filter by status (pending|delivered|failed|dead)").option("--inbound-webhook <id>", "Filter to one inbound webhook").action(async function(opts) {
|
|
25978
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25979
|
+
const client = await createDataClient();
|
|
25980
|
+
const params = new URLSearchParams();
|
|
25981
|
+
if (opts.status) params.set("status", opts.status);
|
|
25982
|
+
if (opts.inboundWebhook) params.set("inbound_webhook_id", opts.inboundWebhook);
|
|
25983
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
25984
|
+
printOutput(
|
|
25985
|
+
await client.request("GET", `/v1/${base}/inbound-webhooks/deliveries${qs}`),
|
|
25986
|
+
outputFormat(this)
|
|
25987
|
+
);
|
|
25988
|
+
});
|
|
25989
|
+
inboundWebhooks.command("delete <id>").description("Delete an inbound webhook").option("-y, --yes", "Skip confirmation prompt").action(async function(id, opts) {
|
|
25990
|
+
if (!opts.yes && !await confirm(`Delete inbound webhook ${id}? This cannot be undone.`)) {
|
|
25991
|
+
console.log("Aborted");
|
|
25992
|
+
return;
|
|
25993
|
+
}
|
|
25994
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
25995
|
+
const client = await createDataClient();
|
|
25996
|
+
await client.request("DELETE", `/v1/${base}/inbound-webhooks/${pathSegment(id, "inbound webhook id")}`);
|
|
25997
|
+
console.log("Deleted");
|
|
25998
|
+
});
|
|
25999
|
+
return inboundWebhooks;
|
|
26000
|
+
}
|
|
26001
|
+
var init_inbound_webhooks = __esm({
|
|
26002
|
+
"src/data/commands/inbound-webhooks.ts"() {
|
|
26003
|
+
"use strict";
|
|
26004
|
+
init_client();
|
|
26005
|
+
init_output();
|
|
26006
|
+
init_helpers();
|
|
26007
|
+
init_utils();
|
|
26008
|
+
}
|
|
26009
|
+
});
|
|
26010
|
+
|
|
26011
|
+
// src/data/commands/query-relationships.ts
|
|
26012
|
+
import { Command as Command7 } from "commander";
|
|
26013
|
+
function buildQueryRelationshipsCommand() {
|
|
26014
|
+
return new Command7("query-relationships").description("Query related records").argument("<record_type>", "RecordType of the source record").argument("<id>", "Source record ID").option("--type <type>", "Filter by relationship type").option("--direction <dir>", "Direction: outgoing, incoming, or both", "both").option("--limit <n>", "Max results", "50").option("--offset <n>", "Skip results", "0").action(async function(recordType2, id, opts) {
|
|
26015
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26016
|
+
const client = await createDataClient();
|
|
26017
|
+
const params = new URLSearchParams();
|
|
26018
|
+
if (opts.type) params.set("rel_type", opts.type);
|
|
26019
|
+
params.set("direction", DIRECTIONS[opts.direction] ?? opts.direction);
|
|
26020
|
+
params.set("limit", opts.limit);
|
|
26021
|
+
params.set("offset", opts.offset);
|
|
26022
|
+
printOutput(
|
|
26023
|
+
await client.request(
|
|
26024
|
+
"GET",
|
|
26025
|
+
`/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${pathSegment(id, "record id")}/related?${params.toString()}`
|
|
26026
|
+
),
|
|
26027
|
+
outputFormat(this)
|
|
26028
|
+
);
|
|
26029
|
+
});
|
|
26030
|
+
}
|
|
26031
|
+
var DIRECTIONS;
|
|
26032
|
+
var init_query_relationships = __esm({
|
|
26033
|
+
"src/data/commands/query-relationships.ts"() {
|
|
26034
|
+
"use strict";
|
|
26035
|
+
init_client();
|
|
26036
|
+
init_output();
|
|
26037
|
+
init_helpers();
|
|
26038
|
+
DIRECTIONS = {
|
|
26039
|
+
outgoing: "source",
|
|
26040
|
+
incoming: "target",
|
|
26041
|
+
both: "both"
|
|
26042
|
+
};
|
|
26043
|
+
}
|
|
26044
|
+
});
|
|
26045
|
+
|
|
26046
|
+
// src/data/commands/record-types.ts
|
|
26047
|
+
import { Command as Command8 } from "commander";
|
|
26048
|
+
function buildRecordTypesCommand() {
|
|
26049
|
+
const recordTypes = new Command8("record-types").description("Manage record_types");
|
|
26050
|
+
recordTypes.command("list").description("List all record_types in a base").action(async function() {
|
|
26051
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26052
|
+
const client = await createDataClient();
|
|
26053
|
+
printOutput(await client.request("GET", `/v1/${base}/record-types`), outputFormat(this));
|
|
26054
|
+
});
|
|
26055
|
+
recordTypes.command("get <id>").description("Get a record_type").action(async function(id) {
|
|
26056
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26057
|
+
const client = await createDataClient();
|
|
26058
|
+
printOutput(await client.request("GET", `/v1/${base}/record-types/${pathSegment(id, "record_type")}`), outputFormat(this));
|
|
26059
|
+
});
|
|
26060
|
+
recordTypes.command("upsert <id>").description("Create or update a record_type").requiredOption("--name <name>", "RecordType name").option("--description <desc>", "Description").option("--schema <json>", "JSON Schema (inline JSON or @filename)").option("--icon <icon>", "Icon name").option("--color <color>", "Hex color").option("--sources <json>", "External sources config (inline JSON or @filename)").action(async function(id, opts) {
|
|
26061
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26062
|
+
const client = await createDataClient();
|
|
26063
|
+
const body = { name: opts.name };
|
|
26064
|
+
if (opts.description) body.description = opts.description;
|
|
26065
|
+
if (opts.schema) body.json_schema = parseData(opts.schema);
|
|
26066
|
+
if (opts.icon) body.icon = opts.icon;
|
|
26067
|
+
if (opts.color) body.color = opts.color;
|
|
26068
|
+
if (opts.sources) body.sources = parseData(opts.sources);
|
|
26069
|
+
printOutput(
|
|
26070
|
+
await client.request("PUT", `/v1/${base}/record-types/${pathSegment(id, "record_type")}`, body),
|
|
26071
|
+
outputFormat(this)
|
|
26072
|
+
);
|
|
26073
|
+
});
|
|
26074
|
+
recordTypes.command("delete <id>").description("Delete a record_type").option("-y, --yes", "Skip confirmation prompt").action(async function(id, opts) {
|
|
26075
|
+
if (!opts.yes && !await confirm(`Delete record_type "${id}"? This cannot be undone.`)) {
|
|
26076
|
+
console.log("Aborted");
|
|
26077
|
+
return;
|
|
26078
|
+
}
|
|
26079
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26080
|
+
const client = await createDataClient();
|
|
26081
|
+
await client.request("DELETE", `/v1/${base}/record-types/${pathSegment(id, "record_type")}`);
|
|
26082
|
+
console.log("Deleted");
|
|
26083
|
+
});
|
|
26084
|
+
recordTypes.command("history <id>").description(
|
|
26085
|
+
"View the change history (audit log) for a record_type \u2014 every schema/config version, who changed it, and when"
|
|
26086
|
+
).option("--limit <n>", "Max results").option("--offset <n>", "Pagination offset").option("--diff", "Include field-level diffs between versions").action(async function(id, opts) {
|
|
26087
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26088
|
+
const client = await createDataClient();
|
|
26089
|
+
printOutput(
|
|
26090
|
+
await client.request("GET", `/v1/${base}/audit/record-types/${pathSegment(id, "record_type")}${historyQuery(opts)}`),
|
|
26091
|
+
outputFormat(this)
|
|
26092
|
+
);
|
|
26093
|
+
});
|
|
26094
|
+
return recordTypes;
|
|
26095
|
+
}
|
|
26096
|
+
var init_record_types = __esm({
|
|
26097
|
+
"src/data/commands/record-types.ts"() {
|
|
26098
|
+
"use strict";
|
|
26099
|
+
init_client();
|
|
26100
|
+
init_output();
|
|
26101
|
+
init_helpers();
|
|
26102
|
+
init_utils();
|
|
26103
|
+
}
|
|
26104
|
+
});
|
|
26105
|
+
|
|
26106
|
+
// src/data/commands/records.ts
|
|
26107
|
+
import { Command as Command9 } from "commander";
|
|
26108
|
+
function recordKey(id, externalSource) {
|
|
26109
|
+
return externalSource ? foreignSegment(id, "external id") : pathSegment(id, "record id");
|
|
26110
|
+
}
|
|
26111
|
+
function buildRecordsCommand() {
|
|
26112
|
+
const records = new Command9("records").description("Manage records");
|
|
26113
|
+
records.command("upsert <record_type>").description("Create or update a record").requiredOption("--data <json>", "Record data (inline JSON or @filename)").option("--id <id>", "Internal record ID (UUID) to update a known record").option("--external-id <id>", "External/agent-supplied ID for idempotent upsert").option("--external-source <source>", "Source system for external_id (e.g. stripe)").action(async function(recordType2, opts) {
|
|
26114
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26115
|
+
const client = await createDataClient();
|
|
26116
|
+
const body = { data: parseData(opts.data) };
|
|
26117
|
+
if (opts.externalId) body.external_id = opts.externalId;
|
|
26118
|
+
if (opts.externalSource) body.external_source = opts.externalSource;
|
|
26119
|
+
const path31 = opts.id ? `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${pathSegment(opts.id, "--id")}` : `/v1/${base}/records/${pathSegment(recordType2, "record_type")}`;
|
|
26120
|
+
printOutput(await client.request("PUT", path31, body), outputFormat(this));
|
|
26121
|
+
});
|
|
26122
|
+
records.command("query <record_type>").description("List/search records: exact filters + fuzzy `search`, sorting, pagination").option(
|
|
26123
|
+
"--external-source <source>",
|
|
26124
|
+
"List from an external source (proxy-backed record_type). Combine with --filter when the source forwards filters."
|
|
26125
|
+
).option(
|
|
26126
|
+
"--filter <json>",
|
|
26127
|
+
"Filter DSL expression (inline JSON or @filename). Use the `search` operator for fuzzy matching."
|
|
26128
|
+
).option(
|
|
26129
|
+
"--sort <json>",
|
|
26130
|
+
'Sort expressions (inline JSON or @filename), e.g. [{"field":"data.created","direction":"desc"}]'
|
|
26131
|
+
).option("--fields <list>", "Comma-separated field projection").option("--limit <n>", "Max results").option("--offset <n>", "Pagination offset").action(async function(recordType2, opts) {
|
|
26132
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26133
|
+
const client = await createDataClient();
|
|
26134
|
+
const qs = new URLSearchParams();
|
|
26135
|
+
if (opts.externalSource) qs.set("external_source", opts.externalSource);
|
|
26136
|
+
if (opts.filter) qs.set("filter", JSON.stringify(parseData(opts.filter)));
|
|
26137
|
+
if (opts.sort) qs.set("sort", JSON.stringify(parseData(opts.sort)));
|
|
26138
|
+
if (opts.fields) qs.set("fields", opts.fields);
|
|
26139
|
+
if (opts.limit) qs.set("limit", opts.limit);
|
|
26140
|
+
if (opts.offset) qs.set("offset", opts.offset);
|
|
26141
|
+
const q = qs.toString();
|
|
26142
|
+
printOutput(
|
|
26143
|
+
await client.request("GET", `/v1/${base}/records/${pathSegment(recordType2, "record_type")}${q ? `?${q}` : ""}`),
|
|
26144
|
+
outputFormat(this)
|
|
26145
|
+
);
|
|
26146
|
+
});
|
|
26147
|
+
records.command("get <record_type> <id>").description(
|
|
26148
|
+
"Get a record by internal ID, or by external_id (pass --external-source to scope it)"
|
|
26149
|
+
).option(
|
|
26150
|
+
"--external-source <source>",
|
|
26151
|
+
"Treat <id> as an external_id scoped to this source system (e.g. stripe)"
|
|
26152
|
+
).action(async function(recordType2, id, opts) {
|
|
26153
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26154
|
+
const client = await createDataClient();
|
|
26155
|
+
let path31 = `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${recordKey(id, opts.externalSource)}`;
|
|
26156
|
+
if (opts.externalSource) path31 += `?external_source=${encodeURIComponent(opts.externalSource)}`;
|
|
26157
|
+
printOutput(await client.request("GET", path31), outputFormat(this));
|
|
26158
|
+
});
|
|
26159
|
+
records.command("delete <record_type> <id>").description(
|
|
26160
|
+
"Delete a record by internal ID, or by external_id (pass --external-source to scope it)"
|
|
26161
|
+
).option("-y, --yes", "Skip confirmation prompt").option(
|
|
26162
|
+
"--external-source <source>",
|
|
26163
|
+
"Treat <id> as an external_id scoped to this source system (e.g. stripe)"
|
|
26164
|
+
).action(async function(recordType2, id, opts) {
|
|
26165
|
+
if (!opts.yes && !await confirm(`Delete record ${recordType2}/${id}? This cannot be undone.`)) {
|
|
26166
|
+
console.log("Aborted");
|
|
26167
|
+
return;
|
|
26168
|
+
}
|
|
26169
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26170
|
+
const client = await createDataClient();
|
|
26171
|
+
let path31 = `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${recordKey(id, opts.externalSource)}`;
|
|
26172
|
+
if (opts.externalSource) {
|
|
26173
|
+
path31 += `?external_source=${encodeURIComponent(opts.externalSource)}&external_id=${encodeURIComponent(id)}`;
|
|
26174
|
+
}
|
|
26175
|
+
await client.request("DELETE", path31);
|
|
26176
|
+
console.log("Deleted");
|
|
26177
|
+
});
|
|
26178
|
+
records.command("history <id>").description(
|
|
26179
|
+
"View the change history (audit log) for a record \u2014 every version, who changed it, and when"
|
|
26180
|
+
).option("--limit <n>", "Max results").option("--offset <n>", "Pagination offset").option("--diff", "Include field-level diffs between versions").action(async function(id, opts) {
|
|
26181
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26182
|
+
const client = await createDataClient();
|
|
26183
|
+
printOutput(
|
|
26184
|
+
await client.request("GET", `/v1/${base}/audit/records/${pathSegment(id, "record id")}${historyQuery(opts)}`),
|
|
26185
|
+
outputFormat(this)
|
|
26186
|
+
);
|
|
26187
|
+
});
|
|
26188
|
+
return records;
|
|
26189
|
+
}
|
|
26190
|
+
var init_records = __esm({
|
|
26191
|
+
"src/data/commands/records.ts"() {
|
|
26192
|
+
"use strict";
|
|
26193
|
+
init_client();
|
|
26194
|
+
init_output();
|
|
26195
|
+
init_helpers();
|
|
26196
|
+
init_utils();
|
|
26197
|
+
}
|
|
26198
|
+
});
|
|
26199
|
+
|
|
26200
|
+
// src/data/commands/relationship-types.ts
|
|
26201
|
+
import { Command as Command10 } from "commander";
|
|
26202
|
+
function buildRelationshipTypesCommand() {
|
|
26203
|
+
const relationshipTypes = new Command10("relationship-types").description(
|
|
26204
|
+
"Manage relationship types (the schema for a relationship's metadata)"
|
|
26205
|
+
);
|
|
26206
|
+
relationshipTypes.command("list").description("List all relationship types in a base").action(async function() {
|
|
26207
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26208
|
+
const client = await createDataClient();
|
|
26209
|
+
printOutput(
|
|
26210
|
+
await client.request("GET", `/v1/${base}/relationship-types`),
|
|
26211
|
+
outputFormat(this)
|
|
26212
|
+
);
|
|
26213
|
+
});
|
|
26214
|
+
relationshipTypes.command("get <rel_type>").description("Get a relationship type").action(async function(relType) {
|
|
26215
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26216
|
+
const client = await createDataClient();
|
|
26217
|
+
printOutput(
|
|
26218
|
+
await client.request("GET", `/v1/${base}/relationship-types/${pathSegment(relType, "rel_type")}`),
|
|
26219
|
+
outputFormat(this)
|
|
26220
|
+
);
|
|
26221
|
+
});
|
|
26222
|
+
relationshipTypes.command("upsert <rel_type>").description("Create or update a relationship type").option("--description <desc>", "Description").option(
|
|
26223
|
+
"--schema <json>",
|
|
26224
|
+
"JSON Schema for the relationship data (inline JSON or @filename). Omit to allow any data."
|
|
26225
|
+
).option(
|
|
26226
|
+
"--source-record-types <json>",
|
|
26227
|
+
"JSON array of allowed source record_types (inline JSON or @filename)"
|
|
26228
|
+
).option(
|
|
26229
|
+
"--target-record-types <json>",
|
|
26230
|
+
"JSON array of allowed target record_types (inline JSON or @filename)"
|
|
26231
|
+
).action(async function(relType, opts) {
|
|
26232
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26233
|
+
const client = await createDataClient();
|
|
26234
|
+
const body = {};
|
|
26235
|
+
if (opts.description) body.description = opts.description;
|
|
26236
|
+
if (opts.schema) body.data_schema = parseData(opts.schema);
|
|
26237
|
+
if (opts.sourceRecordTypes) body.source_record_types = parseData(opts.sourceRecordTypes);
|
|
26238
|
+
if (opts.targetRecordTypes) body.target_record_types = parseData(opts.targetRecordTypes);
|
|
26239
|
+
printOutput(
|
|
26240
|
+
await client.request("PUT", `/v1/${base}/relationship-types/${pathSegment(relType, "rel_type")}`, body),
|
|
26241
|
+
outputFormat(this)
|
|
26242
|
+
);
|
|
26243
|
+
});
|
|
26244
|
+
relationshipTypes.command("delete <rel_type>").description("Delete a relationship type").option("-y, --yes", "Skip confirmation prompt").action(async function(relType, opts) {
|
|
26245
|
+
if (!opts.yes && !await confirm(`Delete relationship type "${relType}"? This cannot be undone.`)) {
|
|
26246
|
+
console.log("Aborted");
|
|
26247
|
+
return;
|
|
26248
|
+
}
|
|
26249
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26250
|
+
const client = await createDataClient();
|
|
26251
|
+
await client.request("DELETE", `/v1/${base}/relationship-types/${pathSegment(relType, "rel_type")}`);
|
|
26252
|
+
console.log("Deleted");
|
|
26253
|
+
});
|
|
26254
|
+
relationshipTypes.command("history <id>").description(
|
|
26255
|
+
"View the change history (audit log) for a relationship type \u2014 every config version, who changed it, and when"
|
|
26256
|
+
).option("--limit <n>", "Max results").option("--offset <n>", "Pagination offset").option("--diff", "Include field-level diffs between versions").action(async function(id, opts) {
|
|
26257
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26258
|
+
const client = await createDataClient();
|
|
26259
|
+
printOutput(
|
|
26260
|
+
await client.request(
|
|
26261
|
+
"GET",
|
|
26262
|
+
`/v1/${base}/audit/relationship-types/${pathSegment(id, "rel_type")}${historyQuery(opts)}`
|
|
26263
|
+
),
|
|
26264
|
+
outputFormat(this)
|
|
26265
|
+
);
|
|
26266
|
+
});
|
|
26267
|
+
return relationshipTypes;
|
|
26268
|
+
}
|
|
26269
|
+
var init_relationship_types = __esm({
|
|
26270
|
+
"src/data/commands/relationship-types.ts"() {
|
|
26271
|
+
"use strict";
|
|
26272
|
+
init_client();
|
|
26273
|
+
init_output();
|
|
26274
|
+
init_helpers();
|
|
26275
|
+
init_utils();
|
|
26276
|
+
}
|
|
26277
|
+
});
|
|
26278
|
+
|
|
26279
|
+
// src/data/commands/relationships.ts
|
|
26280
|
+
import { Command as Command11 } from "commander";
|
|
26281
|
+
function relationshipKey(id, relType) {
|
|
26282
|
+
return relType ? foreignSegment(id, "external id") : pathSegment(id, "relationship id");
|
|
26283
|
+
}
|
|
26284
|
+
function endpointBodyFields(role, byId, byExternal, externalSource) {
|
|
26285
|
+
if ((byId ? 1 : 0) + (byExternal ? 1 : 0) !== 1) {
|
|
26286
|
+
throw expected(`Provide exactly one of --${role} or --${role}-external.`);
|
|
26287
|
+
}
|
|
26288
|
+
const ref = byId ?? byExternal;
|
|
26289
|
+
const segments = ref.split("/");
|
|
26290
|
+
const [recordType2, key] = segments;
|
|
26291
|
+
if (segments.length !== 2 || !recordType2 || !key) {
|
|
26292
|
+
throw expected(
|
|
26293
|
+
`--${role}${byId ? "" : "-external"} must be <record_type/${byId ? "id" : "external_id"}>, got '${ref}'.`
|
|
26294
|
+
);
|
|
26295
|
+
}
|
|
26296
|
+
if (externalSource && !byExternal) {
|
|
26297
|
+
throw expected(`--${role}-external-source requires --${role}-external.`);
|
|
26298
|
+
}
|
|
26299
|
+
const fields = { [`${role}_record_type`]: recordType2 };
|
|
26300
|
+
if (byId) {
|
|
26301
|
+
fields[`${role}_id`] = key;
|
|
26302
|
+
} else {
|
|
26303
|
+
fields[`${role}_external_id`] = key;
|
|
26304
|
+
if (externalSource) fields[`${role}_external_source`] = externalSource;
|
|
26305
|
+
}
|
|
26306
|
+
return fields;
|
|
26307
|
+
}
|
|
26308
|
+
function byKeyQuery(relType, externalSource) {
|
|
26309
|
+
const qs = new URLSearchParams();
|
|
26310
|
+
if (relType) qs.set("rel_type", relType);
|
|
26311
|
+
if (externalSource) qs.set("external_source", externalSource);
|
|
26312
|
+
const q = qs.toString();
|
|
26313
|
+
return q ? `?${q}` : "";
|
|
26314
|
+
}
|
|
26315
|
+
function buildRelationshipsCommand() {
|
|
26316
|
+
const relationships = new Command11("relationships").description(
|
|
26317
|
+
"Manage relationships between records"
|
|
26318
|
+
);
|
|
26319
|
+
relationships.command("upsert").description("Create or update a relationship").option("--source <record_type/id>", "Source record by internal id").option(
|
|
26320
|
+
"--source-external <record_type/external_id>",
|
|
26321
|
+
"Source record by external_id (the record must exist)"
|
|
26322
|
+
).option("--source-external-source <name>", "Source system scoping --source-external").option("--target <record_type/id>", "Target record by internal id").option(
|
|
26323
|
+
"--target-external <record_type/external_id>",
|
|
26324
|
+
"Target record by external_id (the record must exist)"
|
|
26325
|
+
).option("--target-external-source <name>", "Source system scoping --target-external").requiredOption("--type <type>", "Relationship type").option("--id <id>", "Relationship ID").option(
|
|
26326
|
+
"--external-id <key>",
|
|
26327
|
+
"The relationship's own external key: a retried upsert with the same key updates the first row instead of duplicating it"
|
|
26328
|
+
).option("--external-source <name>", "Source system scoping the relationship's --external-id").option("--data <json>", "Relationship metadata (inline JSON or @filename)").action(async function(opts) {
|
|
26329
|
+
const body = {
|
|
26330
|
+
rel_type: opts.type,
|
|
26331
|
+
...endpointBodyFields("source", opts.source, opts.sourceExternal, opts.sourceExternalSource),
|
|
26332
|
+
...endpointBodyFields("target", opts.target, opts.targetExternal, opts.targetExternalSource)
|
|
26333
|
+
};
|
|
26334
|
+
if (opts.id) body.id = opts.id;
|
|
26335
|
+
if (opts.externalId) body.external_id = opts.externalId;
|
|
26336
|
+
if (opts.externalSource) body.external_source = opts.externalSource;
|
|
26337
|
+
if (opts.data) body.data = parseData(opts.data);
|
|
26338
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26339
|
+
const client = await createDataClient();
|
|
26340
|
+
const path31 = opts.id ? `/v1/${base}/relationships/${pathSegment(opts.id, "--id")}` : `/v1/${base}/relationships`;
|
|
26341
|
+
printOutput(await client.request("PUT", path31, body), outputFormat(this));
|
|
26342
|
+
});
|
|
26343
|
+
relationships.command("get <id>").description(
|
|
26344
|
+
"Get a relationship by ID (or by its external key: pass the external_id with --rel-type)"
|
|
26345
|
+
).option(
|
|
26346
|
+
"--rel-type <type>",
|
|
26347
|
+
"Treat <id> as the relationship external_id, scoped to this relationship type"
|
|
26348
|
+
).option("--external-source <name>", "Source system scoping the external_id (with --rel-type)").action(async function(id, opts) {
|
|
26349
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26350
|
+
const client = await createDataClient();
|
|
26351
|
+
printOutput(
|
|
26352
|
+
await client.request(
|
|
26353
|
+
"GET",
|
|
26354
|
+
`/v1/${base}/relationships/${relationshipKey(id, opts.relType)}${byKeyQuery(opts.relType, opts.externalSource)}`
|
|
26355
|
+
),
|
|
26356
|
+
outputFormat(this)
|
|
26357
|
+
);
|
|
26358
|
+
});
|
|
26359
|
+
relationships.command("delete <id>").description(
|
|
26360
|
+
"Delete a relationship by ID (or by its external key: pass the external_id with --rel-type)"
|
|
26361
|
+
).option(
|
|
26362
|
+
"--rel-type <type>",
|
|
26363
|
+
"Treat <id> as the relationship external_id, scoped to this relationship type"
|
|
26364
|
+
).option("--external-source <name>", "Source system scoping the external_id (with --rel-type)").option("-y, --yes", "Skip confirmation prompt").action(async function(id, opts) {
|
|
26365
|
+
if (!opts.yes && !await confirm(`Delete relationship ${id}? This cannot be undone.`)) {
|
|
26366
|
+
console.log("Aborted");
|
|
26367
|
+
return;
|
|
26368
|
+
}
|
|
26369
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26370
|
+
const client = await createDataClient();
|
|
26371
|
+
await client.request(
|
|
26372
|
+
"DELETE",
|
|
26373
|
+
`/v1/${base}/relationships/${relationshipKey(id, opts.relType)}${byKeyQuery(opts.relType, opts.externalSource)}`
|
|
26374
|
+
);
|
|
26375
|
+
console.log("Deleted");
|
|
26376
|
+
});
|
|
26377
|
+
relationships.command("history <id>").description(
|
|
26378
|
+
"View the change history (audit log) for a relationship \u2014 every version, who changed it, and when"
|
|
26379
|
+
).option("--limit <n>", "Max results").option("--offset <n>", "Pagination offset").option("--diff", "Include field-level diffs between versions").action(async function(id, opts) {
|
|
26380
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26381
|
+
const client = await createDataClient();
|
|
26382
|
+
printOutput(
|
|
26383
|
+
await client.request("GET", `/v1/${base}/audit/relationships/${pathSegment(id, "relationship id")}${historyQuery(opts)}`),
|
|
26384
|
+
outputFormat(this)
|
|
26385
|
+
);
|
|
26386
|
+
});
|
|
26387
|
+
return relationships;
|
|
26388
|
+
}
|
|
26389
|
+
var init_relationships = __esm({
|
|
26390
|
+
"src/data/commands/relationships.ts"() {
|
|
26391
|
+
"use strict";
|
|
26392
|
+
init_expected();
|
|
26393
|
+
init_client();
|
|
26394
|
+
init_output();
|
|
26395
|
+
init_helpers();
|
|
26396
|
+
init_utils();
|
|
26397
|
+
}
|
|
26398
|
+
});
|
|
26399
|
+
|
|
26400
|
+
// src/data/commands/seed.ts
|
|
26401
|
+
import { Command as Command12 } from "commander";
|
|
26402
|
+
function buildSeedCommand() {
|
|
26403
|
+
const seed = new Command12("seed").description(
|
|
26404
|
+
"Apply, reset, or clear a seed fixture on a preview base (hermetic eval data)"
|
|
26405
|
+
);
|
|
26406
|
+
seed.command("apply <name>").description(
|
|
26407
|
+
"Idempotently upsert the fixture (keyed by external_id, so re-applying never twins). Preview-only."
|
|
26408
|
+
).action(async function(name) {
|
|
26409
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26410
|
+
const client = await createDataClient();
|
|
26411
|
+
printOutput(
|
|
26412
|
+
await client.request("POST", `/v1/${base}/seeds/${pathSegment(name, "fixture name")}/apply`),
|
|
26413
|
+
outputFormat(this)
|
|
26414
|
+
);
|
|
26415
|
+
});
|
|
26416
|
+
seed.command("reset <name>").description(
|
|
26417
|
+
"Restore the declared baseline: re-apply in place (fixing trigger-mutated records) and prune owned rows the fixture no longer declares. Record types listed in exclusive_record_types are treated as authoritative \u2014 reset also removes their non-declared records (agent-created residue) and any relationships referencing them. Preview-only."
|
|
26418
|
+
).action(async function(name) {
|
|
26419
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26420
|
+
const client = await createDataClient();
|
|
26421
|
+
printOutput(
|
|
26422
|
+
await client.request("POST", `/v1/${base}/seeds/${pathSegment(name, "fixture name")}/reset`),
|
|
26423
|
+
outputFormat(this)
|
|
26424
|
+
);
|
|
26425
|
+
});
|
|
26426
|
+
seed.command("clear <name>").description("Delete every row the fixture owns (teardown). Preview-only.").action(async function(name) {
|
|
26427
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26428
|
+
const client = await createDataClient();
|
|
26429
|
+
printOutput(
|
|
26430
|
+
await client.request("POST", `/v1/${base}/seeds/${pathSegment(name, "fixture name")}/clear`),
|
|
26431
|
+
outputFormat(this)
|
|
26432
|
+
);
|
|
26433
|
+
});
|
|
26434
|
+
seed.command("list").description("List the seed fixtures defined on a base").action(async function() {
|
|
26435
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26436
|
+
const client = await createDataClient();
|
|
26437
|
+
printOutput(await client.request("GET", `/v1/${base}/seeds`), outputFormat(this));
|
|
26438
|
+
});
|
|
26439
|
+
seed.command("get <name>").description("Show a seed fixture definition (its declared records and relationships)").action(async function(name) {
|
|
26440
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26441
|
+
const client = await createDataClient();
|
|
26442
|
+
printOutput(await client.request("GET", `/v1/${base}/seeds/${pathSegment(name, "fixture name")}`), outputFormat(this));
|
|
26443
|
+
});
|
|
26444
|
+
const lease = seed.command("lease").description("Coordinate an isolated fixture lease");
|
|
26445
|
+
lease.command("acquire <fixture>").description("Reset a fixture and atomically acquire the preview base for one eval run").requiredOption("--lease-id <uuidv7>", "Client-generated UUIDv7 (permanently single-use)").requiredOption(
|
|
26446
|
+
"--owner-ref <ref>",
|
|
26447
|
+
"Safe ID: 1-200 letters/digits or ._:@/+~=- (descriptive only)"
|
|
26448
|
+
).action(async function(fixture, opts) {
|
|
26449
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26450
|
+
const client = await createDataClient();
|
|
26451
|
+
printOutput(
|
|
26452
|
+
await client.request("POST", `/v1/${base}/seed-leases/acquire`, {
|
|
26453
|
+
lease_id: opts.leaseId,
|
|
26454
|
+
fixture,
|
|
26455
|
+
owner_ref: opts.ownerRef
|
|
26456
|
+
}),
|
|
26457
|
+
outputFormat(this)
|
|
26458
|
+
);
|
|
26459
|
+
});
|
|
26460
|
+
lease.command("status").description("Inspect your lease, or learn only whether another actor has locked the base").option("--lease-id <uuidv7>", "Inspect a specific lease ID").action(async function(opts) {
|
|
26461
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26462
|
+
const client = await createDataClient();
|
|
26463
|
+
const params = new URLSearchParams();
|
|
26464
|
+
if (opts.leaseId !== void 0) params.set("lease_id", opts.leaseId);
|
|
26465
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
26466
|
+
printOutput(
|
|
26467
|
+
await client.request("GET", `/v1/${base}/seed-leases/status${query}`),
|
|
26468
|
+
outputFormat(this)
|
|
26469
|
+
);
|
|
26470
|
+
});
|
|
26471
|
+
lease.command("release <fixture>").description("Clear fixture-owned data and release the matching lease").requiredOption("--lease-id <uuidv7>", "The UUIDv7 used to acquire the lease").requiredOption("--owner-ref <ref>", "Same safe ID: 1-200 letters/digits or ._:@/+~=-").action(async function(fixture, opts) {
|
|
26472
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26473
|
+
const client = await createDataClient();
|
|
26474
|
+
printOutput(
|
|
26475
|
+
await client.request("POST", `/v1/${base}/seed-leases/release`, {
|
|
26476
|
+
lease_id: opts.leaseId,
|
|
26477
|
+
fixture,
|
|
26478
|
+
owner_ref: opts.ownerRef
|
|
26479
|
+
}),
|
|
26480
|
+
outputFormat(this)
|
|
26481
|
+
);
|
|
26482
|
+
});
|
|
26483
|
+
return seed;
|
|
26484
|
+
}
|
|
26485
|
+
var init_seed = __esm({
|
|
26486
|
+
"src/data/commands/seed.ts"() {
|
|
26487
|
+
"use strict";
|
|
26488
|
+
init_client();
|
|
26489
|
+
init_output();
|
|
26490
|
+
init_helpers();
|
|
26491
|
+
}
|
|
26492
|
+
});
|
|
26493
|
+
|
|
26494
|
+
// src/data/commands/toolsets.ts
|
|
26495
|
+
import { Command as Command13 } from "commander";
|
|
26496
|
+
function collect(value, previous) {
|
|
26497
|
+
return [...previous, value];
|
|
26498
|
+
}
|
|
26499
|
+
function parseSpec(spec) {
|
|
26500
|
+
const [key, opsStr] = spec.split(":");
|
|
26501
|
+
if (!key || !opsStr) {
|
|
26502
|
+
throw expected(`Invalid spec '${spec}'. Expected format: name:op1,op2`);
|
|
26503
|
+
}
|
|
26504
|
+
return { key, ops: splitList(opsStr) };
|
|
26505
|
+
}
|
|
26506
|
+
function parseActionRef(spec) {
|
|
26507
|
+
const [action, actionName] = spec.split("=");
|
|
26508
|
+
if (!action) {
|
|
26509
|
+
throw expected(`Invalid --action '${spec}'. Expected an Action id, or <action_id>=<surface_name>.`);
|
|
26510
|
+
}
|
|
26511
|
+
return actionName ? { action, action_name: actionName } : { action };
|
|
26512
|
+
}
|
|
26513
|
+
function parseRelSpec(spec) {
|
|
26514
|
+
const { key, ops } = parseSpec(spec);
|
|
26515
|
+
return { rel_type: key, operations: ops };
|
|
26516
|
+
}
|
|
26517
|
+
function buildToolsetsCommand() {
|
|
26518
|
+
const toolsets = new Command13("toolsets").description("Manage MCP toolsets");
|
|
26519
|
+
toolsets.command("upsert <slug>").description("Create or update an MCP toolset").option("--name <name>", "Toolset display name (required unless using --config)").option("--description <desc>", "Toolset description").option(
|
|
26520
|
+
"--action <ref>",
|
|
26521
|
+
"Reference an Action by id, optionally renamed: <action_id> or <action_id>=<surface_name> (repeatable). Create Actions first with `wayai actions upsert`.",
|
|
26522
|
+
collect,
|
|
26523
|
+
[]
|
|
26524
|
+
).option("--relationship <spec>", "Relationship tool spec: rel_type:op1,op2 (repeatable)", collect, []).option("--batch <spec>", "Batch operation spec: record_type_or_rel:op1,op2 (repeatable)", collect, []).option("--sql-query", "Enable sql_query tool").option(
|
|
26525
|
+
"--config <json>",
|
|
26526
|
+
"Full toolset config as JSON. A toolset composes first-class Actions by reference \u2014 its `actions` are refs {action: <action_id>, action_name?, description_override?}. Create the Actions with `wayai actions upsert` (each carries its own record_type, operation, and guard/shaping config: filterable_fields, writable_fields, precondition, binding). Use @file.json to read from file."
|
|
26527
|
+
).option(
|
|
26528
|
+
"--mint-token",
|
|
26529
|
+
"After upsert, also mint a toolset-bound (consumer) token for this base and print it (handy for sandbox-testing the preview toolset)"
|
|
26530
|
+
).action(async function(slug, opts) {
|
|
26531
|
+
let body;
|
|
26532
|
+
if (opts.config) {
|
|
26533
|
+
body = parseData(opts.config);
|
|
26534
|
+
} else {
|
|
26535
|
+
if (!opts.name) {
|
|
26536
|
+
throw expected("--name is required (or use --config for full JSON config)");
|
|
26537
|
+
}
|
|
26538
|
+
body = { name: opts.name, actions: opts.action.map(parseActionRef) };
|
|
26539
|
+
if (opts.description) body.description = opts.description;
|
|
26540
|
+
if (opts.relationship.length > 0) {
|
|
26541
|
+
body.relationships = opts.relationship.map(parseRelSpec);
|
|
26542
|
+
}
|
|
26543
|
+
if (opts.batch.length > 0) {
|
|
26544
|
+
const operations = {};
|
|
26545
|
+
for (const spec of opts.batch) {
|
|
26546
|
+
const parsed = parseSpec(spec);
|
|
26547
|
+
operations[parsed.key] = parsed.ops;
|
|
26548
|
+
}
|
|
26549
|
+
body.batch = { enabled: true, operations };
|
|
26550
|
+
}
|
|
26551
|
+
if (opts.sqlQuery) body.sql_query = true;
|
|
26552
|
+
}
|
|
26553
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26554
|
+
const client = await createDataClient();
|
|
26555
|
+
const format = outputFormat(this);
|
|
26556
|
+
printOutput(await client.request("PUT", `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}`, body), format);
|
|
26557
|
+
if (opts.mintToken) {
|
|
26558
|
+
const tokenData = await client.request("POST", "/v1/tokens", {
|
|
26559
|
+
name: `${slug} consumer`,
|
|
26560
|
+
toolset_binding: { base_id: base, toolset_id: slug }
|
|
26561
|
+
});
|
|
26562
|
+
if (format === "json") {
|
|
26563
|
+
printOutput(tokenData, format);
|
|
26564
|
+
} else {
|
|
26565
|
+
console.log("\nToolset-bound token:");
|
|
26566
|
+
printOutput(tokenData, format);
|
|
26567
|
+
console.log(`MCP URL: ${toolsetMcpUrl(slug)}`);
|
|
26568
|
+
}
|
|
26569
|
+
}
|
|
26570
|
+
});
|
|
26571
|
+
toolsets.command("get <slug>").description("Get a toolset").option("--resolved", "Include resolved record_type schemas").action(async function(slug, opts) {
|
|
26572
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26573
|
+
const client = await createDataClient();
|
|
26574
|
+
const path31 = opts.resolved ? `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}/resolved` : `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}`;
|
|
26575
|
+
printOutput(await client.request("GET", path31), outputFormat(this));
|
|
26576
|
+
});
|
|
26577
|
+
toolsets.command("list").description("List all toolsets").action(async function() {
|
|
26578
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26579
|
+
const client = await createDataClient();
|
|
26580
|
+
printOutput(await client.request("GET", `/v1/${base}/toolsets`), outputFormat(this));
|
|
26581
|
+
});
|
|
26582
|
+
toolsets.command("delete <slug>").description("Delete a toolset").option("-y, --yes", "Skip confirmation prompt").action(async function(slug, opts) {
|
|
26583
|
+
if (!opts.yes && !await confirm(`Delete toolset "${slug}"? This cannot be undone.`)) {
|
|
26584
|
+
console.log("Aborted");
|
|
26585
|
+
return;
|
|
26586
|
+
}
|
|
26587
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26588
|
+
const client = await createDataClient();
|
|
26589
|
+
await client.request("DELETE", `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}`);
|
|
26590
|
+
console.log("Deleted");
|
|
26591
|
+
});
|
|
26592
|
+
toolsets.command("url <slug>").description("Get the MCP connection URL for a toolset").action((slug) => {
|
|
26593
|
+
console.log(toolsetMcpUrl(slug));
|
|
26594
|
+
});
|
|
26595
|
+
return toolsets;
|
|
26596
|
+
}
|
|
26597
|
+
var init_toolsets = __esm({
|
|
26598
|
+
"src/data/commands/toolsets.ts"() {
|
|
26599
|
+
"use strict";
|
|
26600
|
+
init_expected();
|
|
26601
|
+
init_client();
|
|
26602
|
+
init_output();
|
|
26603
|
+
init_helpers();
|
|
26604
|
+
init_utils();
|
|
26605
|
+
}
|
|
26606
|
+
});
|
|
26607
|
+
|
|
26608
|
+
// src/data/commands/triggers.ts
|
|
26609
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
26610
|
+
import { Command as Command14 } from "commander";
|
|
26611
|
+
function buildTriggersCommand() {
|
|
26612
|
+
const triggers = new Command14("triggers").description(
|
|
26613
|
+
"Manage triggers (outbound webhooks, internal writes, external writes)"
|
|
26614
|
+
);
|
|
26615
|
+
triggers.command("create").description(
|
|
26616
|
+
"Create a trigger (a webhook, an internal_write that patches a referenced record, or an external_write that mirrors the record to an external source)"
|
|
26617
|
+
).requiredOption("--name <name>", "Trigger name").requiredOption("--events <events>", "Comma-separated event types").option("--url <url>", "Webhook target URL (webhook actions)").option("--secret-stdin", "Read the webhook HMAC signing secret from stdin (webhook actions)").option("--secret-prompt", "Prompt for the webhook HMAC signing secret, masked (webhook actions)").option(
|
|
26618
|
+
"--action <json>",
|
|
26619
|
+
`Action JSON. webhook {"type":"webhook","url":...,"secret":...}; internal_write {"type":"internal_write","target":"slots","match":{"source_field":"data.slot_id"},"patch":{"status":"busy"},"precondition":{"field":"data.status","op":"eq","value":"free"},"mode":"async"} (mode: "async" applies after the write, "transactional" applies atomically so a precondition miss rolls the write back); external_write {"type":"external_write","record_type":"upstream_appointments","source":"legacy","op":"create","watched_fields":"mapped"} (writes the triggering record through that source's write path \u2014 translation, endpoint, auth \u2014 and links the upstream-assigned id back as external_id; "record_type" defaults to the triggering record_type, "op" defaults from the event; "watched_fields" scopes UPDATE dispatch to writes that changed an upstream-mapped field \u2014 "mapped" = the source's to_external keys, or an explicit array of data fields \u2014 so an overlay-only write skips the redundant upstream push; omit to fire on every update)`
|
|
26620
|
+
).option("--id <id>", "Trigger ID (auto-generated if omitted)").option("--record-type-scope <record_types>", "Comma-separated record_type scope").option("--filter <json>", "Filter expression (JSON)").option(
|
|
26621
|
+
"--skip-cascade-writes <bool>",
|
|
26622
|
+
"Skip firing on cascade-originated (internal_write) writes (default true)"
|
|
26623
|
+
).action(async function(opts) {
|
|
26624
|
+
if (!opts.action && !opts.url) {
|
|
26625
|
+
throw expected("Provide --url (webhook) or --action <json> (e.g. an internal_write action).");
|
|
26626
|
+
}
|
|
26627
|
+
const body = {
|
|
26628
|
+
name: opts.name,
|
|
26629
|
+
events: splitList(opts.events),
|
|
26630
|
+
enabled: true
|
|
26631
|
+
};
|
|
26632
|
+
if (opts.action) {
|
|
26633
|
+
body.action = parseData(opts.action);
|
|
26634
|
+
} else {
|
|
26635
|
+
body.url = opts.url;
|
|
26636
|
+
if (opts.secretStdin || opts.secretPrompt) {
|
|
26637
|
+
body.secret = await readSecret(
|
|
26638
|
+
{
|
|
26639
|
+
stdin: opts.secretStdin,
|
|
26640
|
+
prompt: opts.secretPrompt,
|
|
26641
|
+
stdinFlag: "--secret-stdin",
|
|
26642
|
+
promptHint: "--secret-prompt"
|
|
26643
|
+
},
|
|
26644
|
+
"Webhook signing secret"
|
|
26645
|
+
);
|
|
26646
|
+
}
|
|
26647
|
+
}
|
|
26648
|
+
if (opts.recordTypeScope) body.record_type_scope = splitList(opts.recordTypeScope);
|
|
26649
|
+
if (opts.filter) body.filter = parseData(opts.filter);
|
|
26650
|
+
if (opts.skipCascadeWrites !== void 0) {
|
|
26651
|
+
body.skip_cascade_writes = opts.skipCascadeWrites !== "false";
|
|
26652
|
+
}
|
|
26653
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26654
|
+
const client = await createDataClient();
|
|
26655
|
+
const triggerId = opts.id ?? randomUUID2();
|
|
26656
|
+
printOutput(
|
|
26657
|
+
await client.request("PUT", `/v1/${base}/triggers/${pathSegment(triggerId, "--id")}`, body),
|
|
26658
|
+
outputFormat(this)
|
|
26659
|
+
);
|
|
26660
|
+
});
|
|
26661
|
+
triggers.command("get <id>").description("Get a trigger").action(async function(id) {
|
|
26662
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26663
|
+
const client = await createDataClient();
|
|
26664
|
+
printOutput(await client.request("GET", `/v1/${base}/triggers/${pathSegment(id, "trigger id")}`), outputFormat(this));
|
|
26665
|
+
});
|
|
26666
|
+
triggers.command("list").description("List all triggers").action(async function() {
|
|
26667
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26668
|
+
const client = await createDataClient();
|
|
26669
|
+
printOutput(await client.request("GET", `/v1/${base}/triggers`), outputFormat(this));
|
|
26670
|
+
});
|
|
26671
|
+
triggers.command("deliveries").description("List trigger delivery attempts (status, retries, errors)").option("--status <status>", "Filter by status (pending | delivered | failed | dead)").option("--trigger-id <id>", "Filter by trigger id").action(async function(opts) {
|
|
26672
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26673
|
+
const client = await createDataClient();
|
|
26674
|
+
const params = new URLSearchParams();
|
|
26675
|
+
if (opts.status) params.set("status", opts.status);
|
|
26676
|
+
if (opts.triggerId) params.set("trigger_id", opts.triggerId);
|
|
26677
|
+
const qs = params.toString();
|
|
26678
|
+
printOutput(
|
|
26679
|
+
await client.request("GET", `/v1/${base}/triggers/deliveries${qs ? `?${qs}` : ""}`),
|
|
26680
|
+
outputFormat(this)
|
|
26681
|
+
);
|
|
26682
|
+
});
|
|
26683
|
+
triggers.command("delete <id>").description("Delete a trigger").option("-y, --yes", "Skip confirmation prompt").action(async function(id, opts) {
|
|
26684
|
+
if (!opts.yes && !await confirm(`Delete trigger ${id}? This cannot be undone.`)) {
|
|
26685
|
+
console.log("Aborted");
|
|
26686
|
+
return;
|
|
26687
|
+
}
|
|
26688
|
+
const base = pathSegment(requireBase(this), "--base");
|
|
26689
|
+
const client = await createDataClient();
|
|
26690
|
+
await client.request("DELETE", `/v1/${base}/triggers/${pathSegment(id, "trigger id")}`);
|
|
26691
|
+
console.log("Deleted");
|
|
26692
|
+
});
|
|
26693
|
+
return triggers;
|
|
26694
|
+
}
|
|
26695
|
+
var init_triggers = __esm({
|
|
26696
|
+
"src/data/commands/triggers.ts"() {
|
|
26697
|
+
"use strict";
|
|
26698
|
+
init_expected();
|
|
26699
|
+
init_client();
|
|
26700
|
+
init_output();
|
|
26701
|
+
init_helpers();
|
|
26702
|
+
init_utils();
|
|
26703
|
+
}
|
|
26704
|
+
});
|
|
26705
|
+
|
|
26706
|
+
// src/data/program.ts
|
|
26707
|
+
var program_exports = {};
|
|
26708
|
+
__export(program_exports, {
|
|
26709
|
+
DATA_NAMESPACES: () => DATA_NAMESPACES,
|
|
26710
|
+
buildDataProgram: () => buildDataProgram,
|
|
26711
|
+
isDataNamespace: () => isDataNamespace,
|
|
26712
|
+
runDataCommand: () => runDataCommand,
|
|
26713
|
+
withBaseOption: () => withBaseOption,
|
|
26714
|
+
withDataGlobals: () => withDataGlobals
|
|
26715
|
+
});
|
|
26716
|
+
import { Command as Command15 } from "commander";
|
|
26717
|
+
function withDataGlobals(command2) {
|
|
26718
|
+
return command2.option("--org <uuid>", "Organization to operate against (overrides .wayai.yaml)").option("--output <format>", "Output format: json or table", "table").option("--json", "Shorthand for --output json");
|
|
26719
|
+
}
|
|
26720
|
+
function withBaseOption(command2) {
|
|
26721
|
+
return command2.option("--base <id>", "Base id (or set WAYAI_BASE)");
|
|
26722
|
+
}
|
|
26723
|
+
function routeErrorsToCli(command2) {
|
|
26724
|
+
command2.exitOverride().configureOutput({ outputError: () => {
|
|
25309
26725
|
} });
|
|
25310
26726
|
for (const child of command2.commands) routeErrorsToCli(child);
|
|
25311
26727
|
return command2;
|
|
25312
26728
|
}
|
|
25313
26729
|
function buildDataProgram() {
|
|
25314
|
-
const program = new
|
|
26730
|
+
const program = new Command15("wayai");
|
|
25315
26731
|
program.addCommand(withDataGlobals(buildBasesCommand()));
|
|
26732
|
+
for (const build of [
|
|
26733
|
+
buildRecordsCommand,
|
|
26734
|
+
buildRecordTypesCommand,
|
|
26735
|
+
buildRelationshipsCommand,
|
|
26736
|
+
buildRelationshipTypesCommand,
|
|
26737
|
+
buildQueryRelationshipsCommand,
|
|
26738
|
+
buildFilesCommand,
|
|
26739
|
+
buildFileTypesCommand,
|
|
26740
|
+
buildAttachmentsCommand,
|
|
26741
|
+
buildToolsetsCommand,
|
|
26742
|
+
buildActionsCommand,
|
|
26743
|
+
buildTriggersCommand,
|
|
26744
|
+
buildInboundWebhooksCommand,
|
|
26745
|
+
buildSeedCommand
|
|
26746
|
+
]) {
|
|
26747
|
+
program.addCommand(withBaseOption(withDataGlobals(build())));
|
|
26748
|
+
}
|
|
25316
26749
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
25317
26750
|
setDataOrgOverride(globals(actionCommand).org);
|
|
25318
26751
|
});
|
|
@@ -25341,7 +26774,20 @@ async function runDataCommand(namespace, args2) {
|
|
|
25341
26774
|
var init_program = __esm({
|
|
25342
26775
|
"src/data/program.ts"() {
|
|
25343
26776
|
"use strict";
|
|
26777
|
+
init_actions();
|
|
26778
|
+
init_attachments();
|
|
25344
26779
|
init_bases();
|
|
26780
|
+
init_file_types();
|
|
26781
|
+
init_files();
|
|
26782
|
+
init_inbound_webhooks();
|
|
26783
|
+
init_query_relationships();
|
|
26784
|
+
init_record_types();
|
|
26785
|
+
init_records();
|
|
26786
|
+
init_relationship_types();
|
|
26787
|
+
init_relationships();
|
|
26788
|
+
init_seed();
|
|
26789
|
+
init_toolsets();
|
|
26790
|
+
init_triggers();
|
|
25345
26791
|
init_helpers();
|
|
25346
26792
|
init_expected();
|
|
25347
26793
|
init_org_context();
|
|
@@ -25356,7 +26802,7 @@ init_errors2();
|
|
|
25356
26802
|
init_mask_secrets();
|
|
25357
26803
|
init_utils();
|
|
25358
26804
|
init_registry();
|
|
25359
|
-
import { readFileSync as
|
|
26805
|
+
import { readFileSync as readFileSync23 } from "fs";
|
|
25360
26806
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
25361
26807
|
import { dirname as dirname9, join as join28 } from "path";
|
|
25362
26808
|
|
|
@@ -25514,13 +26960,13 @@ Run \`wayai admin skill install\` to update.`);
|
|
|
25514
26960
|
|
|
25515
26961
|
// src/index.ts
|
|
25516
26962
|
var __dirname = dirname9(fileURLToPath2(import.meta.url));
|
|
25517
|
-
var pkg = JSON.parse(
|
|
26963
|
+
var pkg = JSON.parse(readFileSync23(join28(__dirname, "..", "package.json"), "utf-8"));
|
|
25518
26964
|
var [, , command, ...args] = process.argv;
|
|
25519
26965
|
var isBackgroundRefresh = command === REFRESH_COMMAND;
|
|
25520
26966
|
if (!isBackgroundRefresh) initSentry(command, pkg.version);
|
|
25521
26967
|
async function main() {
|
|
25522
26968
|
if (shouldInterceptHelp(command, args, /* @__PURE__ */ new Set([...OWN_HELP_COMMANDS, ...DATA_NAMESPACES]))) {
|
|
25523
|
-
printHelp3();
|
|
26969
|
+
await printHelp3();
|
|
25524
26970
|
return;
|
|
25525
26971
|
}
|
|
25526
26972
|
if (command && !wantsHelp(args)) {
|
|
@@ -25712,7 +27158,7 @@ async function main() {
|
|
|
25712
27158
|
case "--help":
|
|
25713
27159
|
case "-h":
|
|
25714
27160
|
case void 0:
|
|
25715
|
-
printHelp3();
|
|
27161
|
+
await printHelp3();
|
|
25716
27162
|
break;
|
|
25717
27163
|
case "--version":
|
|
25718
27164
|
case "-v":
|
|
@@ -25725,12 +27171,18 @@ async function main() {
|
|
|
25725
27171
|
break;
|
|
25726
27172
|
}
|
|
25727
27173
|
console.error(`Unknown command: ${command}`);
|
|
25728
|
-
printHelp3();
|
|
27174
|
+
await printHelp3();
|
|
25729
27175
|
process.exit(1);
|
|
25730
27176
|
}
|
|
25731
27177
|
}
|
|
25732
27178
|
}
|
|
25733
|
-
function
|
|
27179
|
+
async function dataHelpBlock() {
|
|
27180
|
+
const { buildDataProgram: buildDataProgram2 } = await Promise.resolve().then(() => (init_program(), program_exports));
|
|
27181
|
+
const namespaces = buildDataProgram2().commands;
|
|
27182
|
+
const width = Math.max(...namespaces.map((c) => c.name().length));
|
|
27183
|
+
return namespaces.map((c) => ` ${c.name().padEnd(width)} ${c.description()}`.trimEnd()).join("\n");
|
|
27184
|
+
}
|
|
27185
|
+
async function printHelp3() {
|
|
25734
27186
|
console.log(`
|
|
25735
27187
|
wayai \u2014 WayAI CLI
|
|
25736
27188
|
|
|
@@ -25778,12 +27230,11 @@ Commands:
|
|
|
25778
27230
|
report edit Amend your own pending report (title/description/error/steps/context)
|
|
25779
27231
|
update Update CLI to the latest version
|
|
25780
27232
|
|
|
25781
|
-
Data
|
|
25782
|
-
|
|
27233
|
+
Data \u2014 one namespace per entity. Run \`wayai <namespace> --help\` for its tree.
|
|
27234
|
+
${await dataHelpBlock()}
|
|
25783
27235
|
bases promote Promote a preview base to production (distinct from \`publish\`, which promotes a hub)
|
|
25784
27236
|
bases use <base> Bind this worktree to a base (\`wayai use\` binds a hub)
|
|
25785
27237
|
bases unbind Clear this worktree's base binding
|
|
25786
|
-
Run \`wayai bases --help\` for the full tree.
|
|
25787
27238
|
|
|
25788
27239
|
Flags:
|
|
25789
27240
|
--yes, -y Skip confirmation prompts (useful for CI and scripting)
|