primitive-admin 1.1.0-alpha.4 → 1.1.0-alpha.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/README.md +325 -31
  2. package/assets/skill/skills/primitive-platform/SKILL.md +281 -0
  3. package/dist/bin/primitive.d.ts +2 -0
  4. package/dist/bin/primitive.js +266 -16
  5. package/dist/bin/primitive.js.map +1 -1
  6. package/dist/src/commands/admins.d.ts +2 -0
  7. package/dist/src/commands/admins.js +123 -18
  8. package/dist/src/commands/admins.js.map +1 -1
  9. package/dist/src/commands/analytics.d.ts +2 -0
  10. package/dist/src/commands/analytics.js +464 -55
  11. package/dist/src/commands/analytics.js.map +1 -1
  12. package/dist/src/commands/apps.d.ts +2 -0
  13. package/dist/src/commands/apps.js +55 -13
  14. package/dist/src/commands/apps.js.map +1 -1
  15. package/dist/src/commands/auth.d.ts +2 -0
  16. package/dist/src/commands/auth.js +177 -7
  17. package/dist/src/commands/auth.js.map +1 -1
  18. package/dist/src/commands/blob-buckets.d.ts +2 -0
  19. package/dist/src/commands/blob-buckets.js +422 -0
  20. package/dist/src/commands/blob-buckets.js.map +1 -0
  21. package/dist/src/commands/catalog.d.ts +2 -0
  22. package/dist/src/commands/catalog.js +34 -35
  23. package/dist/src/commands/catalog.js.map +1 -1
  24. package/dist/src/commands/collection-type-configs.d.ts +2 -0
  25. package/dist/src/commands/collection-type-configs.js +178 -0
  26. package/dist/src/commands/collection-type-configs.js.map +1 -0
  27. package/dist/src/commands/collections.d.ts +2 -0
  28. package/dist/src/commands/collections.js +515 -0
  29. package/dist/src/commands/collections.js.map +1 -0
  30. package/dist/src/commands/comparisons.d.ts +2 -0
  31. package/dist/src/commands/comparisons.js +6 -6
  32. package/dist/src/commands/comparisons.js.map +1 -1
  33. package/dist/src/commands/cron-triggers.d.ts +2 -0
  34. package/dist/src/commands/cron-triggers.js +357 -0
  35. package/dist/src/commands/cron-triggers.js.map +1 -0
  36. package/dist/src/commands/database-types.d.ts +2 -0
  37. package/dist/src/commands/database-types.js +471 -0
  38. package/dist/src/commands/database-types.js.map +1 -0
  39. package/dist/src/commands/databases.d.ts +2 -0
  40. package/dist/src/commands/databases.js +1462 -83
  41. package/dist/src/commands/databases.js.map +1 -1
  42. package/dist/src/commands/documents.d.ts +2 -0
  43. package/dist/src/commands/documents.js +518 -11
  44. package/dist/src/commands/documents.js.map +1 -1
  45. package/dist/src/commands/email-templates.d.ts +2 -0
  46. package/dist/src/commands/email-templates.js +281 -0
  47. package/dist/src/commands/email-templates.js.map +1 -0
  48. package/dist/src/commands/env.d.ts +12 -0
  49. package/dist/src/commands/env.js +260 -0
  50. package/dist/src/commands/env.js.map +1 -0
  51. package/dist/src/commands/group-type-configs.d.ts +2 -0
  52. package/dist/src/commands/group-type-configs.js +181 -0
  53. package/dist/src/commands/group-type-configs.js.map +1 -0
  54. package/dist/src/commands/groups.d.ts +2 -0
  55. package/dist/src/commands/groups.js +45 -43
  56. package/dist/src/commands/groups.js.map +1 -1
  57. package/dist/src/commands/guides.d.ts +159 -0
  58. package/dist/src/commands/guides.js +449 -35
  59. package/dist/src/commands/guides.js.map +1 -1
  60. package/dist/src/commands/init.d.ts +17 -0
  61. package/dist/src/commands/init.js +811 -201
  62. package/dist/src/commands/init.js.map +1 -1
  63. package/dist/src/commands/integrations.d.ts +2 -0
  64. package/dist/src/commands/integrations.js +533 -46
  65. package/dist/src/commands/integrations.js.map +1 -1
  66. package/dist/src/commands/llm.d.ts +2 -0
  67. package/dist/src/commands/llm.js +4 -2
  68. package/dist/src/commands/llm.js.map +1 -1
  69. package/dist/src/commands/prompts.d.ts +2 -0
  70. package/dist/src/commands/prompts.js +50 -52
  71. package/dist/src/commands/prompts.js.map +1 -1
  72. package/dist/src/commands/rule-sets.d.ts +3 -0
  73. package/dist/src/commands/rule-sets.js +388 -0
  74. package/dist/src/commands/rule-sets.js.map +1 -0
  75. package/dist/src/commands/scripts.d.ts +2 -0
  76. package/dist/src/commands/scripts.js +667 -0
  77. package/dist/src/commands/scripts.js.map +1 -0
  78. package/dist/src/commands/secrets.d.ts +2 -0
  79. package/dist/src/commands/secrets.js +108 -0
  80. package/dist/src/commands/secrets.js.map +1 -0
  81. package/dist/src/commands/skill.d.ts +2 -0
  82. package/dist/src/commands/skill.js +29 -0
  83. package/dist/src/commands/skill.js.map +1 -0
  84. package/dist/src/commands/sync.d.ts +174 -0
  85. package/dist/src/commands/sync.js +4392 -235
  86. package/dist/src/commands/sync.js.map +1 -1
  87. package/dist/src/commands/tokens.d.ts +2 -0
  88. package/dist/src/commands/tokens.js +122 -19
  89. package/dist/src/commands/tokens.js.map +1 -1
  90. package/dist/src/commands/users.d.ts +2 -0
  91. package/dist/src/commands/users.js +440 -22
  92. package/dist/src/commands/users.js.map +1 -1
  93. package/dist/src/commands/waitlist.d.ts +2 -0
  94. package/dist/src/commands/waitlist.js +10 -10
  95. package/dist/src/commands/waitlist.js.map +1 -1
  96. package/dist/src/commands/webhooks.d.ts +2 -0
  97. package/dist/src/commands/webhooks.js +391 -0
  98. package/dist/src/commands/webhooks.js.map +1 -0
  99. package/dist/src/commands/workflows.d.ts +49 -0
  100. package/dist/src/commands/workflows.js +1009 -123
  101. package/dist/src/commands/workflows.js.map +1 -1
  102. package/dist/src/lib/api-client.d.ts +1272 -0
  103. package/dist/src/lib/api-client.js +1115 -83
  104. package/dist/src/lib/api-client.js.map +1 -1
  105. package/dist/src/lib/auth-flow.d.ts +8 -0
  106. package/dist/src/lib/block-layout.d.ts +160 -0
  107. package/dist/src/lib/block-layout.js +451 -0
  108. package/dist/src/lib/block-layout.js.map +1 -0
  109. package/dist/src/lib/cli-manifest.d.ts +60 -0
  110. package/dist/src/lib/cli-manifest.js +70 -0
  111. package/dist/src/lib/cli-manifest.js.map +1 -0
  112. package/dist/src/lib/config.d.ts +53 -0
  113. package/dist/src/lib/config.js +92 -53
  114. package/dist/src/lib/config.js.map +1 -1
  115. package/dist/src/lib/confirm-prompt.d.ts +83 -0
  116. package/dist/src/lib/confirm-prompt.js +110 -0
  117. package/dist/src/lib/confirm-prompt.js.map +1 -0
  118. package/dist/src/lib/constants.d.ts +2 -0
  119. package/dist/src/lib/constants.js +3 -0
  120. package/dist/src/lib/constants.js.map +1 -0
  121. package/dist/src/lib/crash-handlers.d.ts +20 -0
  122. package/dist/src/lib/crash-handlers.js +49 -0
  123. package/dist/src/lib/crash-handlers.js.map +1 -0
  124. package/dist/src/lib/credentials-store.d.ts +79 -0
  125. package/dist/src/lib/credentials-store.js +307 -0
  126. package/dist/src/lib/credentials-store.js.map +1 -0
  127. package/dist/src/lib/csv.d.ts +48 -0
  128. package/dist/src/lib/csv.js +177 -0
  129. package/dist/src/lib/csv.js.map +1 -0
  130. package/dist/src/lib/db-codegen/dbFingerprint.d.ts +10 -0
  131. package/dist/src/lib/db-codegen/dbFingerprint.js +17 -0
  132. package/dist/src/lib/db-codegen/dbFingerprint.js.map +1 -0
  133. package/dist/src/lib/db-codegen/dbGenerator.d.ts +111 -0
  134. package/dist/src/lib/db-codegen/dbGenerator.js +371 -0
  135. package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -0
  136. package/dist/src/lib/db-codegen/dbNaming.d.ts +45 -0
  137. package/dist/src/lib/db-codegen/dbNaming.js +104 -0
  138. package/dist/src/lib/db-codegen/dbNaming.js.map +1 -0
  139. package/dist/src/lib/db-codegen/dbTemplates.d.ts +97 -0
  140. package/dist/src/lib/db-codegen/dbTemplates.js +159 -0
  141. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -0
  142. package/dist/src/lib/db-codegen/dbTsTypes.d.ts +78 -0
  143. package/dist/src/lib/db-codegen/dbTsTypes.js +112 -0
  144. package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -0
  145. package/dist/src/lib/env-resolver.d.ts +62 -0
  146. package/dist/src/lib/env-resolver.js +121 -0
  147. package/dist/src/lib/env-resolver.js.map +1 -0
  148. package/dist/src/lib/fetch.d.ts +5 -0
  149. package/dist/src/lib/generated-allowlist.d.ts +28 -0
  150. package/dist/src/lib/generated-allowlist.js +213 -0
  151. package/dist/src/lib/generated-allowlist.js.map +1 -0
  152. package/dist/src/lib/init-config.d.ts +59 -0
  153. package/dist/src/lib/init-config.js +113 -0
  154. package/dist/src/lib/init-config.js.map +1 -0
  155. package/dist/src/lib/migration-nag.d.ts +49 -0
  156. package/dist/src/lib/migration-nag.js +163 -0
  157. package/dist/src/lib/migration-nag.js.map +1 -0
  158. package/dist/src/lib/output.d.ts +86 -0
  159. package/dist/src/lib/output.js +150 -8
  160. package/dist/src/lib/output.js.map +1 -1
  161. package/dist/src/lib/paginate.d.ts +33 -0
  162. package/dist/src/lib/paginate.js +42 -0
  163. package/dist/src/lib/paginate.js.map +1 -0
  164. package/dist/src/lib/project-config.d.ts +97 -0
  165. package/dist/src/lib/project-config.js +209 -0
  166. package/dist/src/lib/project-config.js.map +1 -0
  167. package/dist/src/lib/query-operators.d.ts +43 -0
  168. package/dist/src/lib/query-operators.js +80 -0
  169. package/dist/src/lib/query-operators.js.map +1 -0
  170. package/dist/src/lib/refresh-admin-credentials.d.ts +65 -0
  171. package/dist/src/lib/refresh-admin-credentials.js +103 -0
  172. package/dist/src/lib/refresh-admin-credentials.js.map +1 -0
  173. package/dist/src/lib/resolve-platform.d.ts +45 -0
  174. package/dist/src/lib/resolve-platform.js +43 -0
  175. package/dist/src/lib/resolve-platform.js.map +1 -0
  176. package/dist/src/lib/skill-installer.d.ts +23 -0
  177. package/dist/src/lib/skill-installer.js +135 -0
  178. package/dist/src/lib/skill-installer.js.map +1 -0
  179. package/dist/src/lib/snapshots.d.ts +99 -0
  180. package/dist/src/lib/snapshots.js +357 -0
  181. package/dist/src/lib/snapshots.js.map +1 -0
  182. package/dist/src/lib/sync-paths.d.ts +72 -0
  183. package/dist/src/lib/sync-paths.js +130 -0
  184. package/dist/src/lib/sync-paths.js.map +1 -0
  185. package/dist/src/lib/template.d.ts +97 -0
  186. package/dist/src/lib/template.js +336 -62
  187. package/dist/src/lib/template.js.map +1 -1
  188. package/dist/src/lib/token-inject.d.ts +56 -0
  189. package/dist/src/lib/token-inject.js +204 -0
  190. package/dist/src/lib/token-inject.js.map +1 -0
  191. package/dist/src/lib/toml-database-config.d.ts +152 -0
  192. package/dist/src/lib/toml-database-config.js +600 -0
  193. package/dist/src/lib/toml-database-config.js.map +1 -0
  194. package/dist/src/lib/toml-metadata-config.d.ts +108 -0
  195. package/dist/src/lib/toml-metadata-config.js +371 -0
  196. package/dist/src/lib/toml-metadata-config.js.map +1 -0
  197. package/dist/src/lib/toml-params-validator.d.ts +129 -0
  198. package/dist/src/lib/toml-params-validator.js +298 -0
  199. package/dist/src/lib/toml-params-validator.js.map +1 -0
  200. package/dist/src/lib/version-check.d.ts +10 -0
  201. package/dist/src/lib/version-check.js +172 -0
  202. package/dist/src/lib/version-check.js.map +1 -0
  203. package/dist/src/lib/workflow-apply.d.ts +66 -0
  204. package/dist/src/lib/workflow-apply.js +117 -0
  205. package/dist/src/lib/workflow-apply.js.map +1 -0
  206. package/dist/src/lib/workflow-fragments.d.ts +41 -0
  207. package/dist/src/lib/workflow-fragments.js +121 -0
  208. package/dist/src/lib/workflow-fragments.js.map +1 -0
  209. package/dist/src/lib/workflow-toml-validator.d.ts +95 -0
  210. package/dist/src/lib/workflow-toml-validator.js +323 -0
  211. package/dist/src/lib/workflow-toml-validator.js.map +1 -0
  212. package/dist/src/types/index.d.ts +520 -0
  213. package/dist/src/validators.d.ts +64 -0
  214. package/dist/src/validators.js +63 -0
  215. package/dist/src/validators.js.map +1 -0
  216. package/package.json +18 -4
@@ -0,0 +1,86 @@
1
+ export interface TableColumn {
2
+ header: string;
3
+ key: string;
4
+ width?: number;
5
+ /**
6
+ * Opt-in flexible sizing (#1065). When `true`, the column is sized from the
7
+ * remaining terminal width (`options.maxWidth ?? process.stdout.columns`)
8
+ * minus the sibling columns' widths and the inter-column padding, so the
9
+ * table shows as much of this column as fits **without wrapping**. Clamped to
10
+ * `[max(flexFloor, header length), flexMax]`. On a non-TTY (`maxWidth`
11
+ * undefined — piped/redirected) there is no width to wrap against, so the
12
+ * column is sized to `flexMax` (or its content width when `flexMax` is
13
+ * unset). Reading the terminal width is gated to flex columns: tables with no
14
+ * flex column never consult `process.stdout.columns` and stay byte-for-byte
15
+ * (and TTY-) unchanged.
16
+ */
17
+ flex?: boolean;
18
+ /** Minimum width for a `flex` column. Default 0 (header length is always honored). */
19
+ flexFloor?: number;
20
+ /** Maximum width for a `flex` column. Default unbounded. */
21
+ flexMax?: number;
22
+ align?: "left" | "right" | "center";
23
+ format?: (value: any) => string;
24
+ /**
25
+ * Opt-in truncation. When `true` (and the column has a resolved width — a
26
+ * fixed `width` or a computed `flex` width), cell values longer than that
27
+ * width are ellipsized to fit the column so downstream columns stay aligned.
28
+ * Defaults to `false` so existing tables keep their current non-truncating
29
+ * behavior — only columns that explicitly opt in are clipped.
30
+ */
31
+ truncate?: boolean;
32
+ }
33
+ export declare function formatTable(data: Record<string, any>[], columns: TableColumn[], options?: {
34
+ maxWidth?: number;
35
+ }): string;
36
+ export declare function success(message: string): void;
37
+ export declare function error(message: string): void;
38
+ /**
39
+ * Render an API error (or any Error) with its message plus the server's
40
+ * structured `details` payload, if present. Shared by `sync push`,
41
+ * `workflows create`/`update`, and any command that surfaces server-side
42
+ * validation failures (#1173).
43
+ *
44
+ * The server's error envelope can emit `details` as either:
45
+ * - an **array** of validation-issue strings/objects (e.g. the workflow
46
+ * identity validator's per-step reasons), or
47
+ * - an **object** (#666 schema gate — `{ code, ... }`).
48
+ *
49
+ * Both shapes are rendered without throwing; an absent/empty `details` prints
50
+ * just the message. Duck-typed (reads `.message`/`.details`) so it works on
51
+ * any `ApiError` instance without importing the class — keeping `output.ts`
52
+ * dependency-free.
53
+ */
54
+ export declare function printApiError(err: unknown): void;
55
+ export declare function warn(message: string): void;
56
+ export declare function info(message: string): void;
57
+ export declare function dim(message: string): void;
58
+ export declare function heading(message: string): void;
59
+ export declare function json(data: any): void;
60
+ export declare function formatDate(date: string | Date | null | undefined): string;
61
+ export declare function formatStatus(status: string | undefined | null): string;
62
+ export declare function formatId(id: string): string;
63
+ export declare function formatBoolean(value: boolean | undefined | null): string;
64
+ export declare function formatNumber(value: number | undefined | null): string;
65
+ export declare function formatDuration(ms: number | undefined | null): string;
66
+ export declare function formatPercent(value: number | undefined | null): string;
67
+ export declare function keyValue(label: string, value: string | number | boolean | null | undefined): void;
68
+ /**
69
+ * Print a `label: value` line on **stdout** as part of a command's primary
70
+ * data output (e.g., `primitive integrations get <id>`,
71
+ * `primitive workflows get <id>`). Same visual rendering as `keyValue()`,
72
+ * but on the data stream so the value survives `> out.txt` redirection.
73
+ *
74
+ * Use `keyValue()` (stderr) for post-action diagnostic summaries; use
75
+ * `result()` (stdout) for fields the caller specifically requested.
76
+ */
77
+ export declare function result(label: string, value: string | number | boolean | null | undefined): void;
78
+ export declare function divider(): void;
79
+ /**
80
+ * In-place progress indicator for long-running commands (e.g. polling a
81
+ * batch run). Writes to stderr so it can't corrupt JSON on stdout under
82
+ * `--json`. Callers should follow the final progress line with `progressEnd()`
83
+ * to print a trailing newline.
84
+ */
85
+ export declare function progress(message: string): void;
86
+ export declare function progressEnd(): void;
@@ -1,5 +1,24 @@
1
1
  import chalk from "chalk";
2
- export function formatTable(data, columns) {
2
+ /**
3
+ * Ellipsize `str` (its visible, ANSI-stripped length) to at most `width`
4
+ * characters. Strings already within `width` are returned unchanged. Very
5
+ * narrow widths still keep a sensible result: width 1-3 returns leading dots.
6
+ *
7
+ * NOTE: assumes the value carries no ANSI styling (the only opt-in caller —
8
+ * the guides DESCRIPTION column — passes plain strings). Truncating mid-escape
9
+ * would corrupt styling, so truncation is opt-in per column rather than global.
10
+ */
11
+ function truncateToWidth(str, width) {
12
+ const stripped = stripAnsi(str);
13
+ if (stripped.length <= width)
14
+ return str;
15
+ if (width <= 0)
16
+ return "";
17
+ if (width <= 3)
18
+ return ".".repeat(width);
19
+ return stripped.slice(0, width - 1) + "…";
20
+ }
21
+ export function formatTable(data, columns, options) {
3
22
  if (data.length === 0) {
4
23
  return chalk.dim("No results found.");
5
24
  }
@@ -12,6 +31,33 @@ export function formatTable(data, columns) {
12
31
  }));
13
32
  return col.width ?? Math.max(headerWidth, maxDataWidth);
14
33
  });
34
+ // Flex pass (#1065): size the first column marked `flex` from the remaining
35
+ // terminal width so the table shows as much as fits without ever wrapping.
36
+ // The sibling widths above are already content-derived, so subtracting their
37
+ // ACTUAL widths plus the exact `2 * (N - 1)` inter-column padding makes the
38
+ // no-wrap guarantee structural rather than maintained by hand. Gated to flex
39
+ // columns so non-flex tables never read `process.stdout.columns`.
40
+ const flexIndex = columns.findIndex((col) => col.flex);
41
+ if (flexIndex !== -1) {
42
+ const col = columns[flexIndex];
43
+ const floor = Math.max(col.flexFloor ?? 0, col.header.length);
44
+ const cap = col.flexMax ?? Infinity;
45
+ const maxWidth = options?.maxWidth ?? process.stdout.columns;
46
+ if (typeof maxWidth === "number") {
47
+ const siblingWidth = widths.reduce((sum, w, i) => (i === flexIndex ? sum : sum + w), 0);
48
+ const padding = 2 * (columns.length - 1);
49
+ const avail = maxWidth - siblingWidth - padding;
50
+ // Clamp to [floor, cap]; never below the floor (so the header/min content
51
+ // stays readable) and never negative.
52
+ widths[flexIndex] = Math.min(cap, Math.max(floor, avail));
53
+ }
54
+ else {
55
+ // Non-TTY (piped/redirected): no terminal width to wrap against. Show as
56
+ // much as the cap allows — full content up to the contract max — falling
57
+ // back to the content-derived width when no cap is set.
58
+ widths[flexIndex] = cap === Infinity ? widths[flexIndex] : cap;
59
+ }
60
+ }
15
61
  // Format header
16
62
  const header = columns
17
63
  .map((col, i) => {
@@ -24,7 +70,13 @@ export function formatTable(data, columns) {
24
70
  // Format rows
25
71
  const rows = data.map((row) => columns
26
72
  .map((col, i) => {
27
- const value = col.format ? col.format(row[col.key]) : String(row[col.key] ?? "");
73
+ let value = col.format ? col.format(row[col.key]) : String(row[col.key] ?? "");
74
+ // Opt-in: clip over-long cells to the column's resolved width (a fixed
75
+ // `width` or a computed `flex` width) so the columns that follow stay
76
+ // aligned (e.g. guides DESCRIPTION before LANGUAGES).
77
+ if (col.truncate && (col.width !== undefined || col.flex)) {
78
+ value = truncateToWidth(value, widths[i]);
79
+ }
28
80
  return padString(value, widths[i], col.align ?? "left");
29
81
  })
30
82
  .join(" "));
@@ -47,23 +99,84 @@ function stripAnsi(str) {
47
99
  // Simple ANSI escape code stripper
48
100
  return str.replace(/\x1b\[[0-9;]*m/g, "");
49
101
  }
102
+ // Stream-routing convention (see issue #695):
103
+ // - data → stdout (`json`, `result`, plus the formatter helpers below
104
+ // that just return strings for callers to print themselves).
105
+ // - diagnostics → stderr (`success`, `warn`, `info`, `dim`, `heading`,
106
+ // `keyValue`, `divider`, `error`).
107
+ //
108
+ // This mirrors `git`/`kubectl`/`aws`/`gh` so that any command with a `--json`
109
+ // flag emits a single parseable JSON document on stdout, regardless of
110
+ // status, warning, or progress text the same command may print. Callers
111
+ // running interactively still see diagnostics by default because terminals
112
+ // display stderr; users redirecting `2>/dev/null` get a quiet pipe; users
113
+ // running `2>&1` get everything mixed.
114
+ //
115
+ // `result()` vs. `keyValue()` (data vs. diagnostic split):
116
+ // `keyValue()` is a *diagnostic* helper — use it for the `key: value`
117
+ // summary lines printed *after* a side-effecting command like `apps create`,
118
+ // `workflows update`, or `secrets set` (those summaries are nice context but
119
+ // are not what the caller asked the command to produce). `result()` is the
120
+ // *data* counterpart — use it for the primary fields a `get` / `show` /
121
+ // `describe` command emits, where the caller ran the command specifically
122
+ // to read those fields. Keeping the two on different streams means
123
+ // `primitive integrations get foo > out.txt` produces a non-empty `out.txt`
124
+ // even though the same command's status diagnostics still go to stderr.
50
125
  export function success(message) {
51
- console.log(chalk.green("✓") + " " + message);
126
+ console.error(chalk.green("✓") + " " + message);
52
127
  }
53
128
  export function error(message) {
54
129
  console.error(chalk.red("✗") + " " + message);
55
130
  }
131
+ /**
132
+ * Render an API error (or any Error) with its message plus the server's
133
+ * structured `details` payload, if present. Shared by `sync push`,
134
+ * `workflows create`/`update`, and any command that surfaces server-side
135
+ * validation failures (#1173).
136
+ *
137
+ * The server's error envelope can emit `details` as either:
138
+ * - an **array** of validation-issue strings/objects (e.g. the workflow
139
+ * identity validator's per-step reasons), or
140
+ * - an **object** (#666 schema gate — `{ code, ... }`).
141
+ *
142
+ * Both shapes are rendered without throwing; an absent/empty `details` prints
143
+ * just the message. Duck-typed (reads `.message`/`.details`) so it works on
144
+ * any `ApiError` instance without importing the class — keeping `output.ts`
145
+ * dependency-free.
146
+ */
147
+ export function printApiError(err) {
148
+ const e = err;
149
+ const message = typeof e?.message === "string" && e.message.length > 0
150
+ ? e.message
151
+ : String(err);
152
+ error(message);
153
+ const details = e?.details;
154
+ if (Array.isArray(details)) {
155
+ for (const detail of details) {
156
+ console.error(` - ${typeof detail === "string" ? detail : JSON.stringify(detail)}`);
157
+ }
158
+ }
159
+ else if (details && typeof details === "object") {
160
+ // Object form (#666 schema gate): render each key so the reason isn't
161
+ // hidden. Skip the redundant `code` (already implied by the message).
162
+ for (const [key, value] of Object.entries(details)) {
163
+ if (key === "code")
164
+ continue;
165
+ console.error(` ${key}: ${typeof value === "string" ? value : JSON.stringify(value)}`);
166
+ }
167
+ }
168
+ }
56
169
  export function warn(message) {
57
- console.log(chalk.yellow("!") + " " + message);
170
+ console.error(chalk.yellow("!") + " " + message);
58
171
  }
59
172
  export function info(message) {
60
- console.log(chalk.blue("i") + " " + message);
173
+ console.error(chalk.blue("i") + " " + message);
61
174
  }
62
175
  export function dim(message) {
63
- console.log(chalk.dim(message));
176
+ console.error(chalk.dim(message));
64
177
  }
65
178
  export function heading(message) {
66
- console.log(chalk.bold.underline(message));
179
+ console.error(chalk.bold.underline(message));
67
180
  }
68
181
  export function json(data) {
69
182
  console.log(JSON.stringify(data, null, 2));
@@ -130,6 +243,23 @@ export function formatPercent(value) {
130
243
  return `${(value * 100).toFixed(1)}%`;
131
244
  }
132
245
  export function keyValue(label, value) {
246
+ const formattedValue = value === null || value === undefined
247
+ ? chalk.dim("-")
248
+ : typeof value === "boolean"
249
+ ? formatBoolean(value)
250
+ : String(value);
251
+ console.error(`${chalk.dim(label + ":")} ${formattedValue}`);
252
+ }
253
+ /**
254
+ * Print a `label: value` line on **stdout** as part of a command's primary
255
+ * data output (e.g., `primitive integrations get <id>`,
256
+ * `primitive workflows get <id>`). Same visual rendering as `keyValue()`,
257
+ * but on the data stream so the value survives `> out.txt` redirection.
258
+ *
259
+ * Use `keyValue()` (stderr) for post-action diagnostic summaries; use
260
+ * `result()` (stdout) for fields the caller specifically requested.
261
+ */
262
+ export function result(label, value) {
133
263
  const formattedValue = value === null || value === undefined
134
264
  ? chalk.dim("-")
135
265
  : typeof value === "boolean"
@@ -138,6 +268,18 @@ export function keyValue(label, value) {
138
268
  console.log(`${chalk.dim(label + ":")} ${formattedValue}`);
139
269
  }
140
270
  export function divider() {
141
- console.log(chalk.dim("-".repeat(60)));
271
+ console.error(chalk.dim("-".repeat(60)));
272
+ }
273
+ /**
274
+ * In-place progress indicator for long-running commands (e.g. polling a
275
+ * batch run). Writes to stderr so it can't corrupt JSON on stdout under
276
+ * `--json`. Callers should follow the final progress line with `progressEnd()`
277
+ * to print a trailing newline.
278
+ */
279
+ export function progress(message) {
280
+ process.stderr.write(`\r${message}`);
281
+ }
282
+ export function progressEnd() {
283
+ process.stderr.write("\n");
142
284
  }
143
285
  //# sourceMappingURL=output.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/lib/output.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/lib/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Cursor-pagination helper used by the CLI's API client.
3
+ *
4
+ * The server exposes cursor-paginated endpoints (e.g. GET /admin/api/admins/me/apps)
5
+ * that return `{ items, nextCursor? }` pages. Callers historically only fetched
6
+ * the first page, silently truncating results (see issue #436). This helper
7
+ * walks every page and aggregates the items in order.
8
+ *
9
+ * Exported separately so the looping contract can be unit-tested without
10
+ * stubbing the full ApiClient.
11
+ */
12
+ export interface PaginatedPage<T> {
13
+ items: T[];
14
+ nextCursor?: string | null;
15
+ }
16
+ export type PageFetcher<T> = (cursor: string | undefined) => Promise<PaginatedPage<T>>;
17
+ export interface PaginateOptions {
18
+ /**
19
+ * Safety net: if the server hands out a non-advancing cursor (same cursor
20
+ * returned repeatedly, or an implausibly long chain), stop after this many
21
+ * pages and throw. Default: 1000.
22
+ */
23
+ maxPages?: number;
24
+ }
25
+ /**
26
+ * Walk every cursor page from `fetchPage` and return the concatenated items.
27
+ *
28
+ * Detects two failure modes that would otherwise hang the CLI:
29
+ * - A cursor that repeats (server returned the same `nextCursor` twice).
30
+ * - A cursor chain longer than `maxPages` (default 1000).
31
+ * Both throw so the caller fails loudly rather than looping forever.
32
+ */
33
+ export declare function paginateAll<T>(fetchPage: PageFetcher<T>, options?: PaginateOptions): Promise<T[]>;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Cursor-pagination helper used by the CLI's API client.
3
+ *
4
+ * The server exposes cursor-paginated endpoints (e.g. GET /admin/api/admins/me/apps)
5
+ * that return `{ items, nextCursor? }` pages. Callers historically only fetched
6
+ * the first page, silently truncating results (see issue #436). This helper
7
+ * walks every page and aggregates the items in order.
8
+ *
9
+ * Exported separately so the looping contract can be unit-tested without
10
+ * stubbing the full ApiClient.
11
+ */
12
+ /**
13
+ * Walk every cursor page from `fetchPage` and return the concatenated items.
14
+ *
15
+ * Detects two failure modes that would otherwise hang the CLI:
16
+ * - A cursor that repeats (server returned the same `nextCursor` twice).
17
+ * - A cursor chain longer than `maxPages` (default 1000).
18
+ * Both throw so the caller fails loudly rather than looping forever.
19
+ */
20
+ export async function paginateAll(fetchPage, options = {}) {
21
+ const maxPages = options.maxPages ?? 1000;
22
+ const all = [];
23
+ const seenCursors = new Set();
24
+ let cursor;
25
+ for (let page = 0; page < maxPages; page++) {
26
+ const resp = await fetchPage(cursor);
27
+ if (Array.isArray(resp.items)) {
28
+ all.push(...resp.items);
29
+ }
30
+ const next = resp.nextCursor ?? undefined;
31
+ if (!next) {
32
+ return all;
33
+ }
34
+ if (seenCursors.has(next)) {
35
+ throw new Error(`Pagination cursor did not advance (cursor ${next} repeated); aborting to avoid an infinite loop.`);
36
+ }
37
+ seenCursors.add(next);
38
+ cursor = next;
39
+ }
40
+ throw new Error(`Pagination exceeded ${maxPages} pages without terminating; server cursor may not be advancing.`);
41
+ }
42
+ //# sourceMappingURL=paginate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginate.js","sourceRoot":"","sources":["../../../src/lib/paginate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAkBH;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAyB,EACzB,UAA2B,EAAE;IAE7B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;IAC1C,MAAM,GAAG,GAAQ,EAAE,CAAC;IACpB,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IACtC,IAAI,MAA0B,CAAC;IAE/B,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,IAAI,SAAS,CAAC;QAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,GAAG,CAAC;QACb,CAAC;QACD,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,6CAA6C,IAAI,iDAAiD,CACnG,CAAC;QACJ,CAAC;QACD,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtB,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IAED,MAAM,IAAI,KAAK,CACb,uBAAuB,QAAQ,iEAAiE,CACjG,CAAC;AACJ,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Project-scoped configuration (.primitive/config.json).
3
+ *
4
+ * This module handles loading, validating, and saving the project config file
5
+ * that lives inside the .primitive/ directory at the project root. The config
6
+ * defines named environments (dev, prod, staging, etc.) with their API URLs
7
+ * and app IDs.
8
+ *
9
+ * Design:
10
+ * - Config file: .primitive/config.json (or any ancestor directory)
11
+ * - The .primitive/ directory groups the committable config and the
12
+ * gitignored local state (credentials, sync data) in one place.
13
+ * - Format: JSON
14
+ * - Schema is versioned (currently 1). Future versions use semver-ish
15
+ * caret range compatibility: we accept any config where major version
16
+ * matches CURRENT_CONFIG_VERSION.
17
+ * - Invalid configs throw — we do NOT silently ignore malformed files.
18
+ */
19
+ /**
20
+ * Current schema version. Increment the major version when making
21
+ * backward-incompatible changes. Older configs will be rejected.
22
+ */
23
+ export declare const CURRENT_CONFIG_VERSION = 1;
24
+ /**
25
+ * The config file lives inside the .primitive/ directory, not at the
26
+ * project root. This keeps the project root clean and groups all
27
+ * Primitive state (config, credentials, sync data) under one directory.
28
+ */
29
+ export declare const PROJECT_CONFIG_DIR = ".primitive";
30
+ export declare const PROJECT_CONFIG_FILENAME = "config.json";
31
+ /** Display name used in user-facing messages. */
32
+ export declare const PROJECT_CONFIG_DISPLAY_NAME = ".primitive/config.json";
33
+ export interface ProjectEnvironment {
34
+ apiUrl: string;
35
+ appId?: string;
36
+ appName?: string;
37
+ /** Optional notes about this environment. */
38
+ description?: string;
39
+ }
40
+ export interface ProjectConfig {
41
+ /** Schema version (currently 1). */
42
+ version: number;
43
+ /**
44
+ * Default environment name to use when --env is not specified and
45
+ * PRIMITIVE_ENV is unset.
46
+ */
47
+ defaultEnvironment?: string;
48
+ /**
49
+ * Named environments keyed by short name (e.g. "dev", "prod", "staging").
50
+ */
51
+ environments: Record<string, ProjectEnvironment>;
52
+ }
53
+ export declare class ProjectConfigError extends Error {
54
+ readonly path?: string;
55
+ constructor(message: string, path?: string);
56
+ }
57
+ /**
58
+ * Walks upward from `startDir` looking for a `.primitive/config.json` file.
59
+ * Returns the absolute path to the config file, or null if not found.
60
+ *
61
+ * Allows running `primitive` commands from subdirectories of a project,
62
+ * much like `git` walks up to find `.git`.
63
+ */
64
+ export declare function findProjectConfigPath(startDir?: string): string | null;
65
+ /**
66
+ * Returns the project root directory (the parent of .primitive/ that contains
67
+ * .primitive/config.json), or null if no project config is found.
68
+ *
69
+ * When the PRIMITIVE_PROJECT_CONFIG env var override is active, the config
70
+ * file may not live inside a `.primitive/` directory (e.g. in tests), so
71
+ * we simply go up one level from the file.
72
+ */
73
+ export declare function findProjectRoot(startDir?: string): string | null;
74
+ /**
75
+ * Validates a raw parsed object against the ProjectConfig schema.
76
+ * Throws ProjectConfigError with a helpful message on any problem.
77
+ */
78
+ export declare function validateProjectConfig(raw: unknown, sourcePath?: string): ProjectConfig;
79
+ /**
80
+ * Loads and validates the project config from a specific file path.
81
+ * Throws ProjectConfigError on I/O errors, JSON parse errors, or schema
82
+ * validation failures — we deliberately do NOT swallow these, because a
83
+ * broken config should be noisy so the user can fix it.
84
+ */
85
+ export declare function loadProjectConfigFromPath(path: string): ProjectConfig;
86
+ /**
87
+ * Loads the project config by searching upward from the current directory.
88
+ * Returns null (not an error) if no .primitive/config.json is found anywhere.
89
+ * Still throws ProjectConfigError if a config IS found but is invalid.
90
+ */
91
+ export declare function loadProjectConfig(startDir?: string): ProjectConfig | null;
92
+ /**
93
+ * Writes a project config to disk as pretty-printed JSON. Callers are
94
+ * responsible for ensuring the parent directory exists — this function
95
+ * does not try to be clever about location.
96
+ */
97
+ export declare function saveProjectConfig(path: string, config: ProjectConfig): void;