@codyswann/lisa 4.21.6 → 4.22.2

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 (89) hide show
  1. package/all/copy-overwrite/scripts/lisa-environment-prepare.mjs +28 -12
  2. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  3. package/dist/core/lisa-owned-hash-ledger.js +2 -0
  4. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  5. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  6. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  7. package/dist/core/upstream-evidence-manifest.js +9 -7
  8. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  9. package/dist/migrations/ensure-playwright-dedicated-caller.d.ts +0 -2
  10. package/dist/migrations/ensure-playwright-dedicated-caller.d.ts.map +1 -1
  11. package/dist/migrations/ensure-playwright-dedicated-caller.js +12 -40
  12. package/dist/migrations/ensure-playwright-dedicated-caller.js.map +1 -1
  13. package/expo/create-only/.github/workflows/maestro-e2e.yml +6 -0
  14. package/expo/create-only/.github/workflows/playwright-e2e.yml +5 -5
  15. package/package.json +2 -2
  16. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  18. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/SKILL.md +26 -1
  19. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/providers.mjs +90 -2
  20. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +307 -53
  21. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-aws/SKILL.md +20 -3
  22. package/plugins/lisa/skills/lisa-secrets-access/SKILL.md +26 -1
  23. package/plugins/lisa/skills/lisa-secrets-access/scripts/providers.mjs +90 -2
  24. package/plugins/lisa/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +307 -53
  25. package/plugins/lisa/skills/lisa-setup-remote-aws/SKILL.md +20 -3
  26. package/plugins/lisa-agy/plugin.json +1 -1
  27. package/plugins/lisa-agy/skills/lisa-secrets-access/SKILL.md +26 -1
  28. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/providers.mjs +90 -2
  29. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +307 -53
  30. package/plugins/lisa-agy/skills/lisa-setup-remote-aws/SKILL.md +20 -3
  31. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  33. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  34. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-copilot/skills/lisa-secrets-access/SKILL.md +26 -1
  38. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/providers.mjs +90 -2
  39. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +307 -53
  40. package/plugins/lisa-copilot/skills/lisa-setup-remote-aws/SKILL.md +20 -3
  41. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-cursor/skills/lisa-secrets-access/SKILL.md +26 -1
  43. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/providers.mjs +90 -2
  44. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +307 -53
  45. package/plugins/lisa-cursor/skills/lisa-setup-remote-aws/SKILL.md +20 -3
  46. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  48. package/plugins/lisa-expo-agy/plugin.json +1 -1
  49. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  53. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  54. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  58. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  59. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  63. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  64. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  68. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  69. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  73. package/plugins/lisa-rails-agy/plugin.json +1 -1
  74. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  78. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  79. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  83. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  84. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  86. package/plugins/src/base/skills/lisa-secrets-access/SKILL.md +26 -1
  87. package/plugins/src/base/skills/lisa-secrets-access/scripts/providers.mjs +90 -2
  88. package/plugins/src/base/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +307 -53
  89. package/plugins/src/base/skills/lisa-setup-remote-aws/SKILL.md +20 -3
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.21.6",
3
+ "version": "4.22.2",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -281,7 +281,7 @@ Values never enter that process, so its output cannot leak one even if logged.
281
281
 
282
282
  | Provider | Read | Write (rotation only) |
283
283
  | --- | --- | --- |
284
- | `bitwarden` | `bws secret list --output json` → index by `key` | `bws secret edit` |
284
+ | `bitwarden` | `bws secret list --output json` → index by `key` | `bws secret edit`; temporary `create`/`delete` for AWS publication coordination |
285
285
  | `doppler` | `doppler secrets download --no-file --format json` | not implemented |
286
286
  | `env` | environment only; the provider is the environment | n/a |
287
287
  | `1password` | `op read "op://<vault>/<name>/credential"` | not implemented |
@@ -297,6 +297,31 @@ secret you would otherwise store inside it.
297
297
 
298
298
  Unimplemented providers fail with a message naming where to add them, rather than failing obscurely. Do not claim support that does not exist.
299
299
 
300
+ ### AWS bootstrap publication coordination
301
+
302
+ `publish-aws-bootstrap.mjs publish` and `preflight` serialize mutations of
303
+ `LISA_AWS_BOOTSTRAP_JSON` in the provider. Each contender creates a unique,
304
+ non-secret coordination record in the target record's Bitwarden project. The
305
+ oldest active contender wins by provider-issued `creationDate`, with the
306
+ provider id as a deterministic tie-breaker. Later contenders remove themselves
307
+ and stop before the bundle is written.
308
+
309
+ The winner re-reads the target after acquisition, then holds the coordination
310
+ record across the no-op write check, candidate verification, replacement,
311
+ read-back, post-write verification, and any rollback. Cleanup deletes the
312
+ coordination record and proves it no longer appears in the provider. Records
313
+ older than 30 minutes are expired and removed on the next attempt, covering a
314
+ killed host without permitting a permanent lock.
315
+
316
+ Coordination keys start with `LISA_COORDINATION_` and are excluded before
317
+ normal secret selection, so they can never resolve or materialize as
318
+ credentials. Their value is a fixed public sentinel; no credential is copied
319
+ into them. This publication lock is separate from the advisory rotation lease
320
+ record used by `rotate-secret.mjs`.
321
+
322
+ Ordinary session refresh only reads and materializes existing provider values.
323
+ It neither creates coordination records nor writes the AWS bundle.
324
+
300
325
  Cache **in-process only**. Never write a resolved value to disk except through the materialization contract above.
301
326
 
302
327
  ## Doctor checks worth wiring
@@ -33,6 +33,17 @@ export const ENV_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
33
33
  */
34
34
  export const LEASE_KEY = "LISA_ROTATION_LEASES";
35
35
 
36
+ /**
37
+ * Prefix reserved for provider-side coordination records.
38
+ *
39
+ * These records contain no credential material. They exist only long enough
40
+ * to serialize a provider mutation and must never cross the exposure boundary
41
+ * into a shell, file, hook, or CI environment.
42
+ */
43
+ export const COORDINATION_KEY_PREFIX = "LISA_COORDINATION_";
44
+
45
+ const COORDINATION_VALUE = "coordination-only";
46
+
36
47
  /**
37
48
  * The environment variable each provider's CLI reads its own bootstrap from.
38
49
  *
@@ -177,7 +188,7 @@ function fromKeychain(key) {
177
188
  * caller may see, so the set it returns *is* the permitted set. Restating that
178
189
  * as a list in config would duplicate a boundary the provider already enforces.
179
190
  * @param {object} cfg Resolved configuration.
180
- * @returns {Array<{key: string, value: string, note: string, projectId: string|null}>} Rows.
191
+ * @returns {Array<{key: string, value: string, note: string, projectId: string|null, id?: string|null, creationDate?: string|null, revisionDate?: string|null}>} Rows.
181
192
  */
182
193
  export function fetchRaw(cfg) {
183
194
  const env = providerEnv(cfg);
@@ -201,6 +212,8 @@ export function fetchRaw(cfg) {
201
212
  note: s.note ?? "",
202
213
  projectId: s.projectId ?? null,
203
214
  id: s.id ?? null,
215
+ creationDate: s.creationDate ?? null,
216
+ revisionDate: s.revisionDate ?? null,
204
217
  }));
205
218
  }
206
219
 
@@ -248,7 +261,7 @@ function run(bin, args, env) {
248
261
  * which is neither stable nor visible at the call site.
249
262
  * @param {Array<object>} rows Raw provider rows.
250
263
  * @param {{projectIds: string[], excludeKeys: string[]}} narrow Narrowing controls.
251
- * @returns {Map<string, {value: string, note: string, id: string|null}>} Selected secrets by name.
264
+ * @returns {Map<string, {value: string, note: string, id: string|null, projectId: string|null, creationDate: string|null, revisionDate: string|null}>} Selected secrets by name.
252
265
  */
253
266
  export function normalizeRows(
254
267
  rows,
@@ -260,6 +273,12 @@ export function normalizeRows(
260
273
 
261
274
  for (const row of rows) {
262
275
  if (projects.size && !projects.has(row.projectId)) continue;
276
+ if (
277
+ typeof row.key === "string" &&
278
+ row.key.startsWith(COORDINATION_KEY_PREFIX)
279
+ ) {
280
+ continue;
281
+ }
263
282
  if (typeof row.key !== "string" || !ENV_KEY.test(row.key)) continue;
264
283
  if (excluded.has(row.key)) continue;
265
284
  if (out.has(row.key)) {
@@ -276,6 +295,9 @@ export function normalizeRows(
276
295
  value: row.value,
277
296
  note: row.note ?? "",
278
297
  id: row.id ?? null,
298
+ projectId: row.projectId ?? null,
299
+ creationDate: row.creationDate ?? null,
300
+ revisionDate: row.revisionDate ?? null,
279
301
  });
280
302
  }
281
303
  return out;
@@ -370,3 +392,69 @@ export function writeSecret(cfg, id, value) {
370
392
  `Rotation requires a proven write path; add one in providers.mjs.`
371
393
  );
372
394
  }
395
+
396
+ /**
397
+ * Create one provider-issued publication contender in the target project.
398
+ *
399
+ * The deliberately constrained interface accepts no value: coordination
400
+ * records always contain the same public sentinel, which prevents this helper
401
+ * from becoming an alternate credential-write path.
402
+ * @param {object} cfg Resolved configuration.
403
+ * @param {string} key Unique coordination key.
404
+ * @param {string} projectId Project containing the target provider record.
405
+ * @param {string} note Non-sensitive lifecycle metadata.
406
+ * @returns {object} The provider-issued coordination row.
407
+ */
408
+ export function createCoordinationRecord(cfg, key, projectId, note) {
409
+ const env = providerEnv(cfg);
410
+
411
+ if (cfg.provider === "bitwarden") {
412
+ const raw = run(
413
+ "bws",
414
+ [
415
+ "secret",
416
+ "create",
417
+ key,
418
+ COORDINATION_VALUE,
419
+ projectId,
420
+ "--note",
421
+ note,
422
+ "--output",
423
+ "json",
424
+ ],
425
+ env
426
+ );
427
+ const created = JSON.parse(raw);
428
+ return {
429
+ key: created.key,
430
+ value: created.value,
431
+ note: created.note ?? "",
432
+ projectId: created.projectId ?? null,
433
+ id: created.id ?? null,
434
+ creationDate: created.creationDate ?? null,
435
+ revisionDate: created.revisionDate ?? null,
436
+ };
437
+ }
438
+ throw new Error(
439
+ `provider "${cfg.provider}" has no coordination-record creation implemented.\n` +
440
+ `AWS bootstrap publication requires a provider-backed single-writer lock.`
441
+ );
442
+ }
443
+
444
+ /**
445
+ * Remove one provider-side coordination record by its provider identifier.
446
+ * @param {object} cfg Resolved configuration.
447
+ * @param {string} id Provider-side identifier for the coordination record.
448
+ */
449
+ export function removeCoordinationRecord(cfg, id) {
450
+ const env = providerEnv(cfg);
451
+
452
+ if (cfg.provider === "bitwarden") {
453
+ run("bws", ["secret", "delete", id, "--output", "none"], env);
454
+ return;
455
+ }
456
+ throw new Error(
457
+ `provider "${cfg.provider}" has no coordination-record deletion implemented.\n` +
458
+ `AWS bootstrap publication requires verified lock cleanup.`
459
+ );
460
+ }