@codyswann/lisa 2.321.4 → 2.321.5

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 (58) hide show
  1. package/dist/core/upstream-evidence-manifest.js +1 -1
  2. package/package.json +1 -1
  3. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  4. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  5. package/plugins/lisa/.codex-plugin/skills/lisa-setup-automations/scripts/generate-workflow.mjs +32 -13
  6. package/plugins/lisa/skills/lisa-setup-automations/scripts/generate-workflow.mjs +32 -13
  7. package/plugins/lisa-agy/plugin.json +1 -1
  8. package/plugins/lisa-agy/skills/lisa-setup-automations/scripts/generate-workflow.mjs +32 -13
  9. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  10. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  11. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  12. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-copilot/skills/lisa-setup-automations/scripts/generate-workflow.mjs +32 -13
  16. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cursor/skills/lisa-setup-automations/scripts/generate-workflow.mjs +32 -13
  18. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  20. package/plugins/lisa-expo-agy/plugin.json +1 -1
  21. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  25. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  26. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  30. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  31. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  35. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  36. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  40. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  41. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  45. package/plugins/lisa-rails-agy/plugin.json +1 -1
  46. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  50. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  51. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  55. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  56. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/src/base/skills/lisa-setup-automations/scripts/generate-workflow.mjs +32 -13
@@ -550,7 +550,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
550
550
  "plugins/src/base/skills/lisa-sentry-access/SKILL.md": "ecaf49b42bbf399781a3ebd0b1595e5a8ac44422537832e0442b2f184da0c83c",
551
551
  "plugins/src/base/skills/lisa-setup-atlassian/SKILL.md": "3820aecb57d184fde1cfa988e7e1402d8f2a766a0b3ffbb576de5a6a72b3d5c5",
552
552
  "plugins/src/base/skills/lisa-setup-automations/SKILL.md": "3ad004148a54571a50df90f23abec71e8510ef3ea3562ac812f8e2e11beb157a",
553
- "plugins/src/base/skills/lisa-setup-automations/scripts/generate-workflow.mjs": "dd1a0999156bbbaf864fc0f1d85206db5ea2ada172ccac2ee11091303e06ff4d",
553
+ "plugins/src/base/skills/lisa-setup-automations/scripts/generate-workflow.mjs": "bfb3867cc62dd37d84367859e4d796edb7a0c046595b3e0194ddb0b6d3b63d61",
554
554
  "plugins/src/base/skills/lisa-setup-confluence/SKILL.md": "e92d762dbdaeae671c3e52dfe8e10d40a10b606b5e050589181a3898649faedc",
555
555
  "plugins/src/base/skills/lisa-setup-github-repo/SKILL.md": "b9b223a5ffad2f88e3fde5831b60fea9bdc2c981750c49d03bb046d43772a0d3",
556
556
  "plugins/src/base/skills/lisa-setup-github/SKILL.md": "75435e81130abd21c678d302b7a220da95a19868d122ca93168278628b200666",
package/package.json CHANGED
@@ -115,7 +115,7 @@
115
115
  "brace-expansion": ">=5.0.9"
116
116
  },
117
117
  "name": "@codyswann/lisa",
118
- "version": "2.321.4",
118
+ "version": "2.321.5",
119
119
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
120
120
  "main": "dist/index.js",
121
121
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -41,9 +41,20 @@ export function readAutomation(name, cwd = process.cwd()) {
41
41
  `Declare the loop before generating its workflow.`
42
42
  );
43
43
  }
44
+ const surface = cfg.remoteEnv?.surfaces?.[loop.executionEnv];
45
+ const github = cfg.github ?? {};
44
46
  return {
45
47
  ...loop,
46
- repository: cfg.remoteEnv?.surfaces?.[loop.executionEnv]?.repository,
48
+ // Only used for the fork guard, so it is a question about *this* repository
49
+ // rather than about the surface. Read from the surface where one records it
50
+ // — Codex Cloud binds an environment to a repository — and otherwise from
51
+ // the project's own GitHub config. A Claude cloud environment binds no
52
+ // repository at all, and demanding one there asked for a field that cannot
53
+ // exist, which refused to generate a workflow for a correctly configured
54
+ // loop.
55
+ repository:
56
+ surface?.repository ??
57
+ (github.org && github.repo ? `${github.org}/${github.repo}` : undefined),
47
58
  // Where this project keeps its bootstrap. A workstation serving several
48
59
  // tenants gives each its own name, so the generated workflow must template
49
60
  // it rather than assume the default.
@@ -81,12 +92,28 @@ export function renderWorkflow(name, loop) {
81
92
  const bootstrap = loop.bootstrapKey ?? "BWS_ACCESS_TOKEN";
82
93
  if (!loop.repository) {
83
94
  throw new Error(
84
- `automations["${name}"] targets executionEnv "${loop.executionEnv}", ` +
85
- `but no remoteEnv.surfaces["${loop.executionEnv}"].repository is set.\n` +
86
- `Run /lisa:setup:remote-env ${loop.executionEnv} first.`
95
+ `cannot determine which repository this loop belongs to.\n` +
96
+ `The generated workflow guards on it so a fork never dispatches. Set ` +
97
+ `github.org and github.repo in .lisa.config.json.`
87
98
  );
88
99
  }
89
100
 
101
+ // Always emitted, even for a surface whose dispatcher token is not consumed
102
+ // by use. Making it conditional on secrets.rotating would mean a project that
103
+ // later declares one, without regenerating its workflow, silently loses the
104
+ // persist step and strands the replacement. One inert step is the cheaper
105
+ // failure.
106
+ const rotation = `
107
+ # The dispatcher authenticates with a credential that rotates on use, so
108
+ # the replacement must be persisted even when the dispatch itself failed.
109
+ - name: Persist any credential rotation
110
+ if: \${{ always() }}
111
+ env:
112
+ ${bootstrap}: \${{ secrets.${bootstrap} }}
113
+ run: |
114
+ set -euo pipefail
115
+ node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases`;
116
+
90
117
  const trigger = loop.enabled
91
118
  ? ` schedule:\n - cron: '${loop.schedule}'\n workflow_dispatch:`
92
119
  : ` # schedule: disabled until the production path is proven once for one\n` +
@@ -149,15 +176,7 @@ jobs:
149
176
  'executionEnv=${loop.executionEnv} ${loop.payload ?? ""}' \\
150
177
  --skill ${loop.skill ?? `lisa-${name}`}
151
178
 
152
- # The dispatcher authenticates with a credential that rotates on use, so
153
- # the replacement must be persisted even when the dispatch itself failed.
154
- - name: Persist any credential rotation
155
- if: \${{ always() }}
156
- env:
157
- ${bootstrap}: \${{ secrets.${bootstrap} }}
158
- run: |
159
- set -euo pipefail
160
- node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases
179
+ ${rotation}
161
180
  `;
162
181
  }
163
182
 
@@ -41,9 +41,20 @@ export function readAutomation(name, cwd = process.cwd()) {
41
41
  `Declare the loop before generating its workflow.`
42
42
  );
43
43
  }
44
+ const surface = cfg.remoteEnv?.surfaces?.[loop.executionEnv];
45
+ const github = cfg.github ?? {};
44
46
  return {
45
47
  ...loop,
46
- repository: cfg.remoteEnv?.surfaces?.[loop.executionEnv]?.repository,
48
+ // Only used for the fork guard, so it is a question about *this* repository
49
+ // rather than about the surface. Read from the surface where one records it
50
+ // — Codex Cloud binds an environment to a repository — and otherwise from
51
+ // the project's own GitHub config. A Claude cloud environment binds no
52
+ // repository at all, and demanding one there asked for a field that cannot
53
+ // exist, which refused to generate a workflow for a correctly configured
54
+ // loop.
55
+ repository:
56
+ surface?.repository ??
57
+ (github.org && github.repo ? `${github.org}/${github.repo}` : undefined),
47
58
  // Where this project keeps its bootstrap. A workstation serving several
48
59
  // tenants gives each its own name, so the generated workflow must template
49
60
  // it rather than assume the default.
@@ -81,12 +92,28 @@ export function renderWorkflow(name, loop) {
81
92
  const bootstrap = loop.bootstrapKey ?? "BWS_ACCESS_TOKEN";
82
93
  if (!loop.repository) {
83
94
  throw new Error(
84
- `automations["${name}"] targets executionEnv "${loop.executionEnv}", ` +
85
- `but no remoteEnv.surfaces["${loop.executionEnv}"].repository is set.\n` +
86
- `Run /lisa:setup:remote-env ${loop.executionEnv} first.`
95
+ `cannot determine which repository this loop belongs to.\n` +
96
+ `The generated workflow guards on it so a fork never dispatches. Set ` +
97
+ `github.org and github.repo in .lisa.config.json.`
87
98
  );
88
99
  }
89
100
 
101
+ // Always emitted, even for a surface whose dispatcher token is not consumed
102
+ // by use. Making it conditional on secrets.rotating would mean a project that
103
+ // later declares one, without regenerating its workflow, silently loses the
104
+ // persist step and strands the replacement. One inert step is the cheaper
105
+ // failure.
106
+ const rotation = `
107
+ # The dispatcher authenticates with a credential that rotates on use, so
108
+ # the replacement must be persisted even when the dispatch itself failed.
109
+ - name: Persist any credential rotation
110
+ if: \${{ always() }}
111
+ env:
112
+ ${bootstrap}: \${{ secrets.${bootstrap} }}
113
+ run: |
114
+ set -euo pipefail
115
+ node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases`;
116
+
90
117
  const trigger = loop.enabled
91
118
  ? ` schedule:\n - cron: '${loop.schedule}'\n workflow_dispatch:`
92
119
  : ` # schedule: disabled until the production path is proven once for one\n` +
@@ -149,15 +176,7 @@ jobs:
149
176
  'executionEnv=${loop.executionEnv} ${loop.payload ?? ""}' \\
150
177
  --skill ${loop.skill ?? `lisa-${name}`}
151
178
 
152
- # The dispatcher authenticates with a credential that rotates on use, so
153
- # the replacement must be persisted even when the dispatch itself failed.
154
- - name: Persist any credential rotation
155
- if: \${{ always() }}
156
- env:
157
- ${bootstrap}: \${{ secrets.${bootstrap} }}
158
- run: |
159
- set -euo pipefail
160
- node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases
179
+ ${rotation}
161
180
  `;
162
181
  }
163
182
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -41,9 +41,20 @@ export function readAutomation(name, cwd = process.cwd()) {
41
41
  `Declare the loop before generating its workflow.`
42
42
  );
43
43
  }
44
+ const surface = cfg.remoteEnv?.surfaces?.[loop.executionEnv];
45
+ const github = cfg.github ?? {};
44
46
  return {
45
47
  ...loop,
46
- repository: cfg.remoteEnv?.surfaces?.[loop.executionEnv]?.repository,
48
+ // Only used for the fork guard, so it is a question about *this* repository
49
+ // rather than about the surface. Read from the surface where one records it
50
+ // — Codex Cloud binds an environment to a repository — and otherwise from
51
+ // the project's own GitHub config. A Claude cloud environment binds no
52
+ // repository at all, and demanding one there asked for a field that cannot
53
+ // exist, which refused to generate a workflow for a correctly configured
54
+ // loop.
55
+ repository:
56
+ surface?.repository ??
57
+ (github.org && github.repo ? `${github.org}/${github.repo}` : undefined),
47
58
  // Where this project keeps its bootstrap. A workstation serving several
48
59
  // tenants gives each its own name, so the generated workflow must template
49
60
  // it rather than assume the default.
@@ -81,12 +92,28 @@ export function renderWorkflow(name, loop) {
81
92
  const bootstrap = loop.bootstrapKey ?? "BWS_ACCESS_TOKEN";
82
93
  if (!loop.repository) {
83
94
  throw new Error(
84
- `automations["${name}"] targets executionEnv "${loop.executionEnv}", ` +
85
- `but no remoteEnv.surfaces["${loop.executionEnv}"].repository is set.\n` +
86
- `Run /lisa:setup:remote-env ${loop.executionEnv} first.`
95
+ `cannot determine which repository this loop belongs to.\n` +
96
+ `The generated workflow guards on it so a fork never dispatches. Set ` +
97
+ `github.org and github.repo in .lisa.config.json.`
87
98
  );
88
99
  }
89
100
 
101
+ // Always emitted, even for a surface whose dispatcher token is not consumed
102
+ // by use. Making it conditional on secrets.rotating would mean a project that
103
+ // later declares one, without regenerating its workflow, silently loses the
104
+ // persist step and strands the replacement. One inert step is the cheaper
105
+ // failure.
106
+ const rotation = `
107
+ # The dispatcher authenticates with a credential that rotates on use, so
108
+ # the replacement must be persisted even when the dispatch itself failed.
109
+ - name: Persist any credential rotation
110
+ if: \${{ always() }}
111
+ env:
112
+ ${bootstrap}: \${{ secrets.${bootstrap} }}
113
+ run: |
114
+ set -euo pipefail
115
+ node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases`;
116
+
90
117
  const trigger = loop.enabled
91
118
  ? ` schedule:\n - cron: '${loop.schedule}'\n workflow_dispatch:`
92
119
  : ` # schedule: disabled until the production path is proven once for one\n` +
@@ -149,15 +176,7 @@ jobs:
149
176
  'executionEnv=${loop.executionEnv} ${loop.payload ?? ""}' \\
150
177
  --skill ${loop.skill ?? `lisa-${name}`}
151
178
 
152
- # The dispatcher authenticates with a credential that rotates on use, so
153
- # the replacement must be persisted even when the dispatch itself failed.
154
- - name: Persist any credential rotation
155
- if: \${{ always() }}
156
- env:
157
- ${bootstrap}: \${{ secrets.${bootstrap} }}
158
- run: |
159
- set -euo pipefail
160
- node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases
179
+ ${rotation}
161
180
  `;
162
181
  }
163
182
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -41,9 +41,20 @@ export function readAutomation(name, cwd = process.cwd()) {
41
41
  `Declare the loop before generating its workflow.`
42
42
  );
43
43
  }
44
+ const surface = cfg.remoteEnv?.surfaces?.[loop.executionEnv];
45
+ const github = cfg.github ?? {};
44
46
  return {
45
47
  ...loop,
46
- repository: cfg.remoteEnv?.surfaces?.[loop.executionEnv]?.repository,
48
+ // Only used for the fork guard, so it is a question about *this* repository
49
+ // rather than about the surface. Read from the surface where one records it
50
+ // — Codex Cloud binds an environment to a repository — and otherwise from
51
+ // the project's own GitHub config. A Claude cloud environment binds no
52
+ // repository at all, and demanding one there asked for a field that cannot
53
+ // exist, which refused to generate a workflow for a correctly configured
54
+ // loop.
55
+ repository:
56
+ surface?.repository ??
57
+ (github.org && github.repo ? `${github.org}/${github.repo}` : undefined),
47
58
  // Where this project keeps its bootstrap. A workstation serving several
48
59
  // tenants gives each its own name, so the generated workflow must template
49
60
  // it rather than assume the default.
@@ -81,12 +92,28 @@ export function renderWorkflow(name, loop) {
81
92
  const bootstrap = loop.bootstrapKey ?? "BWS_ACCESS_TOKEN";
82
93
  if (!loop.repository) {
83
94
  throw new Error(
84
- `automations["${name}"] targets executionEnv "${loop.executionEnv}", ` +
85
- `but no remoteEnv.surfaces["${loop.executionEnv}"].repository is set.\n` +
86
- `Run /lisa:setup:remote-env ${loop.executionEnv} first.`
95
+ `cannot determine which repository this loop belongs to.\n` +
96
+ `The generated workflow guards on it so a fork never dispatches. Set ` +
97
+ `github.org and github.repo in .lisa.config.json.`
87
98
  );
88
99
  }
89
100
 
101
+ // Always emitted, even for a surface whose dispatcher token is not consumed
102
+ // by use. Making it conditional on secrets.rotating would mean a project that
103
+ // later declares one, without regenerating its workflow, silently loses the
104
+ // persist step and strands the replacement. One inert step is the cheaper
105
+ // failure.
106
+ const rotation = `
107
+ # The dispatcher authenticates with a credential that rotates on use, so
108
+ # the replacement must be persisted even when the dispatch itself failed.
109
+ - name: Persist any credential rotation
110
+ if: \${{ always() }}
111
+ env:
112
+ ${bootstrap}: \${{ secrets.${bootstrap} }}
113
+ run: |
114
+ set -euo pipefail
115
+ node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases`;
116
+
90
117
  const trigger = loop.enabled
91
118
  ? ` schedule:\n - cron: '${loop.schedule}'\n workflow_dispatch:`
92
119
  : ` # schedule: disabled until the production path is proven once for one\n` +
@@ -149,15 +176,7 @@ jobs:
149
176
  'executionEnv=${loop.executionEnv} ${loop.payload ?? ""}' \\
150
177
  --skill ${loop.skill ?? `lisa-${name}`}
151
178
 
152
- # The dispatcher authenticates with a credential that rotates on use, so
153
- # the replacement must be persisted even when the dispatch itself failed.
154
- - name: Persist any credential rotation
155
- if: \${{ always() }}
156
- env:
157
- ${bootstrap}: \${{ secrets.${bootstrap} }}
158
- run: |
159
- set -euo pipefail
160
- node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases
179
+ ${rotation}
161
180
  `;
162
181
  }
163
182
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -41,9 +41,20 @@ export function readAutomation(name, cwd = process.cwd()) {
41
41
  `Declare the loop before generating its workflow.`
42
42
  );
43
43
  }
44
+ const surface = cfg.remoteEnv?.surfaces?.[loop.executionEnv];
45
+ const github = cfg.github ?? {};
44
46
  return {
45
47
  ...loop,
46
- repository: cfg.remoteEnv?.surfaces?.[loop.executionEnv]?.repository,
48
+ // Only used for the fork guard, so it is a question about *this* repository
49
+ // rather than about the surface. Read from the surface where one records it
50
+ // — Codex Cloud binds an environment to a repository — and otherwise from
51
+ // the project's own GitHub config. A Claude cloud environment binds no
52
+ // repository at all, and demanding one there asked for a field that cannot
53
+ // exist, which refused to generate a workflow for a correctly configured
54
+ // loop.
55
+ repository:
56
+ surface?.repository ??
57
+ (github.org && github.repo ? `${github.org}/${github.repo}` : undefined),
47
58
  // Where this project keeps its bootstrap. A workstation serving several
48
59
  // tenants gives each its own name, so the generated workflow must template
49
60
  // it rather than assume the default.
@@ -81,12 +92,28 @@ export function renderWorkflow(name, loop) {
81
92
  const bootstrap = loop.bootstrapKey ?? "BWS_ACCESS_TOKEN";
82
93
  if (!loop.repository) {
83
94
  throw new Error(
84
- `automations["${name}"] targets executionEnv "${loop.executionEnv}", ` +
85
- `but no remoteEnv.surfaces["${loop.executionEnv}"].repository is set.\n` +
86
- `Run /lisa:setup:remote-env ${loop.executionEnv} first.`
95
+ `cannot determine which repository this loop belongs to.\n` +
96
+ `The generated workflow guards on it so a fork never dispatches. Set ` +
97
+ `github.org and github.repo in .lisa.config.json.`
87
98
  );
88
99
  }
89
100
 
101
+ // Always emitted, even for a surface whose dispatcher token is not consumed
102
+ // by use. Making it conditional on secrets.rotating would mean a project that
103
+ // later declares one, without regenerating its workflow, silently loses the
104
+ // persist step and strands the replacement. One inert step is the cheaper
105
+ // failure.
106
+ const rotation = `
107
+ # The dispatcher authenticates with a credential that rotates on use, so
108
+ # the replacement must be persisted even when the dispatch itself failed.
109
+ - name: Persist any credential rotation
110
+ if: \${{ always() }}
111
+ env:
112
+ ${bootstrap}: \${{ secrets.${bootstrap} }}
113
+ run: |
114
+ set -euo pipefail
115
+ node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases`;
116
+
90
117
  const trigger = loop.enabled
91
118
  ? ` schedule:\n - cron: '${loop.schedule}'\n workflow_dispatch:`
92
119
  : ` # schedule: disabled until the production path is proven once for one\n` +
@@ -149,15 +176,7 @@ jobs:
149
176
  'executionEnv=${loop.executionEnv} ${loop.payload ?? ""}' \\
150
177
  --skill ${loop.skill ?? `lisa-${name}`}
151
178
 
152
- # The dispatcher authenticates with a credential that rotates on use, so
153
- # the replacement must be persisted even when the dispatch itself failed.
154
- - name: Persist any credential rotation
155
- if: \${{ always() }}
156
- env:
157
- ${bootstrap}: \${{ secrets.${bootstrap} }}
158
- run: |
159
- set -euo pipefail
160
- node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases
179
+ ${rotation}
161
180
  `;
162
181
  }
163
182
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
4
4
  "description": "Harper/Fabric-specific Lisa 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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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": "2.321.4",
3
+ "version": "2.321.5",
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"
@@ -41,9 +41,20 @@ export function readAutomation(name, cwd = process.cwd()) {
41
41
  `Declare the loop before generating its workflow.`
42
42
  );
43
43
  }
44
+ const surface = cfg.remoteEnv?.surfaces?.[loop.executionEnv];
45
+ const github = cfg.github ?? {};
44
46
  return {
45
47
  ...loop,
46
- repository: cfg.remoteEnv?.surfaces?.[loop.executionEnv]?.repository,
48
+ // Only used for the fork guard, so it is a question about *this* repository
49
+ // rather than about the surface. Read from the surface where one records it
50
+ // — Codex Cloud binds an environment to a repository — and otherwise from
51
+ // the project's own GitHub config. A Claude cloud environment binds no
52
+ // repository at all, and demanding one there asked for a field that cannot
53
+ // exist, which refused to generate a workflow for a correctly configured
54
+ // loop.
55
+ repository:
56
+ surface?.repository ??
57
+ (github.org && github.repo ? `${github.org}/${github.repo}` : undefined),
47
58
  // Where this project keeps its bootstrap. A workstation serving several
48
59
  // tenants gives each its own name, so the generated workflow must template
49
60
  // it rather than assume the default.
@@ -81,12 +92,28 @@ export function renderWorkflow(name, loop) {
81
92
  const bootstrap = loop.bootstrapKey ?? "BWS_ACCESS_TOKEN";
82
93
  if (!loop.repository) {
83
94
  throw new Error(
84
- `automations["${name}"] targets executionEnv "${loop.executionEnv}", ` +
85
- `but no remoteEnv.surfaces["${loop.executionEnv}"].repository is set.\n` +
86
- `Run /lisa:setup:remote-env ${loop.executionEnv} first.`
95
+ `cannot determine which repository this loop belongs to.\n` +
96
+ `The generated workflow guards on it so a fork never dispatches. Set ` +
97
+ `github.org and github.repo in .lisa.config.json.`
87
98
  );
88
99
  }
89
100
 
101
+ // Always emitted, even for a surface whose dispatcher token is not consumed
102
+ // by use. Making it conditional on secrets.rotating would mean a project that
103
+ // later declares one, without regenerating its workflow, silently loses the
104
+ // persist step and strands the replacement. One inert step is the cheaper
105
+ // failure.
106
+ const rotation = `
107
+ # The dispatcher authenticates with a credential that rotates on use, so
108
+ # the replacement must be persisted even when the dispatch itself failed.
109
+ - name: Persist any credential rotation
110
+ if: \${{ always() }}
111
+ env:
112
+ ${bootstrap}: \${{ secrets.${bootstrap} }}
113
+ run: |
114
+ set -euo pipefail
115
+ node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases`;
116
+
90
117
  const trigger = loop.enabled
91
118
  ? ` schedule:\n - cron: '${loop.schedule}'\n workflow_dispatch:`
92
119
  : ` # schedule: disabled until the production path is proven once for one\n` +
@@ -149,15 +176,7 @@ jobs:
149
176
  'executionEnv=${loop.executionEnv} ${loop.payload ?? ""}' \\
150
177
  --skill ${loop.skill ?? `lisa-${name}`}
151
178
 
152
- # The dispatcher authenticates with a credential that rotates on use, so
153
- # the replacement must be persisted even when the dispatch itself failed.
154
- - name: Persist any credential rotation
155
- if: \${{ always() }}
156
- env:
157
- ${bootstrap}: \${{ secrets.${bootstrap} }}
158
- run: |
159
- set -euo pipefail
160
- node .claude/skills/lisa-secrets-access/scripts/rotate-secret.mjs leases
179
+ ${rotation}
161
180
  `;
162
181
  }
163
182