@miosa/cli 1.1.8 → 1.1.11

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.
@@ -0,0 +1,222 @@
1
+ import chalk from "chalk";
2
+ import { ActionAuthorityClient } from "../action-authority.js";
3
+ import { MiosaClient } from "../client.js";
4
+ import { loadConfig } from "../config.js";
5
+ import { renderTable } from "../ui/table.js";
6
+ import { handleError, isJsonMode, printJson } from "./util.js";
7
+ function authority() {
8
+ return new ActionAuthorityClient(new MiosaClient(loadConfig()));
9
+ }
10
+ function parseJson(value) {
11
+ if (!value)
12
+ return {};
13
+ const parsed = JSON.parse(value);
14
+ if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") {
15
+ throw new Error("--params and --constraints must be JSON objects.");
16
+ }
17
+ return parsed;
18
+ }
19
+ export function register(program) {
20
+ const actions = program
21
+ .command("actions")
22
+ .description("Inspect and manage unified MIOSA agent-action authority");
23
+ actions
24
+ .command("catalog")
25
+ .description("List server-owned, version-pinned action capabilities")
26
+ .option("--json", "Output JSON")
27
+ .action(async (opts) => {
28
+ try {
29
+ const catalog = await authority().catalog();
30
+ if (isJsonMode(opts))
31
+ return printJson({ data: catalog });
32
+ renderTable(catalog, [
33
+ { header: "ACTION", key: "name", width: 30 },
34
+ { header: "VERSION", key: "version", width: 10 },
35
+ { header: "RISK", key: "risk", width: 12 },
36
+ { header: "SCOPE", key: "scope", width: 12 },
37
+ { header: "APPROVAL", key: "approval", width: 12 },
38
+ ]);
39
+ }
40
+ catch (error) {
41
+ handleError(error);
42
+ }
43
+ });
44
+ actions
45
+ .command("check <capability>")
46
+ .description("Ask the authority whether one exact invocation may run")
47
+ .option("--params <json>", "Exact action parameters", "{}")
48
+ .option("--workspace <id>", "Workspace scope")
49
+ .option("--invocation-id <id>", "Stable caller-provided invocation ID")
50
+ .option("--json", "Output JSON")
51
+ .action(async (capability, opts) => {
52
+ try {
53
+ const decision = await authority().authorize(capability, parseJson(opts.params), {
54
+ workspaceId: opts.workspace,
55
+ invocationId: opts.invocationId,
56
+ });
57
+ if (isJsonMode(opts))
58
+ return printJson(decision);
59
+ console.log(decision.decision === "allow"
60
+ ? chalk.green("ALLOW")
61
+ : decision.decision === "pending_approval"
62
+ ? chalk.yellow("PENDING APPROVAL")
63
+ : chalk.red("DENY"));
64
+ if (decision.approval_request_id) {
65
+ console.log(`Approval request: ${decision.approval_request_id}`);
66
+ }
67
+ if (decision.receipt_id)
68
+ console.log(`Receipt: ${decision.receipt_id}`);
69
+ }
70
+ catch (error) {
71
+ handleError(error);
72
+ }
73
+ });
74
+ const approvals = actions
75
+ .command("approvals")
76
+ .description("Manage one-time approvals");
77
+ approvals
78
+ .command("list")
79
+ .option("--status <status>", "Filter by status")
80
+ .option("--json", "Output JSON")
81
+ .action(async (opts) => {
82
+ try {
83
+ const rows = await authority().approvals(opts.status);
84
+ if (isJsonMode(opts))
85
+ return printJson({ data: rows });
86
+ renderTable(rows, [
87
+ { header: "ID", key: "id", width: 12 },
88
+ { header: "ACTION", key: "capability_name", width: 28 },
89
+ {
90
+ header: "PRINCIPAL",
91
+ key: (row) => `${row.principal_type}:${row.principal_id}`,
92
+ width: 28,
93
+ },
94
+ { header: "STATUS", key: "status", width: 12 },
95
+ { header: "CREATED", key: "inserted_at", width: 24 },
96
+ ]);
97
+ }
98
+ catch (error) {
99
+ handleError(error);
100
+ }
101
+ });
102
+ for (const decision of ["approve", "deny"]) {
103
+ approvals
104
+ .command(`${decision} <id>`)
105
+ .description(`${decision === "approve" ? "Approve" : "Deny"} one exact invocation`)
106
+ .option("--json", "Output JSON")
107
+ .action(async (id, opts) => {
108
+ try {
109
+ const result = await authority().resolveApproval(id, decision);
110
+ if (isJsonMode(opts))
111
+ return printJson({ data: result });
112
+ console.log(`${result.id}: ${result.status}`);
113
+ }
114
+ catch (error) {
115
+ handleError(error);
116
+ }
117
+ });
118
+ }
119
+ const grants = actions
120
+ .command("grants")
121
+ .description("Manage standing action grants");
122
+ grants
123
+ .command("list")
124
+ .option("--status <status>", "Filter by status")
125
+ .option("--json", "Output JSON")
126
+ .action(async (opts) => {
127
+ try {
128
+ const rows = await authority().grants(opts.status);
129
+ if (isJsonMode(opts))
130
+ return printJson({ data: rows });
131
+ renderTable(rows, [
132
+ { header: "ID", key: "id", width: 12 },
133
+ { header: "ACTION", key: "capability_name", width: 28 },
134
+ {
135
+ header: "PRINCIPAL",
136
+ key: (row) => `${row.principal_type}:${row.principal_id}`,
137
+ width: 28,
138
+ },
139
+ { header: "STATUS", key: "status", width: 12 },
140
+ {
141
+ header: "EXPIRES",
142
+ key: (row) => row.expires_at ?? "never",
143
+ width: 24,
144
+ },
145
+ ]);
146
+ }
147
+ catch (error) {
148
+ handleError(error);
149
+ }
150
+ });
151
+ grants
152
+ .command("create <capability>")
153
+ .requiredOption("--principal-type <type>", "user, api_key, osa, optimal, schedule, opencomputer, mcp, or service")
154
+ .requiredOption("--principal-id <id>", "Exact principal ID")
155
+ .option("--workspace <id>", "Optional workspace restriction")
156
+ .option("--expires-at <iso8601>", "Optional expiration")
157
+ .option("--constraints <json>", "Additional fail-closed constraints", "{}")
158
+ .option("--json", "Output JSON")
159
+ .action(async (capabilityName, opts) => {
160
+ try {
161
+ const client = authority();
162
+ const capability = await client.requireCapability(capabilityName);
163
+ const grant = await client.createGrant({
164
+ capability: {
165
+ name: capability.name,
166
+ fingerprint: capability.fingerprint,
167
+ },
168
+ principal_type: opts.principalType,
169
+ principal_id: opts.principalId,
170
+ ...(opts.workspace ? { workspace_id: opts.workspace } : {}),
171
+ ...(opts.expiresAt ? { expires_at: opts.expiresAt } : {}),
172
+ constraints: parseJson(opts.constraints),
173
+ });
174
+ if (isJsonMode(opts))
175
+ return printJson({ data: grant });
176
+ console.log(chalk.green(`Grant created: ${grant.id}`));
177
+ }
178
+ catch (error) {
179
+ handleError(error);
180
+ }
181
+ });
182
+ grants
183
+ .command("revoke <id>")
184
+ .description("Revoke a standing grant immediately")
185
+ .option("--json", "Output JSON")
186
+ .action(async (id, opts) => {
187
+ try {
188
+ const grant = await authority().revokeGrant(id);
189
+ if (isJsonMode(opts))
190
+ return printJson({ data: grant });
191
+ console.log(chalk.green(`Grant revoked: ${grant.id}`));
192
+ }
193
+ catch (error) {
194
+ handleError(error);
195
+ }
196
+ });
197
+ actions
198
+ .command("receipts")
199
+ .description("List immutable action authority receipts")
200
+ .option("--limit <count>", "Maximum rows", "100")
201
+ .option("--json", "Output JSON")
202
+ .action(async (opts) => {
203
+ try {
204
+ const parsedLimit = Number.parseInt(opts.limit ?? "100", 10);
205
+ const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? 100 : parsedLimit;
206
+ const rows = await authority().receipts(limit);
207
+ if (isJsonMode(opts))
208
+ return printJson({ data: rows });
209
+ renderTable(rows, [
210
+ { header: "TIME", key: "occurred_at", width: 24 },
211
+ { header: "ACTION", key: "capability_name", width: 28 },
212
+ { header: "SURFACE", key: "surface", width: 14 },
213
+ { header: "DECISION", key: "decision", width: 20 },
214
+ { header: "RECEIPT", key: "id", width: 12 },
215
+ ]);
216
+ }
217
+ catch (error) {
218
+ handleError(error);
219
+ }
220
+ });
221
+ }
222
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/commands/actions.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/commands/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAM3C,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEL,0BAA0B,EAG3B,MAAM,qBAAqB,CAAC;AAe7B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAiBnE;AAwBD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAKlC;AAYD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC;IAAE,UAAU,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAgJ/D;AAyGD,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IACjD,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,eAAe,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE;QACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;CACH,GAAG,OAAO,CAAC;IACV,SAAS,EAAE,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;IACzD,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CAqID;AAoED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuoB/C"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/commands/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAM3C,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEL,0BAA0B,EAG3B,MAAM,qBAAqB,CAAC;AAgB7B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAiBnE;AA6DD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAKlC;AAYD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC;IAAE,UAAU,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAgJ/D;AA0GD,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IACjD,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,eAAe,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE;QACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;CACH,GAAG,OAAO,CAAC;IACV,SAAS,EAAE,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;IACzD,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CAqID;AAoED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAojC/C"}
@@ -12,6 +12,7 @@ import { loadLocalLink } from "./link.js";
12
12
  import { loadAcceptanceContract, saveReleaseReceipt, verifyApplicationRelease, } from "../app-release.js";
13
13
  import { applicationIdempotencyKey, createApplicationOperation, loadApplicationOperation, updateApplicationOperation, } from "../app-operation.js";
14
14
  import { handleError, isJsonMode, printJson } from "./util.js";
15
+ import { diagnoseAppDocument } from "../app-document.js";
15
16
  export function requireApplicationLink(dir) {
16
17
  const link = loadLocalLink(dir);
17
18
  if (!link?.deploymentId || !link.name) {
@@ -45,6 +46,28 @@ function boolValue(value, key) {
45
46
  const found = record(value)[key];
46
47
  return typeof found === "boolean" ? found : undefined;
47
48
  }
49
+ function parseJsonObject(value, option) {
50
+ if (!value)
51
+ return {};
52
+ let parsed;
53
+ try {
54
+ parsed = JSON.parse(value);
55
+ }
56
+ catch {
57
+ throw new UserError(`${option} must be valid JSON.`, `Pass a JSON object, for example ${option} '{"enabled":true}'.`);
58
+ }
59
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
60
+ throw new UserError(`${option} must be a JSON object.`, `Pass an object, not ${Array.isArray(parsed) ? "an array" : typeof parsed}.`);
61
+ }
62
+ return parsed;
63
+ }
64
+ function parseNonNegativeInteger(value, option) {
65
+ const parsed = Number(value);
66
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
67
+ throw new UserError(`${option} must be a non-negative integer.`, `Received ${JSON.stringify(value)}.`);
68
+ }
69
+ return parsed;
70
+ }
48
71
  export async function getRelease(client, deploymentId, releaseId) {
49
72
  const raw = await client.apiGet(`/api/v1/deployments/${encodeURIComponent(deploymentId)}/releases/${encodeURIComponent(releaseId)}`);
50
73
  return deploymentPayload(raw);
@@ -169,7 +192,8 @@ async function verifyLinkedRelease(client, dir, link, releaseId, contractPath, r
169
192
  inspection.migration_verified ||
170
193
  verificationEvidence?.migration_verified === true;
171
194
  inspection.policy_verified =
172
- inspection.policy_verified || verificationEvidence?.policy_verified === true;
195
+ inspection.policy_verified ||
196
+ verificationEvidence?.policy_verified === true;
173
197
  const receipt = await verifyApplicationRelease({
174
198
  application: link.name,
175
199
  environment: link.environment,
@@ -472,6 +496,324 @@ export function register(program) {
472
496
  handleError(err);
473
497
  }
474
498
  });
499
+ const documents = app
500
+ .command("documents")
501
+ .description("Inspect durable generated App Documents");
502
+ documents
503
+ .command("list")
504
+ .description("List durable apps in the selected workspace")
505
+ .option("--workspace <id>", "Workspace ID")
506
+ .option("--json", "Output machine-readable App Documents")
507
+ .action(async (opts) => {
508
+ try {
509
+ const config = loadConfig();
510
+ const workspaceId = opts.workspace ?? config.workspace;
511
+ if (!workspaceId) {
512
+ throw new UserError("A workspace is required to list App Documents.", "Pass --workspace <id> or select a CLI workspace context.");
513
+ }
514
+ const query = new URLSearchParams({ workspace_id: workspaceId });
515
+ const payload = await new MiosaClient(config).apiGet(`/api/v1/builder/apps?${query.toString()}`);
516
+ if (isJsonMode(opts)) {
517
+ printJson({ ok: true, data: payload, error: null });
518
+ return;
519
+ }
520
+ console.log(JSON.stringify(payload, null, 2));
521
+ }
522
+ catch (err) {
523
+ handleError(err);
524
+ }
525
+ });
526
+ documents
527
+ .command("show <id>")
528
+ .description("Show one durable App Document")
529
+ .option("--json", "Output machine-readable App Document")
530
+ .action(async (id, opts) => {
531
+ try {
532
+ const payload = await new MiosaClient(loadConfig()).apiGet(`/api/v1/builder/apps/${encodeURIComponent(id)}`);
533
+ if (isJsonMode(opts)) {
534
+ printJson({ ok: true, data: payload, error: null });
535
+ return;
536
+ }
537
+ console.log(JSON.stringify(payload, null, 2));
538
+ }
539
+ catch (err) {
540
+ handleError(err);
541
+ }
542
+ });
543
+ documents
544
+ .command("doctor <id>")
545
+ .description("Verify workspace, venue, declarations, and exact approval")
546
+ .option("--workspace <id>", "Expected workspace ID")
547
+ .option("--json", "Output a stable diagnostic contract")
548
+ .action(async (id, opts) => {
549
+ try {
550
+ const config = loadConfig();
551
+ const client = new MiosaClient(config);
552
+ const [payload, platformDiagnostics] = await Promise.all([
553
+ client.apiGet(`/api/v1/builder/apps/${encodeURIComponent(id)}`),
554
+ client.apiGet(`/api/v1/builder/apps/${encodeURIComponent(id)}/diagnostics`),
555
+ ]);
556
+ const result = diagnoseAppDocument(payload, opts.workspace ?? config.workspace, platformDiagnostics);
557
+ if (isJsonMode(opts)) {
558
+ printJson({
559
+ ok: result.ok,
560
+ data: result,
561
+ error: result.ok
562
+ ? null
563
+ : {
564
+ code: "APP_DOCUMENT_DIAGNOSTIC_FAILED",
565
+ message: "One or more App Document checks failed.",
566
+ },
567
+ });
568
+ }
569
+ else {
570
+ console.log(JSON.stringify(result, null, 2));
571
+ }
572
+ if (!result.ok)
573
+ process.exitCode = 1;
574
+ }
575
+ catch (err) {
576
+ handleError(err);
577
+ }
578
+ });
579
+ documents
580
+ .command("approve <id>")
581
+ .description("Approve the current exact app version for release publishing")
582
+ .requiredOption("--release <id>", "Immutable candidate release ID")
583
+ .option("--reason <reason>", "Review reason")
584
+ .option("--json", "Output the exact approval")
585
+ .action(async (id, opts) => {
586
+ try {
587
+ const payload = await new MiosaClient(loadConfig()).apiPost(`/api/v1/builder/apps/${encodeURIComponent(id)}/approvals`, { reason: opts.reason, release_id: opts.release });
588
+ if (isJsonMode(opts)) {
589
+ printJson({ ok: true, data: payload, error: null });
590
+ return;
591
+ }
592
+ console.log(JSON.stringify(payload, null, 2));
593
+ }
594
+ catch (err) {
595
+ handleError(err);
596
+ }
597
+ });
598
+ documents
599
+ .command("revoke <id>")
600
+ .description("Revoke one exact-version review approval")
601
+ .requiredOption("--approval <id>", "Approval ID")
602
+ .option("--json", "Output machine-readable result")
603
+ .action(async (id, opts) => {
604
+ try {
605
+ await new MiosaClient(loadConfig()).apiPost(`/api/v1/builder/apps/${encodeURIComponent(id)}/approvals/${encodeURIComponent(opts.approval)}/revoke`, {});
606
+ const result = {
607
+ app_document_id: id,
608
+ approval_id: opts.approval,
609
+ revoked: true,
610
+ };
611
+ if (isJsonMode(opts)) {
612
+ printJson({ ok: true, data: result, error: null });
613
+ return;
614
+ }
615
+ console.log(JSON.stringify(result, null, 2));
616
+ }
617
+ catch (err) {
618
+ handleError(err);
619
+ }
620
+ });
621
+ const data = documents
622
+ .command("data")
623
+ .description("Read and write declared durable app collections");
624
+ data
625
+ .command("list <id> <collection>")
626
+ .description("List records in one declared app collection")
627
+ .option("--limit <count>", "Maximum records", "100")
628
+ .option("--json", "Output machine-readable records")
629
+ .action(async (id, collection, opts) => {
630
+ try {
631
+ const limit = parseNonNegativeInteger(opts.limit, "--limit");
632
+ const payload = await new MiosaClient(loadConfig()).apiGet(`/api/v1/builder/apps/${encodeURIComponent(id)}/data/${encodeURIComponent(collection)}?limit=${limit}`);
633
+ if (isJsonMode(opts)) {
634
+ printJson({ ok: true, data: payload, error: null });
635
+ return;
636
+ }
637
+ console.log(JSON.stringify(payload, null, 2));
638
+ }
639
+ catch (err) {
640
+ handleError(err);
641
+ }
642
+ });
643
+ data
644
+ .command("get <id> <collection> <key>")
645
+ .description("Read one exact app collection record")
646
+ .option("--json", "Output a machine-readable record")
647
+ .action(async (id, collection, key, opts) => {
648
+ try {
649
+ const payload = await new MiosaClient(loadConfig()).apiGet(`/api/v1/builder/apps/${encodeURIComponent(id)}/data/${encodeURIComponent(collection)}/${encodeURIComponent(key)}`);
650
+ if (isJsonMode(opts)) {
651
+ printJson({ ok: true, data: payload, error: null });
652
+ return;
653
+ }
654
+ console.log(JSON.stringify(payload, null, 2));
655
+ }
656
+ catch (err) {
657
+ handleError(err);
658
+ }
659
+ });
660
+ data
661
+ .command("put <id> <collection> <key>")
662
+ .description("Create or update one app collection record")
663
+ .requiredOption("--value <json>", "JSON object value")
664
+ .option("--expected-version <number>", "Exact current version")
665
+ .option("--json", "Output the stored record")
666
+ .action(async (id, collection, key, opts) => {
667
+ try {
668
+ const body = {
669
+ value: parseJsonObject(opts.value, "--value"),
670
+ };
671
+ if (opts.expectedVersion !== undefined) {
672
+ body["expected_version"] = parseNonNegativeInteger(opts.expectedVersion, "--expected-version");
673
+ }
674
+ const payload = await new MiosaClient(loadConfig()).apiPut(`/api/v1/builder/apps/${encodeURIComponent(id)}/data/${encodeURIComponent(collection)}/${encodeURIComponent(key)}`, body);
675
+ if (isJsonMode(opts)) {
676
+ printJson({ ok: true, data: payload, error: null });
677
+ return;
678
+ }
679
+ console.log(JSON.stringify(payload, null, 2));
680
+ }
681
+ catch (err) {
682
+ handleError(err);
683
+ }
684
+ });
685
+ data
686
+ .command("delete <id> <collection> <key>")
687
+ .description("Delete one exact app collection record")
688
+ .option("--expected-version <number>", "Exact current version")
689
+ .option("--json", "Output machine-readable result")
690
+ .action(async (id, collection, key, opts) => {
691
+ try {
692
+ const query = opts.expectedVersion === undefined
693
+ ? ""
694
+ : `?expected_version=${parseNonNegativeInteger(opts.expectedVersion, "--expected-version")}`;
695
+ await new MiosaClient(loadConfig()).apiDelete(`/api/v1/builder/apps/${encodeURIComponent(id)}/data/${encodeURIComponent(collection)}/${encodeURIComponent(key)}${query}`);
696
+ const result = {
697
+ app_document_id: id,
698
+ collection,
699
+ key,
700
+ deleted: true,
701
+ };
702
+ if (isJsonMode(opts)) {
703
+ printJson({ ok: true, data: result, error: null });
704
+ return;
705
+ }
706
+ console.log(JSON.stringify(result, null, 2));
707
+ }
708
+ catch (err) {
709
+ handleError(err);
710
+ }
711
+ });
712
+ const automations = documents
713
+ .command("automations")
714
+ .description("Operate durable, authority-governed app automation runs");
715
+ automations
716
+ .command("list <id>")
717
+ .description("List automation runs for one app")
718
+ .option("--limit <count>", "Maximum runs", "100")
719
+ .option("--json", "Output machine-readable runs")
720
+ .action(async (id, opts) => {
721
+ try {
722
+ const limit = parseNonNegativeInteger(opts.limit, "--limit");
723
+ const payload = await new MiosaClient(loadConfig()).apiGet(`/api/v1/builder/apps/${encodeURIComponent(id)}/automation-runs?limit=${limit}`);
724
+ if (isJsonMode(opts)) {
725
+ printJson({ ok: true, data: payload, error: null });
726
+ return;
727
+ }
728
+ console.log(JSON.stringify(payload, null, 2));
729
+ }
730
+ catch (err) {
731
+ handleError(err);
732
+ }
733
+ });
734
+ automations
735
+ .command("start <id> <automation>")
736
+ .description("Start one reviewed automation")
737
+ .option("--trigger <json>", "Trigger metadata JSON", "{}")
738
+ .option("--json", "Output the durable run")
739
+ .action(async (id, automation, opts) => {
740
+ try {
741
+ const payload = await new MiosaClient(loadConfig()).apiPost(`/api/v1/builder/apps/${encodeURIComponent(id)}/automations/${encodeURIComponent(automation)}/runs`, { trigger: parseJsonObject(opts.trigger, "--trigger") });
742
+ if (isJsonMode(opts)) {
743
+ printJson({ ok: true, data: payload, error: null });
744
+ return;
745
+ }
746
+ console.log(JSON.stringify(payload, null, 2));
747
+ }
748
+ catch (err) {
749
+ handleError(err);
750
+ }
751
+ });
752
+ automations
753
+ .command("claim <id> <run>")
754
+ .description("Claim or resume the current automation step")
755
+ .option("--json", "Output the exact authority-bound claim")
756
+ .action(async (id, run, opts) => {
757
+ try {
758
+ const payload = await new MiosaClient(loadConfig()).apiPost(`/api/v1/builder/apps/${encodeURIComponent(id)}/automation-runs/${encodeURIComponent(run)}/claim`, {});
759
+ if (isJsonMode(opts)) {
760
+ printJson({ ok: true, data: payload, error: null });
761
+ return;
762
+ }
763
+ console.log(JSON.stringify(payload, null, 2));
764
+ }
765
+ catch (err) {
766
+ handleError(err);
767
+ }
768
+ });
769
+ automations
770
+ .command("complete <id> <run>")
771
+ .description("Complete the exact claimed automation step")
772
+ .requiredOption("--cursor <number>", "Claimed step cursor")
773
+ .requiredOption("--idempotency-key <key>", "Claimed idempotency key")
774
+ .option("--output <json>", "Step output JSON object", "{}")
775
+ .option("--json", "Output the updated run")
776
+ .action(async (id, run, opts) => {
777
+ try {
778
+ const payload = await new MiosaClient(loadConfig()).apiPost(`/api/v1/builder/apps/${encodeURIComponent(id)}/automation-runs/${encodeURIComponent(run)}/complete`, {
779
+ cursor: parseNonNegativeInteger(opts.cursor, "--cursor"),
780
+ idempotency_key: opts.idempotencyKey,
781
+ output: parseJsonObject(opts.output, "--output"),
782
+ });
783
+ if (isJsonMode(opts)) {
784
+ printJson({ ok: true, data: payload, error: null });
785
+ return;
786
+ }
787
+ console.log(JSON.stringify(payload, null, 2));
788
+ }
789
+ catch (err) {
790
+ handleError(err);
791
+ }
792
+ });
793
+ automations
794
+ .command("fail <id> <run>")
795
+ .description("Fail the exact claimed automation step")
796
+ .requiredOption("--cursor <number>", "Claimed step cursor")
797
+ .requiredOption("--idempotency-key <key>", "Claimed idempotency key")
798
+ .requiredOption("--reason <reason>", "Failure reason")
799
+ .option("--json", "Output the updated run")
800
+ .action(async (id, run, opts) => {
801
+ try {
802
+ const payload = await new MiosaClient(loadConfig()).apiPost(`/api/v1/builder/apps/${encodeURIComponent(id)}/automation-runs/${encodeURIComponent(run)}/fail`, {
803
+ cursor: parseNonNegativeInteger(opts.cursor, "--cursor"),
804
+ idempotency_key: opts.idempotencyKey,
805
+ reason: opts.reason,
806
+ });
807
+ if (isJsonMode(opts)) {
808
+ printJson({ ok: true, data: payload, error: null });
809
+ return;
810
+ }
811
+ console.log(JSON.stringify(payload, null, 2));
812
+ }
813
+ catch (err) {
814
+ handleError(err);
815
+ }
816
+ });
475
817
  app
476
818
  .command("pull")
477
819
  .argument("[path]", "Local app directory", ".")