primitive-admin 1.2.0-alpha.7 → 1.2.0-alpha.9

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 (93) hide show
  1. package/README.md +8 -2
  2. package/assets/skill/skills/primitive-platform/SKILL.md +22 -8
  3. package/dist/src/commands/apps-children.d.ts +1 -1
  4. package/dist/src/commands/apps-children.js +55 -145
  5. package/dist/src/commands/apps-children.js.map +1 -1
  6. package/dist/src/commands/auth.js +107 -33
  7. package/dist/src/commands/auth.js.map +1 -1
  8. package/dist/src/commands/database-types.js +13 -313
  9. package/dist/src/commands/database-types.js.map +1 -1
  10. package/dist/src/commands/databases.js +13 -1
  11. package/dist/src/commands/databases.js.map +1 -1
  12. package/dist/src/commands/documents.js +70 -11
  13. package/dist/src/commands/documents.js.map +1 -1
  14. package/dist/src/commands/llm.js +9 -6
  15. package/dist/src/commands/llm.js.map +1 -1
  16. package/dist/src/commands/settings.d.ts +12 -9
  17. package/dist/src/commands/settings.js +31 -79
  18. package/dist/src/commands/settings.js.map +1 -1
  19. package/dist/src/commands/sync-app-settings.d.ts +12 -2
  20. package/dist/src/commands/sync-app-settings.js +35 -10
  21. package/dist/src/commands/sync-app-settings.js.map +1 -1
  22. package/dist/src/commands/sync.d.ts +1 -8
  23. package/dist/src/commands/sync.js +47 -45
  24. package/dist/src/commands/sync.js.map +1 -1
  25. package/dist/src/lib/api-client.d.ts +46 -6
  26. package/dist/src/lib/api-client.js +156 -64
  27. package/dist/src/lib/api-client.js.map +1 -1
  28. package/dist/src/lib/app-settings-descriptor.d.ts +38 -0
  29. package/dist/src/lib/app-settings-descriptor.js +96 -4
  30. package/dist/src/lib/app-settings-descriptor.js.map +1 -1
  31. package/dist/src/lib/child-apps-local.d.ts +0 -46
  32. package/dist/src/lib/child-apps-local.js +2 -72
  33. package/dist/src/lib/child-apps-local.js.map +1 -1
  34. package/dist/src/lib/credentials-home.d.ts +51 -0
  35. package/dist/src/lib/credentials-home.js +169 -0
  36. package/dist/src/lib/credentials-home.js.map +1 -0
  37. package/dist/src/lib/credentials-lock.d.ts +80 -0
  38. package/dist/src/lib/credentials-lock.js +222 -0
  39. package/dist/src/lib/credentials-lock.js.map +1 -0
  40. package/dist/src/lib/credentials-store.d.ts +56 -4
  41. package/dist/src/lib/credentials-store.js +236 -78
  42. package/dist/src/lib/credentials-store.js.map +1 -1
  43. package/dist/src/lib/env-resolver-core.d.ts +1 -1
  44. package/dist/src/lib/env-resolver-core.js.map +1 -1
  45. package/dist/src/lib/function-bundle.d.ts +38 -18
  46. package/dist/src/lib/function-bundle.js +60 -35
  47. package/dist/src/lib/function-bundle.js.map +1 -1
  48. package/dist/src/lib/function-document-types.d.ts +5 -3
  49. package/dist/src/lib/function-document-types.js +10 -14
  50. package/dist/src/lib/function-document-types.js.map +1 -1
  51. package/dist/src/lib/function-source-roots.d.ts +67 -0
  52. package/dist/src/lib/function-source-roots.js +148 -0
  53. package/dist/src/lib/function-source-roots.js.map +1 -0
  54. package/dist/src/lib/function-sync.d.ts +27 -0
  55. package/dist/src/lib/function-sync.js +16 -3
  56. package/dist/src/lib/function-sync.js.map +1 -1
  57. package/dist/src/lib/function-triggers.d.ts +15 -3
  58. package/dist/src/lib/function-triggers.js +72 -10
  59. package/dist/src/lib/function-triggers.js.map +1 -1
  60. package/dist/src/lib/function-typecheck.d.ts +37 -2
  61. package/dist/src/lib/function-typecheck.js +210 -28
  62. package/dist/src/lib/function-typecheck.js.map +1 -1
  63. package/dist/src/lib/generated-config-surfaces.d.ts +48 -11
  64. package/dist/src/lib/generated-config-surfaces.js +178 -49
  65. package/dist/src/lib/generated-config-surfaces.js.map +1 -1
  66. package/dist/src/lib/generated-sdk-types.d.ts +1 -1
  67. package/dist/src/lib/generated-sdk-types.js +1 -1
  68. package/dist/src/lib/generated-sdk-types.js.map +1 -1
  69. package/dist/src/lib/generated-workflow-model-fields.d.ts +20 -0
  70. package/dist/src/lib/generated-workflow-model-fields.js +53 -0
  71. package/dist/src/lib/generated-workflow-model-fields.js.map +1 -0
  72. package/dist/src/lib/login-scope-lines.d.ts +1 -1
  73. package/dist/src/lib/login-scope-lines.js +1 -1
  74. package/dist/src/lib/login-scope-lines.js.map +1 -1
  75. package/dist/src/lib/project-config.d.ts +7 -0
  76. package/dist/src/lib/project-config.js +22 -1
  77. package/dist/src/lib/project-config.js.map +1 -1
  78. package/dist/src/lib/prompt-schema-codegen.d.ts +10 -3
  79. package/dist/src/lib/prompt-schema-codegen.js +52 -14
  80. package/dist/src/lib/prompt-schema-codegen.js.map +1 -1
  81. package/dist/src/lib/root-import-decision.d.ts +9 -4
  82. package/dist/src/lib/root-import-decision.js +24 -3
  83. package/dist/src/lib/root-import-decision.js.map +1 -1
  84. package/dist/src/lib/scope-request.d.ts +8 -5
  85. package/dist/src/lib/scope-request.js +17 -8
  86. package/dist/src/lib/scope-request.js.map +1 -1
  87. package/dist/src/lib/swift-codegen/agentGenerator.d.ts +6 -2
  88. package/dist/src/lib/swift-codegen/agentGenerator.js +56 -4
  89. package/dist/src/lib/swift-codegen/agentGenerator.js.map +1 -1
  90. package/dist/src/lib/workflow-field-descriptor.d.ts +91 -0
  91. package/dist/src/lib/workflow-field-descriptor.js +153 -0
  92. package/dist/src/lib/workflow-field-descriptor.js.map +1 -0
  93. package/package.json +2 -2
@@ -26,7 +26,7 @@ import { canonicalizeServerTextFields } from "../lib/server-text-normalization.j
26
26
  import { canonicalJsonStringify } from "../lib/canonical-json.js";
27
27
  import { reconcileWorkflowIncludes } from "../lib/workflow-include-preserve.js";
28
28
  import { newPullWriteTally, writePulledFile, } from "../lib/pull-write.js";
29
- import { serializeSection, parseTomlToAppSettings, buildAppSettingsPayload, } from "../lib/app-settings-descriptor.js";
29
+ import { serializeSection, parseTomlToAppSettings, buildAppSettingsPayload, settingsProtectionLevel, } from "../lib/app-settings-descriptor.js";
30
30
  import { collectAppSettingsPushErrors, writePulledAppSettings, diffAppSettings, appSettingsFieldDiffs, appSettingsNameExcluded, appSettingsNameExcludedForState, hashAppSettingsForDiff, } from "./sync-app-settings.js";
31
31
  import { applyWorkflowBody, legacyDraftSlotWarning } from "../lib/workflow-apply.js";
32
32
  // #2645 — named config bodies live in `workflows/<key>.configs/<name>.toml`.
@@ -59,7 +59,7 @@ import { agentFunctionChangeRefusals, agentFunctionUses, } from "../lib/generate
59
59
  import { resolvePromptStrictOutput } from "../lib/generated-config-surfaces.js";
60
60
  // #3179 — the function's two halves: the header payloads and the envelope
61
61
  // `config push` sends, and the bytes `config pull` writes back.
62
- import { applyFunctionPull, buildFunctionConfigPush, createDocumentSchemaDropWarner, documentSchemaRetentionFailure, buildFunctionCreatePayload, buildFunctionUpdatePayload, functionDiffEntity, functionTomlPreflightErrors, planDocumentSchemaPull, planFunctionPull, serializeFunction, } from "../lib/function-sync.js";
62
+ import { applyFunctionPull, buildFunctionConfigPush, buildFunctionConfigPushDetailed, createDocumentSchemaDropWarner, documentSchemaRetentionFailure, buildFunctionCreatePayload, buildFunctionUpdatePayload, functionDiffEntity, functionTomlPreflightErrors, planDocumentSchemaPull, planFunctionPull, serializeFunction, } from "../lib/function-sync.js";
63
63
  import { newerVersionLine, pullNewerVersionLine, rollbackDiffHint, } from "../lib/function-versions.js";
64
64
  import { FunctionBuildError } from "../lib/function-bundle.js";
65
65
  // #3182 — the local half of capability validation. The grammar is the vendored
@@ -77,6 +77,7 @@ import { isFunctionDeclarationFile, resolveDocumentSchema, } from "../lib/functi
77
77
  // #3331 — and the compiler is actually asked: a push holds the code it ships
78
78
  // to the declarations it just generated.
79
79
  import { createFunctionTypechecker, } from "../lib/function-typecheck.js";
80
+ import { resolveFunctionSourceRoots } from "../lib/function-source-roots.js";
80
81
  import { detectLayout, migrateLegacyToV2 } from "../lib/block-layout.js";
81
82
  import { ABSENT_FROM_EXPORT, LOCAL_ONLY_ABSENT, LOCAL_ONLY_NEW, PUSH_PRUNE_SPECS, REMOTE_ONLY_UNMANAGED, REMOTE_ONLY_WILL_DELETE, SYNC_RESOURCE_TYPES, VALIDATION_ERROR, applyPrune, attachmentWritePath, attemptFetch, classifyLocalOnly, classifyPruneDeleteFailure, classifyRemoteOnly, collectPushPruneCandidates, decidePushPruneCandidate, formatPrunePlan, hasUncommittedChanges, isSafeAttachmentFilename, isSafeSyncFilename, planPrune, preserveUnwrittenEntries, removePrunedSidecar, ruleSetFileKey, } from "../lib/sync-resource-types.js";
82
83
  import { normalizeTestCaseKey, testCaseKeyError, } from "../lib/test-case-keys.js";
@@ -88,8 +89,6 @@ export { resolveSlugCollisions, slugifyTestCaseName, testCaseFileBasenames, } fr
88
89
  import { success, error, printApiError, info, warn, keyValue, json, divider, } from "../lib/output.js";
89
90
  import { filterFilesBySelection, parseSyncSelectors, SelectorError, selectionIncludesKey, selectionIncludesType, selectionIncludesApp, selectionIncludesAnyVar, trackedSelectorKeys, unmatchedSelectors, } from "../lib/sync-selectors.js";
90
91
  import { confirmPrompt, ConfirmPromptError } from "../lib/confirm-prompt.js";
91
- import { pushFailureIsTransient, writePushFailureReport } from "../lib/push-failure-report.js";
92
- import { isTransientRequestFailure } from "../lib/transient-retry.js";
93
92
  import { signingSecretStatusWarning, signingSecretHealthWarning, previousSigningSecretWarning, } from "../lib/signing-secret-status.js";
94
93
  import chalk from "chalk";
95
94
  function ensureDir(dirPath) {
@@ -2688,6 +2687,9 @@ export async function runConfigPushPreflight(input) {
2688
2687
  fileName: parsedApp?.app?.name,
2689
2688
  }),
2690
2689
  nameOptional: localEnvironment,
2690
+ // #4564 — the protection level follows the name on a machine-local
2691
+ // environment: out of the body, so out of what is validated.
2692
+ excludeProtection: localEnvironment,
2691
2693
  });
2692
2694
  for (const e of appErrors) {
2693
2695
  preflightValidationErrors.push(` app.toml: ${e}`);
@@ -7217,7 +7219,6 @@ export async function pushTestCasesForBlock(params) {
7217
7219
  const testCaseExtra = { lookupMaps: params.lookupMaps };
7218
7220
  const listed = await listAllTestCases(client, appId, blockType, blockId);
7219
7221
  const liveOk = listed.ok;
7220
- const liveReadTransient = "error" in listed && isTransientRequestFailure(listed.error);
7221
7222
  if (!liveOk) {
7222
7223
  warn(` ${blockKey} test cases: live state unavailable — falling back to last-sync content hashes`);
7223
7224
  }
@@ -7479,7 +7480,6 @@ export async function pushTestCasesForBlock(params) {
7479
7480
  type: "test-case",
7480
7481
  key: `${blockKey}/${slug}`,
7481
7482
  message,
7482
- transient: isTransientRequestFailure(err),
7483
7483
  });
7484
7484
  }
7485
7485
  continue;
@@ -7527,7 +7527,7 @@ export async function pushTestCasesForBlock(params) {
7527
7527
  continue;
7528
7528
  }
7529
7529
  if (degraded.action === "decline") {
7530
- params.declined?.("test-case", `${blockKey}/${slug}`, { action: "live-unavailable", transient: liveReadTransient }, existingEntry?.modifiedAt);
7530
+ params.declined?.("test-case", `${blockKey}/${slug}`, { action: "live-unavailable" }, existingEntry?.modifiedAt);
7531
7531
  continue;
7532
7532
  }
7533
7533
  }
@@ -7594,7 +7594,6 @@ export async function pushTestCasesForBlock(params) {
7594
7594
  type: "test-case",
7595
7595
  key: `${blockKey}/${slug}`,
7596
7596
  message,
7597
- transient: isTransientRequestFailure(err),
7598
7597
  });
7599
7598
  continue;
7600
7599
  }
@@ -7673,7 +7672,6 @@ export async function pushTestCasesForBlock(params) {
7673
7672
  type: "test-case",
7674
7673
  key: `${blockKey}/${slug}`,
7675
7674
  message,
7676
- transient: isTransientRequestFailure(err),
7677
7675
  });
7678
7676
  continue;
7679
7677
  }
@@ -7718,7 +7716,6 @@ export async function pushTestCasesForBlock(params) {
7718
7716
  type: "attachment",
7719
7717
  key: `${blockKey}/${slug}/${filename}`,
7720
7718
  message,
7721
- transient: isTransientRequestFailure(err),
7722
7719
  });
7723
7720
  }
7724
7721
  }
@@ -8290,7 +8287,7 @@ export async function applyTestCasePrune(params) {
8290
8287
  catch (err) {
8291
8288
  const message = err?.message || String(err);
8292
8289
  warn(` Failed to delete attachment ${key}: ${message}`);
8293
- params.failures.push({ type: "attachment", key, message, transient: isTransientRequestFailure(err) });
8290
+ params.failures.push({ type: "attachment", key, message });
8294
8291
  }
8295
8292
  }
8296
8293
  for (const candidate of params.candidates) {
@@ -8325,7 +8322,7 @@ export async function applyTestCasePrune(params) {
8325
8322
  catch (err) {
8326
8323
  const message = err?.message || String(err);
8327
8324
  warn(` Failed to delete test case ${key}: ${message}`);
8328
- params.failures.push({ type: "test-case", key, message, transient: isTransientRequestFailure(err) });
8325
+ params.failures.push({ type: "test-case", key, message });
8329
8326
  }
8330
8327
  }
8331
8328
  return { deleted, deletedAttachments };
@@ -9670,6 +9667,7 @@ export function registerConfigSyncCommands(sync) {
9670
9667
  // tree's name and whose baseline never includes one.
9671
9668
  semanticHash: hashAppSettingsForDiff(settings, {
9672
9669
  excludeName: pullsLocalEnvironment,
9670
+ excludeProtection: pullsLocalEnvironment,
9673
9671
  }),
9674
9672
  }
9675
9673
  : pullSelection
@@ -10075,13 +10073,7 @@ What a push guarantees (two stages):
10075
10073
  * never an unconditional write — with the type named so the operator
10076
10074
  * knows drift detection was not in force for it this run.
10077
10075
  */
10078
- /** Whether each live read that failed this run was transient (#4491). */
10079
- const liveReadFailures = [];
10080
10076
  const warnLiveUnavailable = (label, reason) => {
10081
- // A string reason names a consequence ("rule sets unavailable") of a
10082
- // read already recorded here.
10083
- if (typeof reason !== "string")
10084
- liveReadFailures.push(isTransientRequestFailure(reason));
10085
10077
  const message = reason instanceof Error ? reason.message : String(reason ?? "unknown");
10086
10078
  warn(` ${label}: live state unavailable (${message}) — falling back to last-sync content hashes`);
10087
10079
  };
@@ -10099,11 +10091,6 @@ What a push guarantees (two stages):
10099
10091
  applyFailures.push({
10100
10092
  type,
10101
10093
  key,
10102
- // A rerun can read what this one could not only when the failed
10103
- // read was transient; a decliner that does not say which read
10104
- // failed is judged by every read that failed this run.
10105
- transient: outcome.transient ??
10106
- (liveReadFailures.length > 0 && liveReadFailures.every(Boolean)),
10107
10094
  message: "live state could not be read and the manifest holds no " +
10108
10095
  "last-sync content hash for this file, so push cannot tell " +
10109
10096
  "which side moved. Nothing was written. Run `config pull` to " +
@@ -10495,6 +10482,9 @@ What a push guarantees (two stages):
10495
10482
  const { settings: appPayload, warnings: appWarnings } = buildAppSettingsPayload(tomlData, {
10496
10483
  excludeName: payloadExcludesName,
10497
10484
  nameOptional: localEnvironment,
10485
+ // #4564 — on a machine-local environment the level is the
10486
+ // shared tree's, like the name, and never this child's.
10487
+ excludeProtection: localEnvironment,
10498
10488
  });
10499
10489
  for (const w of appWarnings) {
10500
10490
  warn(` ${w}`);
@@ -10524,6 +10514,7 @@ What a push guarantees (two stages):
10524
10514
  excludeName: localEnvironment ||
10525
10515
  options.recordExclusion !== undefined ||
10526
10516
  (options.keepExclusion && compareExcludesName),
10517
+ excludeProtection: localEnvironment,
10527
10518
  }),
10528
10519
  ...(options.recordExclusion !== undefined
10529
10520
  ? { excludedName: options.recordExclusion }
@@ -10534,8 +10525,17 @@ What a push guarantees (two stages):
10534
10525
  };
10535
10526
  let applyAppSettings = true;
10536
10527
  if (appLiveOk) {
10537
- const compareOptions = { excludeName: compareExcludesName };
10538
- const localHash = hashAppSettingsForDiff(appPayload, compareOptions);
10528
+ const compareOptions = {
10529
+ excludeName: compareExcludesName,
10530
+ excludeProtection: localEnvironment,
10531
+ };
10532
+ // The file's deprecated `protected` key reads against the live
10533
+ // level, as the server's write will (DSO-4564-001), so a change
10534
+ // made only through it is not skipped as unchanged.
10535
+ const localHash = hashAppSettingsForDiff(appPayload, {
10536
+ ...compareOptions,
10537
+ legacyProtectedAgainst: settingsProtectionLevel(liveSettings ?? {}),
10538
+ });
10539
10539
  const remoteHash = hashAppSettingsForDiff(liveSettings ?? {}, compareOptions);
10540
10540
  if (options.force) {
10541
10541
  // `--force` is the operator saying "local wins": no direction
@@ -14201,18 +14201,31 @@ What a push guarantees (two stages):
14201
14201
  // consulted per function, so one broken file refuses itself and
14202
14202
  // nothing else; `--no-typecheck` is the escape hatch, and an
14203
14203
  // unavailable compiler warns rather than failing the push.
14204
+ const files = selectFiles("function", functionsPushDir, readdirSync(functionsPushDir).filter(isFunctionDeclarationFile));
14205
+ // #4502 — the directories outside the tree that function code may
14206
+ // import from, resolved once for the push so a dropped entry is
14207
+ // named once rather than once per function. The bundler and the
14208
+ // checker are handed the same list, so they agree on what is shared.
14209
+ const functionSourceRoots = files.length > 0
14210
+ ? resolveFunctionSourceRoots(configDir)
14211
+ : { roots: [], warnings: [] };
14212
+ for (const warning of functionSourceRoots.warnings)
14213
+ warn(` ${warning}`);
14214
+ const sourceRoots = functionSourceRoots.roots.map((root) => root.absolute);
14204
14215
  let typecheckSetup = null;
14205
14216
  const functionTypechecker = () => {
14206
14217
  if (options.typecheck === false)
14207
14218
  return null;
14208
14219
  if (typecheckSetup === null) {
14209
- typecheckSetup = createFunctionTypechecker(configDir);
14220
+ typecheckSetup = createFunctionTypechecker(configDir, {
14221
+ sourceRoots,
14222
+ onWarning: (message) => warn(` ${message}`),
14223
+ });
14210
14224
  for (const warning of typecheckSetup.warnings)
14211
14225
  warn(` ${warning}`);
14212
14226
  }
14213
14227
  return typecheckSetup.checker;
14214
14228
  };
14215
- const files = selectFiles("function", functionsPushDir, readdirSync(functionsPushDir).filter(isFunctionDeclarationFile));
14216
14229
  const functionSpec = configDiffSpec("function");
14217
14230
  const liveFunctions = new Map();
14218
14231
  let functionsLiveOk = true;
@@ -14273,13 +14286,15 @@ What a push guarantees (two stages):
14273
14286
  // Build first: nothing is sent for a function whose code does not
14274
14287
  // compile or whose imports leave the tree.
14275
14288
  let push;
14289
+ let projectSources;
14276
14290
  try {
14277
- push = await buildFunctionConfigPush({
14291
+ ({ push, projectSources } = await buildFunctionConfigPushDetailed({
14278
14292
  configDir,
14279
14293
  functionKey: key,
14280
14294
  filePath,
14281
14295
  tomlData,
14282
- });
14296
+ sourceRoots,
14297
+ }));
14283
14298
  }
14284
14299
  catch (err) {
14285
14300
  if (!(err instanceof FunctionBuildError))
@@ -14309,7 +14324,7 @@ What a push guarantees (two stages):
14309
14324
  // sent for it and whether or not this is a dry run.
14310
14325
  const typechecker = functionTypechecker();
14311
14326
  if (typechecker) {
14312
- const failure = typechecker.check(key, push.sources.map((source) => source.path));
14327
+ const failure = typechecker.check(key, push.sources.map((source) => source.path), projectSources);
14313
14328
  if (failure) {
14314
14329
  applyFailures.push({
14315
14330
  type: "function",
@@ -14486,7 +14501,6 @@ What a push guarantees (two stages):
14486
14501
  type: "function",
14487
14502
  key,
14488
14503
  message: String(err?.message ?? err),
14489
- transient: isTransientRequestFailure(err),
14490
14504
  });
14491
14505
  // A refused create, or a refused push to a row the server does
14492
14506
  // not hold live (an archived tombstone). A row this push created
@@ -15319,7 +15333,6 @@ What a push guarantees (two stages):
15319
15333
  type: "email-template",
15320
15334
  key: emailType,
15321
15335
  message: err?.message || String(err),
15322
- transient: isTransientRequestFailure(err),
15323
15336
  });
15324
15337
  }
15325
15338
  }
@@ -15856,17 +15869,6 @@ What a push guarantees (two stages):
15856
15869
  else {
15857
15870
  error(failureSummary);
15858
15871
  }
15859
- writePushFailureReport(pushFailureIsTransient({
15860
- applyFailures,
15861
- conflicts: conflicts.length,
15862
- blockedDatabaseTypes: blockedDatabaseTypes.length,
15863
- schemaErrors: schemaErrors.schemaRequired.length +
15864
- schemaErrors.opRefs.length +
15865
- schemaErrors.schemaBreaks.length +
15866
- schemaErrors.uncheckableOps.length +
15867
- schemaErrors.tomlParse.length +
15868
- schemaErrors.opsExist.length,
15869
- }));
15870
15872
  process.exit(1);
15871
15873
  }
15872
15874
  else {
@@ -15907,7 +15909,6 @@ What a push guarantees (two stages):
15907
15909
  // Print message + structured server-side validation details
15908
15910
  // (issue #684; now via the shared #1173 helper).
15909
15911
  printApiError(err);
15910
- writePushFailureReport(isTransientRequestFailure(err));
15911
15912
  process.exit(1);
15912
15913
  }
15913
15914
  });
@@ -17093,6 +17094,7 @@ What a push guarantees (two stages):
17093
17094
  const { settings: localAppSettings, errors: appErrors } = buildAppSettingsPayload(appTomlData, {
17094
17095
  excludeName,
17095
17096
  nameOptional: diffsLocalEnvironment,
17097
+ excludeProtection: diffsLocalEnvironment,
17096
17098
  });
17097
17099
  if (appErrors.length > 0) {
17098
17100
  appRow(VALIDATION_ERROR, appErrors.join("; "));
@@ -17107,7 +17109,7 @@ What a push guarantees (two stages):
17107
17109
  });
17108
17110
  }
17109
17111
  else {
17110
- const fieldDiffs = appSettingsFieldDiffs(localAppSettings, settingsOutcome.value ?? {}, { excludeName });
17112
+ const fieldDiffs = appSettingsFieldDiffs(localAppSettings, settingsOutcome.value ?? {}, { excludeName, excludeProtection: diffsLocalEnvironment });
17111
17113
  if (fieldDiffs.length === 0) {
17112
17114
  appRow("exists");
17113
17115
  }