primitive-admin 1.1.0 → 1.2.0-alpha.0

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 (62) hide show
  1. package/README.md +11 -11
  2. package/assets/skill/skills/primitive-platform/SKILL.md +6 -0
  3. package/dist/src/commands/collections.js +20 -17
  4. package/dist/src/commands/collections.js.map +1 -1
  5. package/dist/src/commands/database-types.js +13 -313
  6. package/dist/src/commands/database-types.js.map +1 -1
  7. package/dist/src/commands/databases.js +0 -19
  8. package/dist/src/commands/databases.js.map +1 -1
  9. package/dist/src/commands/groups.js +16 -0
  10. package/dist/src/commands/groups.js.map +1 -1
  11. package/dist/src/commands/llm.js +9 -6
  12. package/dist/src/commands/llm.js.map +1 -1
  13. package/dist/src/commands/settings.d.ts +18 -0
  14. package/dist/src/commands/settings.js +54 -0
  15. package/dist/src/commands/settings.js.map +1 -0
  16. package/dist/src/commands/sync.d.ts +1 -4
  17. package/dist/src/commands/sync.js +42 -45
  18. package/dist/src/commands/sync.js.map +1 -1
  19. package/dist/src/commands/workflows.js +3 -3
  20. package/dist/src/commands/workflows.js.map +1 -1
  21. package/dist/src/lib/api-client.d.ts +3 -40
  22. package/dist/src/lib/api-client.js +20 -69
  23. package/dist/src/lib/api-client.js.map +1 -1
  24. package/dist/src/lib/app-match-guard.d.ts +44 -0
  25. package/dist/src/lib/app-match-guard.js +72 -0
  26. package/dist/src/lib/app-match-guard.js.map +1 -0
  27. package/dist/src/lib/collection-export.d.ts +37 -9
  28. package/dist/src/lib/collection-export.js +48 -12
  29. package/dist/src/lib/collection-export.js.map +1 -1
  30. package/dist/src/lib/function-triggers.d.ts +66 -0
  31. package/dist/src/lib/function-triggers.js +285 -0
  32. package/dist/src/lib/function-triggers.js.map +1 -0
  33. package/dist/src/lib/generated-allowlist.js +0 -1
  34. package/dist/src/lib/generated-allowlist.js.map +1 -1
  35. package/dist/src/lib/generated-config-surfaces.js +56 -32
  36. package/dist/src/lib/generated-config-surfaces.js.map +1 -1
  37. package/dist/src/lib/generated-sdk-types.d.ts +1 -1
  38. package/dist/src/lib/generated-sdk-types.js +1 -1
  39. package/dist/src/lib/generated-sdk-types.js.map +1 -1
  40. package/dist/src/lib/generated-workflow-model-fields.d.ts +20 -0
  41. package/dist/src/lib/generated-workflow-model-fields.js +53 -0
  42. package/dist/src/lib/generated-workflow-model-fields.js.map +1 -0
  43. package/dist/src/lib/google-client-secret-status.d.ts +35 -0
  44. package/dist/src/lib/google-client-secret-status.js +56 -0
  45. package/dist/src/lib/google-client-secret-status.js.map +1 -0
  46. package/dist/src/lib/log-inspection.d.ts +1 -6
  47. package/dist/src/lib/log-inspection.js +5 -7
  48. package/dist/src/lib/log-inspection.js.map +1 -1
  49. package/dist/src/lib/migration-nag.d.ts +2 -2
  50. package/dist/src/lib/migration-nag.js +4 -3
  51. package/dist/src/lib/migration-nag.js.map +1 -1
  52. package/dist/src/lib/paginate.d.ts +8 -24
  53. package/dist/src/lib/paginate.js +8 -21
  54. package/dist/src/lib/paginate.js.map +1 -1
  55. package/dist/src/lib/sync-dir-selector.d.ts +1 -1
  56. package/dist/src/lib/sync-dir-selector.js +1 -1
  57. package/dist/src/lib/toml-database-config.js +2 -2
  58. package/dist/src/lib/toml-database-config.js.map +1 -1
  59. package/dist/src/lib/workflow-field-descriptor.d.ts +91 -0
  60. package/dist/src/lib/workflow-field-descriptor.js +153 -0
  61. package/dist/src/lib/workflow-field-descriptor.js.map +1 -0
  62. package/package.json +2 -2
@@ -0,0 +1,54 @@
1
+ /**
2
+ * `primitive settings` — the app-settings READER (issue #1033, Phase 2;
3
+ * narrowed to a reader by #2645).
4
+ *
5
+ * App settings are authored in `app.toml` and applied with `sync push`, so
6
+ * this group carries the one thing the file cannot answer: what the server is
7
+ * actually running. `settings get` renders the server-effective settings —
8
+ * `get` rather than `show`, so the read verb is the same word on every
9
+ * configuration surface.
10
+ *
11
+ * `settings pull`, `settings diff` and `settings push` are gone. They operated
12
+ * on the same `app.toml` and the same `entities.app` hash `sync` owns, so they
13
+ * were a second pathway to one piece of state; `sync pull|diff|push --only app`
14
+ * is the single one. The remaining command logic lives in
15
+ * `sync-app-settings.ts`, shared with `sync`.
16
+ */
17
+ import { ApiClient } from "../lib/api-client.js";
18
+ import { resolveAppId } from "../lib/config.js";
19
+ import { showAppSettings } from "./sync-app-settings.js";
20
+ export function registerSettingsCommands(program) {
21
+ const settings = program
22
+ .command("settings")
23
+ .description("View the app settings the server is running")
24
+ .addHelpText("after", `
25
+ Examples:
26
+ $ primitive settings get # Render current server settings
27
+ $ primitive settings get --json # Machine-readable
28
+ $ primitive sync pull --only app # Write server settings to app.toml
29
+ $ primitive config set app app.baseUrl=https://example.com
30
+ $ primitive sync diff --only app # Show local app.toml vs server
31
+ $ primitive sync push --only app # Apply app.toml edits to the server
32
+
33
+ app.toml is the ONLY way to manage app configuration (issue #2645): a full
34
+ \`sync push\` applies it, and \`sync push --only app\` applies it alone.
35
+ \`primitive config fields app\` lists its keys, types and defaults. The Google OAuth
36
+ client secret is an ordinary [auth] key holding a reference into the app's
37
+ secret store, never the secret itself: store the value with
38
+ 'primitive secrets set GOOGLE_CLIENT_SECRET --value <secret>', then set
39
+ googleClientSecret = "{{secrets.GOOGLE_CLIENT_SECRET}}" in app.toml. A literal
40
+ secret there is rejected by the server.
41
+ `);
42
+ // settings get
43
+ settings
44
+ .command("get")
45
+ .description("Show the current server-effective app settings")
46
+ .argument("[app-id]", "App ID (uses current app if not specified)")
47
+ .option("--app <app-id>", "App ID")
48
+ .option("--json", "Output as JSON")
49
+ .action(async (appId, options) => {
50
+ const resolvedAppId = resolveAppId(appId, options);
51
+ await showAppSettings(new ApiClient(), resolvedAppId, options);
52
+ });
53
+ }
54
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/commands/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,UAAU,wBAAwB,CAAC,OAAgB;IACvD,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,6CAA6C,CAAC;SAC1D,WAAW,CACV,OAAO,EACP;;;;;;;;;;;;;;;;;CAiBL,CACI,CAAC;IAEJ,eAAe;IACf,QAAQ;SACL,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,gDAAgD,CAAC;SAC7D,QAAQ,CAAC,UAAU,EAAE,4CAA4C,CAAC;SAClE,MAAM,CAAC,gBAAgB,EAAE,QAAQ,CAAC;SAClC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC/B,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,eAAe,CAAC,IAAI,SAAS,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -706,9 +706,6 @@ export declare function buildBlobBucketUpdatePayload(bucket: any): any;
706
706
  * first-wins rule: making the file's meaning depend on entry order is the kind
707
707
  * of implicit behavior this issue exists to remove, and silently picking one
708
708
  * would let the repo claim something the server does not do.
709
- *
710
- * `isActive` is accepted as a legacy spelling — the create leg read it before
711
- * pull ever wrote a marker, so a hand-authored file carrying it keeps working.
712
709
  */
713
710
  export declare function promptActiveConfigName(configs: any[]): string | undefined;
714
711
  /**
@@ -1554,7 +1551,7 @@ export declare function hashLocalConfigForDiff(spec: ConfigDiffSpec, parsedToml:
1554
1551
  * Hash a SERVER entity the same way, by serializing it into the file `sync
1555
1552
  * pull` would write and hashing that — so the two sides are normalized
1556
1553
  * identically by construction, and a legacy encoding on disk (a JSON-string
1557
- * operation, an id-based rule-set reference) is not a false `Modified`.
1554
+ * operation) is not a false `Modified`.
1558
1555
  *
1559
1556
  * `extra` carries the sibling rows a type's file also holds: a database type's
1560
1557
  * operations and subscriptions, which the list response does not include.
@@ -1698,12 +1698,9 @@ const PROMPT_CONFIG_DEFAULT_STATUS = fieldServerDefault(PROMPT_CONFIG_TABLE, "st
1698
1698
  * first-wins rule: making the file's meaning depend on entry order is the kind
1699
1699
  * of implicit behavior this issue exists to remove, and silently picking one
1700
1700
  * would let the repo claim something the server does not do.
1701
- *
1702
- * `isActive` is accepted as a legacy spelling — the create leg read it before
1703
- * pull ever wrote a marker, so a hand-authored file carrying it keeps working.
1704
1701
  */
1705
1702
  export function promptActiveConfigName(configs) {
1706
- const marked = (configs || []).filter((c) => c?.active === true || c?.isActive === true);
1703
+ const marked = (configs || []).filter((c) => c?.active === true);
1707
1704
  if (marked.length > 1) {
1708
1705
  throw new Error(`Only one [[configs]] entry may set active = true; found ${marked.length} ` +
1709
1706
  `(${marked.map((c) => c.name).join(", ")}).`);
@@ -4012,7 +4009,7 @@ export function parseDatabaseTypeToml(tomlData) {
4012
4009
  },
4013
4010
  }));
4014
4011
  canonicalizeDatabaseTypeConfig(typeConfig);
4015
- // Both rule-set spellings; the name form resolves to an id later.
4012
+ // The `ruleSetName` reference; it resolves to an id later.
4016
4013
  applyRuleSetReference(typeSection, typeConfig);
4017
4014
  if (tomlData.triggers) {
4018
4015
  typeConfig.triggers = tomlData.triggers;
@@ -4081,13 +4078,16 @@ export function parseRuleSetToml(tomlData) {
4081
4078
  /**
4082
4079
  * Read a config's rule-set reference off its TOML table (#2644).
4083
4080
  *
4084
- * Both spellings are accepted — the portable `ruleSetName` and the legacy
4085
- * `ruleSetId` — and the name form is left as `_ruleSetName` for
4081
+ * One spelling, the portable `ruleSetName`, left as `_ruleSetName` for
4086
4082
  * `resolveRuleSetReference` to turn into an id once the app's rule sets are
4087
- * known. Neither present means no reference, which push sends as an explicit
4088
- * `null` so removing the line clears it (#1567).
4083
+ * known. Absent means no reference, which push sends as an explicit `null` so
4084
+ * removing the line clears it (#1567). The id spelling `ruleSetId` is retired
4085
+ * (#3997): the preflight refuses it through `retired-keys.ts`, and it is never
4086
+ * read here, so no id authored in TOML reaches the wire.
4089
4087
  */
4090
4088
  function applyRuleSetReference(section, entity) {
4089
+ // The payload builder put the `ruleSetName` value on the `ruleSetId` field;
4090
+ // the resolver sets the real id.
4091
4091
  delete entity.ruleSetId;
4092
4092
  if (section.ruleSetName && section.ruleSetName !== "") {
4093
4093
  // Trimmed to match the name the server stores for the rule set itself
@@ -4097,9 +4097,6 @@ function applyRuleSetReference(section, entity) {
4097
4097
  ? section.ruleSetName.trim()
4098
4098
  : section.ruleSetName;
4099
4099
  }
4100
- else if (section.ruleSetId && section.ruleSetId !== "") {
4101
- entity.ruleSetId = section.ruleSetId;
4102
- }
4103
4100
  }
4104
4101
  /** Drop keys the TOML did not carry, so `"x" in entity` stays meaningful. */
4105
4102
  function dropUndefined(entity) {
@@ -4162,22 +4159,22 @@ export function parseCollectionTypeConfigToml(tomlData) {
4162
4159
  // the SAME push parser before hashing.
4163
4160
  //
4164
4161
  // Parsing through the push parser — rather than hashing the raw parsed TOML —
4165
- // is what makes the comparison encoding-independent, and is why the four known
4162
+ // is what makes the comparison encoding-independent, and is why the known
4166
4163
  // false-diff traps do not fire: a legacy JSON-string operation and the native
4167
4164
  // `[operations.definition]` table the server emits normalize to one shape
4168
- // (`normalizeOperationFromToml`); a `ruleSetName` reference and its legacy
4169
- // `ruleSetId` resolve to the same id (`normalizeRuleSetRefForDiff`); an omitted
4170
- // `autoAddCreator` picks up the same default the server serializes
4171
- // (`parseGroupTypeConfigToml`); and a metadata-category's identity is read from
4172
- // the parsed `[metadataCategoryConfig]` content, not the filename. Hashing raw
4173
- // parsed TOML would show a false `Modified` for each of those equivalent forms.
4165
+ // (`normalizeOperationFromToml`); a `ruleSetName` reference resolves to the id
4166
+ // the server holds (`normalizeRuleSetRefForDiff`); an omitted `autoAddCreator`
4167
+ // picks up the same default the server serializes (`parseGroupTypeConfigToml`);
4168
+ // and a metadata-category's identity is read from the parsed
4169
+ // `[metadataCategoryConfig]` content, not the filename. Hashing raw parsed TOML
4170
+ // would show a false `Modified` for each of those equivalent forms.
4174
4171
  /**
4175
4172
  * Resolve a parsed entity's rule-set reference to a stable id for hashing.
4176
4173
  * `parseGroupTypeConfigToml` / `parseCollectionTypeConfigToml` /
4177
- * `parseDatabaseTypeToml` leave either `_ruleSetName` (key-based) or a legacy
4178
- * `ruleSetId` on the entity; collapsing both to `ruleSetId` here means the two
4179
- * encodings of the same reference hash equal. `throwOnMissing: false` so an
4180
- * unresolvable name degrades gracefully rather than aborting the diff.
4174
+ * `parseDatabaseTypeToml` leave the `ruleSetName` reference as `_ruleSetName`;
4175
+ * resolving it to `ruleSetId` here means the local file and the server entity
4176
+ * hash the same reference. `throwOnMissing: false` so an unresolvable name
4177
+ * degrades gracefully rather than aborting the diff.
4181
4178
  *
4182
4179
  * When the name does NOT resolve — a typo, or a rule set added locally in the
4183
4180
  * same tree but not yet on the server — `resolveRuleSetReference` deletes
@@ -5066,7 +5063,7 @@ export function hashLocalConfigForDiff(spec, parsedToml, maps, extra) {
5066
5063
  * Hash a SERVER entity the same way, by serializing it into the file `sync
5067
5064
  * pull` would write and hashing that — so the two sides are normalized
5068
5065
  * identically by construction, and a legacy encoding on disk (a JSON-string
5069
- * operation, an id-based rule-set reference) is not a false `Modified`.
5066
+ * operation) is not a false `Modified`.
5070
5067
  *
5071
5068
  * `extra` carries the sibling rows a type's file also holds: a database type's
5072
5069
  * operations and subscriptions, which the list response does not include.
@@ -17263,28 +17260,28 @@ What a push guarantees (two stages):
17263
17260
  let unchangedCount = 0;
17264
17261
  // ---- database-type-configs/ pass ----
17265
17262
  if (dbFiles.length > 0) {
17266
- // Hydrate ruleSetIdToName from local sync state so files that
17267
- // reference a rule set via the legacy `ruleSetId = "01..."` form
17268
- // round-trip with the correct `ruleSetName`. Without this, any user
17269
- // who runs migrate-toml against a file with a rule-set assignment
17270
- // would silently lose that reference (review feedback r3246633010).
17271
- //
17272
- // Files that use the modern key-based `ruleSetName = "..."` form
17273
- // don't need the map at all — `parseDatabaseTypeToml` stores the
17274
- // value in `typeConfig._ruleSetName` and the serializer now prefers
17275
- // that. The map is only load-bearing for the legacy ID-based form.
17276
- const ruleSetIdToName = new Map();
17277
- const migrateSyncState = loadSyncState(configDir);
17278
- if (migrateSyncState?.entities?.ruleSets) {
17279
- for (const [fileKey, entry] of Object.entries(migrateSyncState.entities.ruleSets)) {
17280
- if (entry && typeof entry === "object" && "id" in entry && entry.id) {
17281
- // fileKey is the sanitized rule-set name (see config pull at
17282
- // sync.ts:1385). It's the same shape the server returned and
17283
- // matches what a TOML file's ruleSetName field would carry.
17284
- ruleSetIdToName.set(entry.id, fileKey);
17285
- }
17286
- }
17263
+ // #3997 — refuse a tree carrying a retired key (the id-based
17264
+ // `ruleSetId`) with the message `config push` gives, before anything is
17265
+ // rewritten. This is a separate pass, not a check inside the loop below:
17266
+ // that loop writes each file and saves sync state before it parses the
17267
+ // next, so an in-loop abort would leave earlier files rewritten. Every
17268
+ // offending file is reported, so the author fixes the tree once.
17269
+ const retiredKeyErrors = [];
17270
+ for (const file of dbFiles) {
17271
+ const message = configUnknownKeyError(`database-type-configs/${file}`, parseTomlFile(join(dbTypesDir, file)), DATABASE_TYPE_TABLE);
17272
+ if (message)
17273
+ retiredKeyErrors.push(message);
17287
17274
  }
17275
+ if (retiredKeyErrors.length > 0) {
17276
+ for (const message of retiredKeyErrors)
17277
+ error(` ${message}`);
17278
+ error(`Aborting migrate-toml: ${retiredKeyErrors.length} database-type ` +
17279
+ "file(s) carry a retired or unrecognized key; nothing was rewritten.");
17280
+ process.exit(1);
17281
+ }
17282
+ // The parser yields the rule-set reference only as `_ruleSetName`,
17283
+ // which the serializer prefers, so there is no id to map to a name.
17284
+ const ruleSetIdToName = new Map();
17288
17285
  for (const file of dbFiles) {
17289
17286
  const filePath = join(dbTypesDir, file);
17290
17287
  const rawBefore = readFileSync(filePath, "utf-8");