primitive-admin 1.1.0-alpha.75 → 1.1.0-alpha.76

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 (40) hide show
  1. package/dist/bin/primitive.js +98 -10
  2. package/dist/bin/primitive.js.map +1 -1
  3. package/dist/src/commands/functions.js +53 -18
  4. package/dist/src/commands/functions.js.map +1 -1
  5. package/dist/src/commands/prompts.js +54 -39
  6. package/dist/src/commands/prompts.js.map +1 -1
  7. package/dist/src/commands/sync.d.ts +39 -0
  8. package/dist/src/commands/sync.js +163 -90
  9. package/dist/src/commands/sync.js.map +1 -1
  10. package/dist/src/commands/workflows.js +61 -30
  11. package/dist/src/commands/workflows.js.map +1 -1
  12. package/dist/src/lib/api-client.d.ts +16 -1
  13. package/dist/src/lib/api-client.js +16 -3
  14. package/dist/src/lib/api-client.js.map +1 -1
  15. package/dist/src/lib/block-selector.d.ts +58 -0
  16. package/dist/src/lib/block-selector.js +92 -0
  17. package/dist/src/lib/block-selector.js.map +1 -0
  18. package/dist/src/lib/config-object-descriptor.js +1 -3
  19. package/dist/src/lib/config-object-descriptor.js.map +1 -1
  20. package/dist/src/lib/function-collect.d.ts +29 -7
  21. package/dist/src/lib/function-collect.js +135 -11
  22. package/dist/src/lib/function-collect.js.map +1 -1
  23. package/dist/src/lib/function-grants-preflight.d.ts +34 -88
  24. package/dist/src/lib/function-grants-preflight.js +32 -145
  25. package/dist/src/lib/function-grants-preflight.js.map +1 -1
  26. package/dist/src/lib/function-sync.d.ts +3 -14
  27. package/dist/src/lib/function-sync.js +10 -49
  28. package/dist/src/lib/function-sync.js.map +1 -1
  29. package/dist/src/lib/function-triggers.d.ts +6 -0
  30. package/dist/src/lib/function-triggers.js +63 -4
  31. package/dist/src/lib/function-triggers.js.map +1 -1
  32. package/dist/src/lib/generated-config-surfaces.d.ts +188 -236
  33. package/dist/src/lib/generated-config-surfaces.js +355 -453
  34. package/dist/src/lib/generated-config-surfaces.js.map +1 -1
  35. package/dist/src/lib/generated-sdk-types.d.ts +1 -1
  36. package/dist/src/lib/generated-sdk-types.js +1 -1
  37. package/dist/src/lib/generated-sdk-types.js.map +1 -1
  38. package/dist/src/lib/toml-database-config.js +19 -2
  39. package/dist/src/lib/toml-database-config.js.map +1 -1
  40. package/package.json +1 -1
@@ -6,6 +6,7 @@ import { generateWorkflowTypes, } from "../lib/workflow-codegen/generator.js";
6
6
  import { generateWorkflowSwiftTypes } from "../lib/swift-codegen/generator.js";
7
7
  import { ApiClient } from "../lib/api-client.js";
8
8
  import { resolveAppId } from "../lib/config.js";
9
+ import { resolveWorkflowSelector } from "../lib/block-selector.js";
9
10
  import { formatAccessRuleForDisplay } from "../lib/access-rule-display.js";
10
11
  import { resolveCodegenSourceDir } from "../lib/codegen-shared/resolveCodegenSourceDir.js";
11
12
  import { resolveSyncDirOverride } from "../lib/sync-dir-selector.js";
@@ -254,6 +255,17 @@ export function formatConfigSlotLabel(slot, configName, configId, prefixLength =
254
255
  }
255
256
  return slot;
256
257
  }
258
+ /**
259
+ * Resolve a workflow reference — its server id, or the author-chosen key its
260
+ * TOML file is named for — for the `tests` verbs (#3249).
261
+ *
262
+ * The key is what an operator has: `workflows/<key>.toml` is the object and
263
+ * `workflows/<key>.tests/` its cases. The resolution lives in
264
+ * `block-selector.ts`, shared with `prompts`.
265
+ */
266
+ async function resolveWorkflowId(client, appId, ref) {
267
+ return (await resolveWorkflowSelector(client, appId, ref)).blockId;
268
+ }
257
269
  export function registerWorkflowsCommands(program) {
258
270
  const workflows = program
259
271
  .command("workflows")
@@ -1810,22 +1822,30 @@ Test cases are authored in TOML at workflows/<key>.tests/<name>.toml and applied
1810
1822
  with \`primitive config push\` (issue #2769); \`config fields workflow\` lists the
1811
1823
  fields. Deleting a case is removing its file and running \`config push --prune\`.
1812
1824
 
1825
+ Every verb here takes the workflow's KEY or its ID (#3249). An identifier
1826
+ that names no workflow in the app fails; "No test cases found." only ever
1827
+ means the workflow exists and has no cases.
1828
+
1813
1829
  Examples:
1814
- $ primitive workflows tests list <workflow-id>
1815
- $ primitive workflows tests run <workflow-id> <test-case-id>
1816
- $ primitive workflows tests run-all <workflow-id>
1817
- $ primitive workflows tests run-all <workflow-id> --test-cases 01ABC,01DEF,01GHI
1830
+ $ primitive workflows tests list <workflow>
1831
+ $ primitive workflows tests run <workflow> <test-case-id>
1832
+ $ primitive workflows tests run-all <workflow>
1833
+ $ primitive workflows tests run-all <workflow> --test-cases 01ABC,01DEF,01GHI
1818
1834
  `);
1819
1835
  tests
1820
1836
  .command("list")
1821
1837
  .description("List test cases for a workflow")
1822
- .argument("<workflow-id>", "Workflow ID")
1838
+ .argument("<workflow>", "Workflow key or ID")
1823
1839
  .option("--app <app-id>", "App ID (uses current app if not specified)")
1824
1840
  .option("--json", "Output as JSON")
1825
- .action(async (workflowId, options) => {
1841
+ .action(async (workflow, options) => {
1826
1842
  const resolvedAppId = resolveAppId(undefined, options);
1827
1843
  const client = new ApiClient();
1828
1844
  try {
1845
+ // #3249 — resolve BEFORE listing: the test-case endpoint answers an
1846
+ // unknown block with an empty page, so an unresolved identifier would
1847
+ // print "No test cases found." and exit 0.
1848
+ const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
1829
1849
  const { items } = await client.listTestCases(resolvedAppId, "workflow", workflowId);
1830
1850
  if (options.json) {
1831
1851
  json(items);
@@ -1850,14 +1870,15 @@ Examples:
1850
1870
  tests
1851
1871
  .command("get")
1852
1872
  .description("Get test case details")
1853
- .argument("<workflow-id>", "Workflow ID")
1873
+ .argument("<workflow>", "Workflow key or ID")
1854
1874
  .argument("<test-case-id>", "Test Case ID")
1855
1875
  .option("--app <app-id>", "App ID (uses current app if not specified)")
1856
1876
  .option("--json", "Output as JSON")
1857
- .action(async (workflowId, testCaseId, options) => {
1877
+ .action(async (workflow, testCaseId, options) => {
1858
1878
  const resolvedAppId = resolveAppId(undefined, options);
1859
1879
  const client = new ApiClient();
1860
1880
  try {
1881
+ const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
1861
1882
  const result = await client.getTestCase(resolvedAppId, "workflow", workflowId, testCaseId);
1862
1883
  if (options.json) {
1863
1884
  json(result);
@@ -1917,14 +1938,15 @@ Examples:
1917
1938
  tests
1918
1939
  .command("run")
1919
1940
  .description("Run a single test case")
1920
- .argument("<workflow-id>", "Workflow ID")
1941
+ .argument("<workflow>", "Workflow key or ID")
1921
1942
  .argument("<test-case-id>", "Test Case ID")
1922
1943
  .option("--app <app-id>", "App ID (uses current app if not specified)")
1923
1944
  .option("--json", "Output as JSON")
1924
- .action(async (workflowId, testCaseId, options) => {
1945
+ .action(async (workflow, testCaseId, options) => {
1925
1946
  const resolvedAppId = resolveAppId(undefined, options);
1926
1947
  const client = new ApiClient();
1927
1948
  try {
1949
+ const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
1928
1950
  // Get test case to retrieve its variables
1929
1951
  const testCase = await client.getTestCase(resolvedAppId, "workflow", workflowId, testCaseId);
1930
1952
  // #3158 — the case's stored input IS the run's input, and the server
@@ -1983,14 +2005,17 @@ Examples:
1983
2005
  tests
1984
2006
  .command("run-all")
1985
2007
  .description("Run all test cases for a workflow, or a specific subset")
1986
- .argument("<workflow-id>", "Workflow ID")
2008
+ .argument("<workflow>", "Workflow key or ID")
1987
2009
  .option("--app <app-id>", "App ID (uses current app if not specified)")
1988
2010
  .option("--test-cases <ids>", "Comma-separated list of test case IDs to run (runs only these)")
1989
2011
  .option("--json", "Output as JSON")
1990
- .action(async (workflowId, options) => {
2012
+ .action(async (workflow, options) => {
1991
2013
  const resolvedAppId = resolveAppId(undefined, options);
1992
2014
  const client = new ApiClient();
1993
2015
  try {
2016
+ // #3249 — resolve first, so `Total Tests: 0` can only ever mean the
2017
+ // workflow exists and has no cases, never that the identifier was wrong.
2018
+ const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
1994
2019
  // Parse test case IDs if provided
1995
2020
  let testCaseIds;
1996
2021
  if (options.testCases) {
@@ -2047,15 +2072,16 @@ Examples:
2047
2072
  tests
2048
2073
  .command("runs")
2049
2074
  .description("List recent test runs for a workflow")
2050
- .argument("<workflow-id>", "Workflow ID")
2075
+ .argument("<workflow>", "Workflow key or ID")
2051
2076
  .option("--app <app-id>", "App ID (uses current app if not specified)")
2052
2077
  .option("--limit <n>", "Maximum number of runs to show", "20")
2053
2078
  .option("--group <group>", "Filter by comparison group")
2054
2079
  .option("--json", "Output as JSON")
2055
- .action(async (workflowId, options) => {
2080
+ .action(async (workflow, options) => {
2056
2081
  const resolvedAppId = resolveAppId(undefined, options);
2057
2082
  const client = new ApiClient();
2058
2083
  try {
2084
+ const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
2059
2085
  const { items } = await client.listTestRuns(resolvedAppId, "workflow", workflowId, {
2060
2086
  limit: parseInt(options.limit),
2061
2087
  comparisonGroup: options.group,
@@ -2097,23 +2123,24 @@ Examples:
2097
2123
  .description("Run tests in parallel using workflow-based execution")
2098
2124
  .addHelpText("after", `
2099
2125
  Examples:
2100
- $ primitive workflows tests batch start <workflow-id>
2101
- $ primitive workflows tests batch start <workflow-id> --test-cases 01ABC,01DEF
2102
- $ primitive workflows tests batch status <workflow-id> <batch-id>
2103
- $ primitive workflows tests batch cancel <workflow-id> <batch-id>
2126
+ $ primitive workflows tests batch start <workflow>
2127
+ $ primitive workflows tests batch start <workflow> --test-cases 01ABC,01DEF
2128
+ $ primitive workflows tests batch status <workflow> <batch-id>
2129
+ $ primitive workflows tests batch cancel <workflow> <batch-id>
2104
2130
  `);
2105
2131
  // Start batch tests
2106
2132
  batch
2107
2133
  .command("start")
2108
2134
  .description("Start parallel batch test execution")
2109
- .argument("<workflow-id>", "Workflow ID")
2135
+ .argument("<workflow>", "Workflow key or ID")
2110
2136
  .option("--app <app-id>", "App ID (uses current app if not specified)")
2111
2137
  .option("--test-cases <ids>", "Comma-separated list of test case IDs to run")
2112
2138
  .option("--json", "Output as JSON")
2113
- .action(async (workflowId, options) => {
2139
+ .action(async (workflow, options) => {
2114
2140
  const resolvedAppId = resolveAppId(undefined, options);
2115
2141
  const client = new ApiClient();
2116
2142
  try {
2143
+ const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
2117
2144
  let testCaseIds;
2118
2145
  if (options.testCases) {
2119
2146
  testCaseIds = options.testCases.split(",").map((id) => id.trim()).filter(Boolean);
@@ -2149,15 +2176,16 @@ Examples:
2149
2176
  batch
2150
2177
  .command("status")
2151
2178
  .description("Get status of a batch test execution")
2152
- .argument("<workflow-id>", "Workflow ID")
2179
+ .argument("<workflow>", "Workflow key or ID")
2153
2180
  .argument("<batch-id>", "Batch ID")
2154
2181
  .option("--app <app-id>", "App ID (uses current app if not specified)")
2155
2182
  .option("--wait", "Wait for completion (polls every 2 seconds)")
2156
2183
  .option("--json", "Output as JSON")
2157
- .action(async (workflowId, batchId, options) => {
2184
+ .action(async (workflow, batchId, options) => {
2158
2185
  const resolvedAppId = resolveAppId(undefined, options);
2159
2186
  const client = new ApiClient();
2160
2187
  try {
2188
+ const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
2161
2189
  const fetchStatus = async () => {
2162
2190
  return client.getBatchTestStatus(resolvedAppId, "workflow", workflowId, batchId);
2163
2191
  };
@@ -2214,12 +2242,12 @@ Examples:
2214
2242
  batch
2215
2243
  .command("cancel")
2216
2244
  .description("Cancel a running batch test execution")
2217
- .argument("<workflow-id>", "Workflow ID")
2245
+ .argument("<workflow>", "Workflow key or ID")
2218
2246
  .argument("<batch-id>", "Batch ID")
2219
2247
  .option("--app <app-id>", "App ID (uses current app if not specified)")
2220
2248
  .option("-y, --yes", "Skip confirmation prompt")
2221
2249
  .option("--json", "Output as JSON")
2222
- .action(async (workflowId, batchId, options) => {
2250
+ .action(async (workflow, batchId, options) => {
2223
2251
  const resolvedAppId = resolveAppId(undefined, options);
2224
2252
  if (!options.yes) {
2225
2253
  let confirm;
@@ -2237,6 +2265,7 @@ Examples:
2237
2265
  }
2238
2266
  const client = new ApiClient();
2239
2267
  try {
2268
+ const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
2240
2269
  // First get current status to get instance IDs
2241
2270
  const status = await client.getBatchTestStatus(resolvedAppId, "workflow", workflowId, batchId);
2242
2271
  // Get instance IDs that are still running
@@ -2276,21 +2305,22 @@ with \`primitive config push\` (#2769); removing one and running
2276
2305
  \`config push --prune\` deletes it server-side. These verbs read server state.
2277
2306
 
2278
2307
  Examples:
2279
- $ primitive workflows tests attachments list <workflow-id> <test-case-id>
2280
- $ primitive workflows tests attachments download <workflow-id> <test-case-id> document.pdf
2308
+ $ primitive workflows tests attachments list <workflow> <test-case-id>
2309
+ $ primitive workflows tests attachments download <workflow> <test-case-id> document.pdf
2281
2310
  `);
2282
2311
  // List attachments
2283
2312
  attachments
2284
2313
  .command("list")
2285
2314
  .description("List attachments for a test case")
2286
- .argument("<workflow-id>", "Workflow ID")
2315
+ .argument("<workflow>", "Workflow key or ID")
2287
2316
  .argument("<test-case-id>", "Test Case ID")
2288
2317
  .option("--app <app-id>", "App ID (uses current app if not specified)")
2289
2318
  .option("--json", "Output as JSON")
2290
- .action(async (workflowId, testCaseId, options) => {
2319
+ .action(async (workflow, testCaseId, options) => {
2291
2320
  const resolvedAppId = resolveAppId(undefined, options);
2292
2321
  const client = new ApiClient();
2293
2322
  try {
2323
+ const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
2294
2324
  const result = await client.listTestCaseAttachments(resolvedAppId, "workflow", workflowId, testCaseId);
2295
2325
  if (options.json) {
2296
2326
  json(result.attachments);
@@ -2319,15 +2349,16 @@ Examples:
2319
2349
  attachments
2320
2350
  .command("download")
2321
2351
  .description("Download a file attachment from a test case")
2322
- .argument("<workflow-id>", "Workflow ID")
2352
+ .argument("<workflow>", "Workflow key or ID")
2323
2353
  .argument("<test-case-id>", "Test Case ID")
2324
2354
  .argument("<filename>", "Name of the file to download")
2325
2355
  .argument("[output-path]", "Output path (defaults to current directory)")
2326
2356
  .option("--app <app-id>", "App ID (uses current app if not specified)")
2327
- .action(async (workflowId, testCaseId, filename, outputPath, options) => {
2357
+ .action(async (workflow, testCaseId, filename, outputPath, options) => {
2328
2358
  const resolvedAppId = resolveAppId(undefined, options);
2329
2359
  const client = new ApiClient();
2330
2360
  try {
2361
+ const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
2331
2362
  const result = await client.downloadTestCaseAttachment(resolvedAppId, "workflow", workflowId, testCaseId, filename);
2332
2363
  const finalPath = outputPath || filename;
2333
2364
  writeFileSync(finalPath, result.data);