@macedon-technologies/batman 1.17.3 → 1.18.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.
- package/.jsii +124 -17
- package/.swamp.yaml +6 -0
- package/API.md +107 -0
- package/CLAUDE.md +44 -0
- package/architecture-rules/README.md +42 -0
- package/architecture-rules/check.ts +162 -0
- package/architecture-rules/rules.json +3 -0
- package/architecture-rules/tsconfig.json +14 -0
- package/attestation/manifest.ts +40 -0
- package/attestation/tsconfig.json +13 -0
- package/attestation/verify.ts +142 -0
- package/lib/BatmanProject.js +8 -2
- package/lib/BootcampProject.js +8 -2
- package/lib/CodeOwnersFile.js +1 -1
- package/lib/ProductionDeployWorkflow.js +1 -1
- package/lib/SoftwareFactoryArchitectureRules.d.ts +10 -0
- package/lib/SoftwareFactoryArchitectureRules.js +245 -0
- package/lib/SoftwareFactoryAttestation.d.ts +18 -0
- package/lib/SoftwareFactoryAttestation.js +221 -0
- package/lib/SoftwareFactoryFiles.d.ts +45 -0
- package/lib/SoftwareFactoryFiles.js +102 -0
- package/lib/SoftwareFactoryModels.d.ts +25 -0
- package/lib/SoftwareFactoryModels.js +306 -0
- package/lib/SoftwareFactoryOpenSpecGates.d.ts +8 -0
- package/lib/SoftwareFactoryOpenSpecGates.js +75 -0
- package/lib/SoftwareFactoryWorkflows.d.ts +28 -0
- package/lib/SoftwareFactoryWorkflows.js +326 -0
- package/lib/StagingDeployWorkflow.js +1 -1
- package/lib/WorkflowAutoDiscover.js +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -1
- package/lib/utils.js +29 -1
- package/models/@goodcraft/github/platform-common-pr.yaml +10 -0
- package/models/@swamp/software-factory/platform-common-factory.yaml +240 -0
- package/models/@webframp/github/platform-common-issues.yaml +8 -0
- package/models/command/shell/platform-common-shell-architecture.yaml +8 -0
- package/models/command/shell/platform-common-shell-manifest.yaml +8 -0
- package/models/command/shell/platform-common-shell.yaml +8 -0
- package/openspec-gates/check-tasks-complete.ts +44 -0
- package/openspec-gates/tsconfig.json +13 -0
- package/package.json +6 -1
- package/workflows/workflow-openspec-plan-verify.yaml +51 -0
- package/workflows/workflow-openspec-tasks-verify.yaml +51 -0
- package/workflows/workflow-pre-pr-verify.yaml +118 -0
package/.jsii
CHANGED
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
},
|
|
159
159
|
"locationInModule": {
|
|
160
160
|
"filename": "src/BatmanProject.ts",
|
|
161
|
-
"line":
|
|
161
|
+
"line": 64
|
|
162
162
|
},
|
|
163
163
|
"parameters": [
|
|
164
164
|
{
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
"kind": "class",
|
|
173
173
|
"locationInModule": {
|
|
174
174
|
"filename": "src/BatmanProject.ts",
|
|
175
|
-
"line":
|
|
175
|
+
"line": 63
|
|
176
176
|
},
|
|
177
177
|
"name": "BatmanProject",
|
|
178
178
|
"symbolId": "src/BatmanProject:BatmanProject"
|
|
@@ -190,7 +190,7 @@
|
|
|
190
190
|
"kind": "interface",
|
|
191
191
|
"locationInModule": {
|
|
192
192
|
"filename": "src/BatmanProject.ts",
|
|
193
|
-
"line":
|
|
193
|
+
"line": 12
|
|
194
194
|
},
|
|
195
195
|
"name": "BatmanProjectOptions",
|
|
196
196
|
"properties": [
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
"immutable": true,
|
|
204
204
|
"locationInModule": {
|
|
205
205
|
"filename": "src/BatmanProject.ts",
|
|
206
|
-
"line":
|
|
206
|
+
"line": 17
|
|
207
207
|
},
|
|
208
208
|
"name": "dev",
|
|
209
209
|
"type": {
|
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
"immutable": true,
|
|
220
220
|
"locationInModule": {
|
|
221
221
|
"filename": "src/BatmanProject.ts",
|
|
222
|
-
"line":
|
|
222
|
+
"line": 27
|
|
223
223
|
},
|
|
224
224
|
"name": "prod",
|
|
225
225
|
"type": {
|
|
@@ -235,7 +235,7 @@
|
|
|
235
235
|
"immutable": true,
|
|
236
236
|
"locationInModule": {
|
|
237
237
|
"filename": "src/BatmanProject.ts",
|
|
238
|
-
"line":
|
|
238
|
+
"line": 22
|
|
239
239
|
},
|
|
240
240
|
"name": "staging",
|
|
241
241
|
"type": {
|
|
@@ -251,7 +251,7 @@
|
|
|
251
251
|
"immutable": true,
|
|
252
252
|
"locationInModule": {
|
|
253
253
|
"filename": "src/BatmanProject.ts",
|
|
254
|
-
"line":
|
|
254
|
+
"line": 52
|
|
255
255
|
},
|
|
256
256
|
"name": "actionVersions",
|
|
257
257
|
"optional": true,
|
|
@@ -268,7 +268,7 @@
|
|
|
268
268
|
"immutable": true,
|
|
269
269
|
"locationInModule": {
|
|
270
270
|
"filename": "src/BatmanProject.ts",
|
|
271
|
-
"line":
|
|
271
|
+
"line": 42
|
|
272
272
|
},
|
|
273
273
|
"name": "additionalCodeOwners",
|
|
274
274
|
"optional": true,
|
|
@@ -290,7 +290,7 @@
|
|
|
290
290
|
"immutable": true,
|
|
291
291
|
"locationInModule": {
|
|
292
292
|
"filename": "src/BatmanProject.ts",
|
|
293
|
-
"line":
|
|
293
|
+
"line": 32
|
|
294
294
|
},
|
|
295
295
|
"name": "additionalTags",
|
|
296
296
|
"optional": true,
|
|
@@ -313,7 +313,7 @@
|
|
|
313
313
|
"immutable": true,
|
|
314
314
|
"locationInModule": {
|
|
315
315
|
"filename": "src/BatmanProject.ts",
|
|
316
|
-
"line":
|
|
316
|
+
"line": 59
|
|
317
317
|
},
|
|
318
318
|
"name": "authorizerObjectVersion",
|
|
319
319
|
"optional": true,
|
|
@@ -330,7 +330,7 @@
|
|
|
330
330
|
"immutable": true,
|
|
331
331
|
"locationInModule": {
|
|
332
332
|
"filename": "src/BatmanProject.ts",
|
|
333
|
-
"line":
|
|
333
|
+
"line": 37
|
|
334
334
|
},
|
|
335
335
|
"name": "n8nWorkflows",
|
|
336
336
|
"optional": true,
|
|
@@ -347,7 +347,7 @@
|
|
|
347
347
|
"immutable": true,
|
|
348
348
|
"locationInModule": {
|
|
349
349
|
"filename": "src/BatmanProject.ts",
|
|
350
|
-
"line":
|
|
350
|
+
"line": 47
|
|
351
351
|
},
|
|
352
352
|
"name": "websiteDeps",
|
|
353
353
|
"optional": true,
|
|
@@ -376,7 +376,7 @@
|
|
|
376
376
|
},
|
|
377
377
|
"locationInModule": {
|
|
378
378
|
"filename": "src/BootcampProject.ts",
|
|
379
|
-
"line":
|
|
379
|
+
"line": 18
|
|
380
380
|
},
|
|
381
381
|
"parameters": [
|
|
382
382
|
{
|
|
@@ -390,7 +390,7 @@
|
|
|
390
390
|
"kind": "class",
|
|
391
391
|
"locationInModule": {
|
|
392
392
|
"filename": "src/BootcampProject.ts",
|
|
393
|
-
"line":
|
|
393
|
+
"line": 17
|
|
394
394
|
},
|
|
395
395
|
"name": "BootcampProject",
|
|
396
396
|
"symbolId": "src/BootcampProject:BootcampProject"
|
|
@@ -408,7 +408,7 @@
|
|
|
408
408
|
"kind": "interface",
|
|
409
409
|
"locationInModule": {
|
|
410
410
|
"filename": "src/BootcampProject.ts",
|
|
411
|
-
"line":
|
|
411
|
+
"line": 13
|
|
412
412
|
},
|
|
413
413
|
"name": "BootcampProjectOptions",
|
|
414
414
|
"symbolId": "src/BootcampProject:BootcampProjectOptions"
|
|
@@ -780,6 +780,113 @@
|
|
|
780
780
|
],
|
|
781
781
|
"symbolId": "src/ProductionDeployWorkflow:ProductionDeployWorkflowOptions"
|
|
782
782
|
},
|
|
783
|
+
"@macedon-technologies/batman.SoftwareFactoryFiles": {
|
|
784
|
+
"assembly": "@macedon-technologies/batman",
|
|
785
|
+
"docs": {
|
|
786
|
+
"remarks": "What swamp itself would generate (extension docs pulled via\n`swamp extension pull`, `.swamp.yaml`, the vault, and the \"swamp managed\nsection\" in CLAUDE.md) is deliberately NOT hand-templated here — those are\nproduced by the real `swamp` CLI. `swamp init` is idempotent (a no-op if\nthe repo is already initialized), so it's wired into the project's\n`install`/`install:ci` tasks and runs automatically on every install,\nguarded so it's a silent no-op on a machine without `swamp` on PATH (e.g.\nCI). The extension pulls and vault creation are one-time, not idempotent\nin a way that's safe to repeat on every install, so they stay in the\n`swamp:bootstrap` task this construct adds. Only exman's own authored\nconfig (the factory's state machine, the architecture-rule engine, the\nattestation mechanism, the OpenSpec task-completion gate, and the 3 swamp\nworkflows that wire them together) is templated.",
|
|
787
|
+
"stability": "stable",
|
|
788
|
+
"summary": "Backports exman's swamp \"software factory\" pattern (macedon-technologies/exman#13) as generated scaffolding: a `@swamp/software-factory` state machine that drives a GitHub issue from intake through an opened PR, enforcing OpenSpec usage, an architecture rule registry, and a pre-PR verification gate whose attestation is re-checked at merge time."
|
|
789
|
+
},
|
|
790
|
+
"fqn": "@macedon-technologies/batman.SoftwareFactoryFiles",
|
|
791
|
+
"initializer": {
|
|
792
|
+
"docs": {
|
|
793
|
+
"stability": "stable"
|
|
794
|
+
},
|
|
795
|
+
"locationInModule": {
|
|
796
|
+
"filename": "src/SoftwareFactoryFiles.ts",
|
|
797
|
+
"line": 55
|
|
798
|
+
},
|
|
799
|
+
"parameters": [
|
|
800
|
+
{
|
|
801
|
+
"name": "project",
|
|
802
|
+
"type": {
|
|
803
|
+
"fqn": "projen.javascript.NodeProject"
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
"name": "options",
|
|
808
|
+
"type": {
|
|
809
|
+
"fqn": "@macedon-technologies/batman.SoftwareFactoryFilesOptions"
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
]
|
|
813
|
+
},
|
|
814
|
+
"kind": "class",
|
|
815
|
+
"locationInModule": {
|
|
816
|
+
"filename": "src/SoftwareFactoryFiles.ts",
|
|
817
|
+
"line": 54
|
|
818
|
+
},
|
|
819
|
+
"name": "SoftwareFactoryFiles",
|
|
820
|
+
"symbolId": "src/SoftwareFactoryFiles:SoftwareFactoryFiles"
|
|
821
|
+
},
|
|
822
|
+
"@macedon-technologies/batman.SoftwareFactoryFilesOptions": {
|
|
823
|
+
"assembly": "@macedon-technologies/batman",
|
|
824
|
+
"datatype": true,
|
|
825
|
+
"docs": {
|
|
826
|
+
"stability": "stable"
|
|
827
|
+
},
|
|
828
|
+
"fqn": "@macedon-technologies/batman.SoftwareFactoryFilesOptions",
|
|
829
|
+
"kind": "interface",
|
|
830
|
+
"locationInModule": {
|
|
831
|
+
"filename": "src/SoftwareFactoryFiles.ts",
|
|
832
|
+
"line": 11
|
|
833
|
+
},
|
|
834
|
+
"name": "SoftwareFactoryFilesOptions",
|
|
835
|
+
"properties": [
|
|
836
|
+
{
|
|
837
|
+
"abstract": true,
|
|
838
|
+
"docs": {
|
|
839
|
+
"stability": "stable",
|
|
840
|
+
"summary": "The bare repo name (e.g. `expense-tracker`), used to derive the factory's model names (`<repoName>-factory`, `<repoName>-issues`, `<repoName>-pr`, `<repoName>-shell*`) and vault name (`<repoName>-secrets`)."
|
|
841
|
+
},
|
|
842
|
+
"immutable": true,
|
|
843
|
+
"locationInModule": {
|
|
844
|
+
"filename": "src/SoftwareFactoryFiles.ts",
|
|
845
|
+
"line": 17
|
|
846
|
+
},
|
|
847
|
+
"name": "repoName",
|
|
848
|
+
"type": {
|
|
849
|
+
"primitive": "string"
|
|
850
|
+
}
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
"abstract": true,
|
|
854
|
+
"docs": {
|
|
855
|
+
"stability": "stable",
|
|
856
|
+
"summary": "Overrides for the pinned action versions used by `verify-attestation.yml`."
|
|
857
|
+
},
|
|
858
|
+
"immutable": true,
|
|
859
|
+
"locationInModule": {
|
|
860
|
+
"filename": "src/SoftwareFactoryFiles.ts",
|
|
861
|
+
"line": 29
|
|
862
|
+
},
|
|
863
|
+
"name": "actionVersions",
|
|
864
|
+
"optional": true,
|
|
865
|
+
"type": {
|
|
866
|
+
"fqn": "@macedon-technologies/batman.WorkflowActionVersions"
|
|
867
|
+
}
|
|
868
|
+
},
|
|
869
|
+
{
|
|
870
|
+
"abstract": true,
|
|
871
|
+
"docs": {
|
|
872
|
+
"default": "'main'",
|
|
873
|
+
"stability": "stable",
|
|
874
|
+
"summary": "The branch the factory opens pull requests against."
|
|
875
|
+
},
|
|
876
|
+
"immutable": true,
|
|
877
|
+
"locationInModule": {
|
|
878
|
+
"filename": "src/SoftwareFactoryFiles.ts",
|
|
879
|
+
"line": 24
|
|
880
|
+
},
|
|
881
|
+
"name": "baseBranch",
|
|
882
|
+
"optional": true,
|
|
883
|
+
"type": {
|
|
884
|
+
"primitive": "string"
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
],
|
|
888
|
+
"symbolId": "src/SoftwareFactoryFiles:SoftwareFactoryFilesOptions"
|
|
889
|
+
},
|
|
783
890
|
"@macedon-technologies/batman.StagingDeployWorkflow": {
|
|
784
891
|
"assembly": "@macedon-technologies/batman",
|
|
785
892
|
"base": "projen.YamlFile",
|
|
@@ -1140,6 +1247,6 @@
|
|
|
1140
1247
|
"symbolId": "src/WorkflowAutoDiscover:WorkflowAutoDiscover"
|
|
1141
1248
|
}
|
|
1142
1249
|
},
|
|
1143
|
-
"version": "1.
|
|
1144
|
-
"fingerprint": "
|
|
1250
|
+
"version": "1.18.0",
|
|
1251
|
+
"fingerprint": "JZfOtlClOJntadBGRkaeJ0IXkGuwwTH6CJrv4+kfKYI="
|
|
1145
1252
|
}
|
package/.swamp.yaml
ADDED
package/API.md
CHANGED
|
@@ -10572,6 +10572,63 @@ Overrides for the pinned action versions used by this workflow.
|
|
|
10572
10572
|
|
|
10573
10573
|
---
|
|
10574
10574
|
|
|
10575
|
+
### SoftwareFactoryFilesOptions <a name="SoftwareFactoryFilesOptions" id="@macedon-technologies/batman.SoftwareFactoryFilesOptions"></a>
|
|
10576
|
+
|
|
10577
|
+
#### Initializer <a name="Initializer" id="@macedon-technologies/batman.SoftwareFactoryFilesOptions.Initializer"></a>
|
|
10578
|
+
|
|
10579
|
+
```typescript
|
|
10580
|
+
import { SoftwareFactoryFilesOptions } from '@macedon-technologies/batman'
|
|
10581
|
+
|
|
10582
|
+
const softwareFactoryFilesOptions: SoftwareFactoryFilesOptions = { ... }
|
|
10583
|
+
```
|
|
10584
|
+
|
|
10585
|
+
#### Properties <a name="Properties" id="Properties"></a>
|
|
10586
|
+
|
|
10587
|
+
| **Name** | **Type** | **Description** |
|
|
10588
|
+
| --- | --- | --- |
|
|
10589
|
+
| <code><a href="#@macedon-technologies/batman.SoftwareFactoryFilesOptions.property.repoName">repoName</a></code> | <code>string</code> | The bare repo name (e.g. `expense-tracker`), used to derive the factory's model names (`<repoName>-factory`, `<repoName>-issues`, `<repoName>-pr`, `<repoName>-shell*`) and vault name (`<repoName>-secrets`). |
|
|
10590
|
+
| <code><a href="#@macedon-technologies/batman.SoftwareFactoryFilesOptions.property.actionVersions">actionVersions</a></code> | <code><a href="#@macedon-technologies/batman.WorkflowActionVersions">WorkflowActionVersions</a></code> | Overrides for the pinned action versions used by `verify-attestation.yml`. |
|
|
10591
|
+
| <code><a href="#@macedon-technologies/batman.SoftwareFactoryFilesOptions.property.baseBranch">baseBranch</a></code> | <code>string</code> | The branch the factory opens pull requests against. |
|
|
10592
|
+
|
|
10593
|
+
---
|
|
10594
|
+
|
|
10595
|
+
##### `repoName`<sup>Required</sup> <a name="repoName" id="@macedon-technologies/batman.SoftwareFactoryFilesOptions.property.repoName"></a>
|
|
10596
|
+
|
|
10597
|
+
```typescript
|
|
10598
|
+
public readonly repoName: string;
|
|
10599
|
+
```
|
|
10600
|
+
|
|
10601
|
+
- *Type:* string
|
|
10602
|
+
|
|
10603
|
+
The bare repo name (e.g. `expense-tracker`), used to derive the factory's model names (`<repoName>-factory`, `<repoName>-issues`, `<repoName>-pr`, `<repoName>-shell*`) and vault name (`<repoName>-secrets`).
|
|
10604
|
+
|
|
10605
|
+
---
|
|
10606
|
+
|
|
10607
|
+
##### `actionVersions`<sup>Optional</sup> <a name="actionVersions" id="@macedon-technologies/batman.SoftwareFactoryFilesOptions.property.actionVersions"></a>
|
|
10608
|
+
|
|
10609
|
+
```typescript
|
|
10610
|
+
public readonly actionVersions: WorkflowActionVersions;
|
|
10611
|
+
```
|
|
10612
|
+
|
|
10613
|
+
- *Type:* <a href="#@macedon-technologies/batman.WorkflowActionVersions">WorkflowActionVersions</a>
|
|
10614
|
+
|
|
10615
|
+
Overrides for the pinned action versions used by `verify-attestation.yml`.
|
|
10616
|
+
|
|
10617
|
+
---
|
|
10618
|
+
|
|
10619
|
+
##### `baseBranch`<sup>Optional</sup> <a name="baseBranch" id="@macedon-technologies/batman.SoftwareFactoryFilesOptions.property.baseBranch"></a>
|
|
10620
|
+
|
|
10621
|
+
```typescript
|
|
10622
|
+
public readonly baseBranch: string;
|
|
10623
|
+
```
|
|
10624
|
+
|
|
10625
|
+
- *Type:* string
|
|
10626
|
+
- *Default:* 'main'
|
|
10627
|
+
|
|
10628
|
+
The branch the factory opens pull requests against.
|
|
10629
|
+
|
|
10630
|
+
---
|
|
10631
|
+
|
|
10575
10632
|
### StagingDeployWorkflowOptions <a name="StagingDeployWorkflowOptions" id="@macedon-technologies/batman.StagingDeployWorkflowOptions"></a>
|
|
10576
10633
|
|
|
10577
10634
|
#### Initializer <a name="Initializer" id="@macedon-technologies/batman.StagingDeployWorkflowOptions.Initializer"></a>
|
|
@@ -10797,5 +10854,55 @@ The `actions/upload-artifact` action reference, used by projen's built-in depend
|
|
|
10797
10854
|
|
|
10798
10855
|
---
|
|
10799
10856
|
|
|
10857
|
+
## Classes <a name="Classes" id="Classes"></a>
|
|
10858
|
+
|
|
10859
|
+
### SoftwareFactoryFiles <a name="SoftwareFactoryFiles" id="@macedon-technologies/batman.SoftwareFactoryFiles"></a>
|
|
10860
|
+
|
|
10861
|
+
Backports exman's swamp "software factory" pattern (macedon-technologies/exman#13) as generated scaffolding: a `@swamp/software-factory` state machine that drives a GitHub issue from intake through an opened PR, enforcing OpenSpec usage, an architecture rule registry, and a pre-PR verification gate whose attestation is re-checked at merge time.
|
|
10862
|
+
|
|
10863
|
+
What swamp itself would generate (extension docs pulled via
|
|
10864
|
+
`swamp extension pull`, `.swamp.yaml`, the vault, and the "swamp managed
|
|
10865
|
+
section" in CLAUDE.md) is deliberately NOT hand-templated here — those are
|
|
10866
|
+
produced by the real `swamp` CLI. `swamp init` is idempotent (a no-op if
|
|
10867
|
+
the repo is already initialized), so it's wired into the project's
|
|
10868
|
+
`install`/`install:ci` tasks and runs automatically on every install,
|
|
10869
|
+
guarded so it's a silent no-op on a machine without `swamp` on PATH (e.g.
|
|
10870
|
+
CI). The extension pulls and vault creation are one-time, not idempotent
|
|
10871
|
+
in a way that's safe to repeat on every install, so they stay in the
|
|
10872
|
+
`swamp:bootstrap` task this construct adds. Only exman's own authored
|
|
10873
|
+
config (the factory's state machine, the architecture-rule engine, the
|
|
10874
|
+
attestation mechanism, the OpenSpec task-completion gate, and the 3 swamp
|
|
10875
|
+
workflows that wire them together) is templated.
|
|
10876
|
+
|
|
10877
|
+
#### Initializers <a name="Initializers" id="@macedon-technologies/batman.SoftwareFactoryFiles.Initializer"></a>
|
|
10878
|
+
|
|
10879
|
+
```typescript
|
|
10880
|
+
import { SoftwareFactoryFiles } from '@macedon-technologies/batman'
|
|
10881
|
+
|
|
10882
|
+
new SoftwareFactoryFiles(project: NodeProject, options: SoftwareFactoryFilesOptions)
|
|
10883
|
+
```
|
|
10884
|
+
|
|
10885
|
+
| **Name** | **Type** | **Description** |
|
|
10886
|
+
| --- | --- | --- |
|
|
10887
|
+
| <code><a href="#@macedon-technologies/batman.SoftwareFactoryFiles.Initializer.parameter.project">project</a></code> | <code>projen.javascript.NodeProject</code> | *No description.* |
|
|
10888
|
+
| <code><a href="#@macedon-technologies/batman.SoftwareFactoryFiles.Initializer.parameter.options">options</a></code> | <code><a href="#@macedon-technologies/batman.SoftwareFactoryFilesOptions">SoftwareFactoryFilesOptions</a></code> | *No description.* |
|
|
10889
|
+
|
|
10890
|
+
---
|
|
10891
|
+
|
|
10892
|
+
##### `project`<sup>Required</sup> <a name="project" id="@macedon-technologies/batman.SoftwareFactoryFiles.Initializer.parameter.project"></a>
|
|
10893
|
+
|
|
10894
|
+
- *Type:* projen.javascript.NodeProject
|
|
10895
|
+
|
|
10896
|
+
---
|
|
10897
|
+
|
|
10898
|
+
##### `options`<sup>Required</sup> <a name="options" id="@macedon-technologies/batman.SoftwareFactoryFiles.Initializer.parameter.options"></a>
|
|
10899
|
+
|
|
10900
|
+
- *Type:* <a href="#@macedon-technologies/batman.SoftwareFactoryFilesOptions">SoftwareFactoryFilesOptions</a>
|
|
10901
|
+
|
|
10902
|
+
---
|
|
10903
|
+
|
|
10904
|
+
|
|
10905
|
+
|
|
10906
|
+
|
|
10800
10907
|
|
|
10801
10908
|
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<!-- BEGIN swamp managed section - DO NOT EDIT -->
|
|
2
|
+
# Project
|
|
3
|
+
|
|
4
|
+
This repository is managed with [swamp](https://github.com/swamp-club/swamp).
|
|
5
|
+
|
|
6
|
+
## Rules
|
|
7
|
+
|
|
8
|
+
1. **Search before you build.** When automating AWS, APIs, or any external service: (a) search community extensions with `swamp extension search <query>` — prefer `@swamp/*` official extensions first, (b) search local/installed types with `swamp model type search <query>`, (c) if a community extension exists, install it with `swamp extension pull <package>` instead of building from scratch, (d) extend an existing type if it covers the domain but lacks the method you need, (e) only create a custom extension model in `extensions/models/` as a last resort. Use the `swamp` skill for guidance. The `command/shell` model is ONLY for ad-hoc one-off shell commands, NEVER for wrapping CLI tools or building integrations.
|
|
9
|
+
2. **Extend, don't be clever.** When a model covers the domain but lacks the method you need, extend it with `export const extension` — don't bypass it with shell scripts, CLI tools, or multi-step hacks. One method, one purpose. Use `swamp model type describe <type> --json` to check available methods.
|
|
10
|
+
3. **Use the data model.** Once data exists in a model (via `lookup`, `start`, `sync`, etc.), reference it with CEL expressions. Don't re-fetch data that's already available.
|
|
11
|
+
4. **CEL expressions everywhere.** Wire models together with CEL expressions. Always prefer `data.latest("<name>", "<dataName>").attributes.<field>` over the deprecated `model.<name>.resource.<spec>.<instance>.attributes.<field>` pattern.
|
|
12
|
+
5. **Verify before destructive operations.** Always `swamp model get <name> --json` and verify resource IDs before running delete/stop/destroy methods.
|
|
13
|
+
6. **Prefer fan-out methods over loops.** When operating on multiple targets, use a single method that handles all targets internally (factory pattern) rather than looping N separate `swamp model method run` calls against the same model. Multiple parallel calls against the same model contend on the per-model lock, causing timeouts. A single fan-out method acquires the lock once and produces all outputs in one execution. Check `swamp model type describe` for methods that accept filters or produce multiple outputs.
|
|
14
|
+
7. **Extension npm deps are bundled, not lockfile-tracked.** Swamp's bundler inlines all npm packages (except zod) into extension bundles at bundle time. `deno.lock` and `package.json` do NOT cover extension model dependencies — this is by design. Always pin explicit versions in `npm:` import specifiers (e.g., `npm:lodash-es@4.17.21`).
|
|
15
|
+
8. **Reports for reusable data pipelines.** When the task involves building a repeatable pipeline to transform, aggregate, or analyze model output (security reports, cost analysis, compliance checks, summaries), create a report extension. Use the `swamp` skill for guidance.
|
|
16
|
+
9. **"Workflow" means a swamp workflow.** In this repository the word "workflow" (and "create/run/execute/validate/debug workflow", "automate", "orchestrate", "automated/nightly job") refers to a swamp workflow — a declarative YAML DAG of model-method steps authored via `swamp workflow create`. Load and follow the `swamp` skill for these requests. Do NOT interpret these as a request to build an agent task list, spin up worktrees, or schedule a cron/remote agent. Only use those orchestration mechanisms when the user explicitly names one (e.g. "task list", "subagent", "worktree", "cron", "remote agent") or explicitly asks you to do the work yourself step by step rather than author a swamp workflow.
|
|
17
|
+
10. **Use swamp, don't bypass it.** Always work through swamp commands — don't go around them with raw shell tools. Use `swamp data query` to find data, not `grep`/`find` on `.swamp/` files. Use model methods to interact with resources, not `curl`/`aws`/`gcloud`/`kubectl` when a model type already wraps that API — check with `swamp model type search`. Use `swamp help` for CLI discovery, not guesswork. Composing with swamp output is fine (e.g. piping `--json` through `jq`) — the anti-pattern is bypassing swamp entirely.
|
|
18
|
+
11. **Inspect reports after failures.** When a model method or workflow run fails, inspect its generated reports before retrying or changing definitions. Reports run even on failure and capture structured diagnostics — error messages, execution status, arguments, and data output pointers. Use `swamp report get @swamp/method-summary --model <model> --json` for method failures or `swamp report get @swamp/workflow-summary --workflow <workflow> --json` for workflow failures. Run `swamp help report get` to confirm current retrieval syntax.
|
|
19
|
+
|
|
20
|
+
## Skills
|
|
21
|
+
|
|
22
|
+
**IMPORTANT:** Always load swamp skills, even when in plan mode. The skills provide
|
|
23
|
+
essential context for working with this repository.
|
|
24
|
+
|
|
25
|
+
- `swamp` - Swamp CLI — models, workflows, data, vaults, extensions, publishing, repos, reports, issues, and troubleshooting
|
|
26
|
+
- `swamp-getting-started` - Interactive onboarding for new swamp users
|
|
27
|
+
|
|
28
|
+
## Getting Started
|
|
29
|
+
|
|
30
|
+
**IMPORTANT:** At the start of every conversation, run
|
|
31
|
+
`swamp model search --json`. If no models are returned (empty result), you MUST
|
|
32
|
+
immediately invoke the `swamp-getting-started` skill before doing anything else.
|
|
33
|
+
This walks new users through an interactive onboarding tutorial.
|
|
34
|
+
|
|
35
|
+
If models already exist, start by using the `swamp` skill to work with
|
|
36
|
+
swamp models.
|
|
37
|
+
|
|
38
|
+
## Commands
|
|
39
|
+
|
|
40
|
+
Use `swamp --help` to see available commands. For a machine-readable JSON
|
|
41
|
+
schema of the CLI (commands, options, arguments) intended for agent
|
|
42
|
+
consumption, run `swamp help [<command>...]` — e.g. `swamp help` returns
|
|
43
|
+
the full tree, and `swamp help model method run` scopes to a subtree.
|
|
44
|
+
<!-- END swamp managed section -->
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Architecture rules
|
|
2
|
+
|
|
3
|
+
A data-driven registry of architectural constraints, enforced by
|
|
4
|
+
`pnpm validate:architecture` and run as part of the pre-PR verification
|
|
5
|
+
workflow (`workflows/workflow-pre-pr-verify.yaml`) before the swamp factory
|
|
6
|
+
opens a PR. New rules are new entries in `rules.json`, not new code — the
|
|
7
|
+
engine (`check.ts`) only needs a new case in `evaluateRule()` when a rule
|
|
8
|
+
needs a genuinely new kind of check.
|
|
9
|
+
|
|
10
|
+
## Rule shape
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"id": "unique-id",
|
|
15
|
+
"description": "What this enforces and why.",
|
|
16
|
+
"enabled": true,
|
|
17
|
+
"severity": "low" | "medium" | "high" | "critical",
|
|
18
|
+
"check": {
|
|
19
|
+
"type": "forbidden-import",
|
|
20
|
+
"from": ["glob patterns selecting files this rule inspects"],
|
|
21
|
+
"forbid": ["glob patterns those files may not import from"]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`enabled: false` rules are skipped (reported as "deferred") rather than
|
|
27
|
+
evaluated — use this for a rule you've named and described but don't yet
|
|
28
|
+
have a concrete convention to check.
|
|
29
|
+
|
|
30
|
+
## Current rules
|
|
31
|
+
|
|
32
|
+
None yet — `rules.json` ships empty. Add rules as your domain module
|
|
33
|
+
conventions solidify (e.g. an event-sourced/CQRS module layout under
|
|
34
|
+
`src/domains/<name>/{commands,events,aggregates,projections}/`).
|
|
35
|
+
|
|
36
|
+
## Adding a check type
|
|
37
|
+
|
|
38
|
+
`forbidden-import` is the only implemented `check.type`. If a future rule
|
|
39
|
+
needs something it can't express (e.g. "every aggregate file must have a
|
|
40
|
+
matching events file"), add a new `type` value, a matching interface, and a
|
|
41
|
+
case in `evaluateRule()` in `check.ts` — keep the engine itself generic;
|
|
42
|
+
rule-specific knowledge belongs in `rules.json`.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic architecture-rule engine. Rules live entirely in rules.json — this
|
|
3
|
+
* file only knows how to evaluate the check "types" that rules can declare.
|
|
4
|
+
* Add a new rule by adding a rules.json entry; add a new check type by adding
|
|
5
|
+
* a case in evaluateRule().
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import rulesFile from './rules.json';
|
|
10
|
+
|
|
11
|
+
interface ForbiddenImportCheck {
|
|
12
|
+
type: 'forbidden-import';
|
|
13
|
+
// Glob patterns (relative to repo root) selecting the files this rule inspects.
|
|
14
|
+
from: string[];
|
|
15
|
+
// Glob patterns (relative to repo root) that "from" files may not import from.
|
|
16
|
+
forbid: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Rule {
|
|
20
|
+
id: string;
|
|
21
|
+
description: string;
|
|
22
|
+
enabled: boolean;
|
|
23
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
24
|
+
check: ForbiddenImportCheck;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface Violation {
|
|
28
|
+
ruleId: string;
|
|
29
|
+
severity: string;
|
|
30
|
+
message: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
34
|
+
const IGNORED_DIRS = new Set(['node_modules', '.git', '.swamp', 'cdk.out', 'lib', 'build', 'dist']);
|
|
35
|
+
|
|
36
|
+
// Minimal glob -> RegExp: supports "*", "**", "**/" and literal path segments.
|
|
37
|
+
// No new dependency for this — the only pattern shapes rules.json ever needs
|
|
38
|
+
// are directory-prefix globs like "src/domains/*/commands/**".
|
|
39
|
+
function globToRegExp(glob: string): RegExp {
|
|
40
|
+
let out = '';
|
|
41
|
+
for (let i = 0; i < glob.length; i++) {
|
|
42
|
+
const c = glob[i];
|
|
43
|
+
if (c === '*' && glob[i + 1] === '*') {
|
|
44
|
+
i++;
|
|
45
|
+
if (glob[i + 1] === '/') {
|
|
46
|
+
out += '(?:.*/)?';
|
|
47
|
+
i++;
|
|
48
|
+
} else {
|
|
49
|
+
out += '.*';
|
|
50
|
+
}
|
|
51
|
+
} else if (c === '*') {
|
|
52
|
+
out += '[^/]*';
|
|
53
|
+
} else if (c === '?') {
|
|
54
|
+
out += '[^/]';
|
|
55
|
+
} else if ('.+^${}()|[]\\'.includes(c)) {
|
|
56
|
+
out += `\\${c}`;
|
|
57
|
+
} else {
|
|
58
|
+
out += c;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return new RegExp(`^${out}$`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function matchesAny(relFile: string, globs: string[]): boolean {
|
|
65
|
+
return globs.some((glob) => globToRegExp(glob).test(relFile));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function toRepoRelative(absPath: string): string {
|
|
69
|
+
return path.relative(REPO_ROOT, absPath).split(path.sep).join('/');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function walk(dir: string, acc: string[] = []): string[] {
|
|
73
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
74
|
+
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
75
|
+
const full = path.join(dir, entry.name);
|
|
76
|
+
if (entry.isDirectory()) {
|
|
77
|
+
walk(full, acc);
|
|
78
|
+
} else if (entry.isFile() && (entry.name.endsWith('.ts') || entry.name.endsWith('.tsx'))) {
|
|
79
|
+
acc.push(full);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return acc;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const RELATIVE_IMPORT_RE = /(?:import|export)\s+(?:[^'";]*?\bfrom\s+)?['"](\.[^'"]+)['"]/g;
|
|
86
|
+
|
|
87
|
+
function findRelativeImports(source: string): string[] {
|
|
88
|
+
const specs: string[] = [];
|
|
89
|
+
RELATIVE_IMPORT_RE.lastIndex = 0;
|
|
90
|
+
let match: RegExpExecArray | null;
|
|
91
|
+
while ((match = RELATIVE_IMPORT_RE.exec(source))) {
|
|
92
|
+
specs.push(match[1]);
|
|
93
|
+
}
|
|
94
|
+
return specs;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// An import spec resolves to a module, not a specific file extension, so a
|
|
98
|
+
// forbid glob is checked against the bare resolved path plus its .ts/index.ts
|
|
99
|
+
// variants.
|
|
100
|
+
function resolvedCandidates(fromFile: string, spec: string): string[] {
|
|
101
|
+
const resolved = toRepoRelative(path.normalize(path.join(path.dirname(fromFile), spec)));
|
|
102
|
+
return [resolved, `${resolved}.ts`, `${resolved}/index.ts`];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function evaluateForbiddenImport(rule: Rule): Violation[] {
|
|
106
|
+
const { from, forbid } = rule.check;
|
|
107
|
+
if (from.length === 0 || forbid.length === 0) return [];
|
|
108
|
+
|
|
109
|
+
const violations: Violation[] = [];
|
|
110
|
+
for (const file of walk(REPO_ROOT)) {
|
|
111
|
+
const relFile = toRepoRelative(file);
|
|
112
|
+
if (!matchesAny(relFile, from)) continue;
|
|
113
|
+
|
|
114
|
+
const source = fs.readFileSync(file, 'utf8');
|
|
115
|
+
for (const spec of findRelativeImports(source)) {
|
|
116
|
+
const candidates = resolvedCandidates(file, spec);
|
|
117
|
+
if (candidates.some((candidate) => matchesAny(candidate, forbid))) {
|
|
118
|
+
violations.push({
|
|
119
|
+
ruleId: rule.id,
|
|
120
|
+
severity: rule.severity,
|
|
121
|
+
message: `${relFile} imports "${spec}", which resolves under a path forbidden by rule "${rule.id}"`,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return violations;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function evaluateRule(rule: Rule): Violation[] {
|
|
130
|
+
switch (rule.check.type) {
|
|
131
|
+
case 'forbidden-import':
|
|
132
|
+
return evaluateForbiddenImport(rule);
|
|
133
|
+
default:
|
|
134
|
+
throw new Error(`architecture-rules: unknown check.type "${(rule.check as { type: string }).type}" on rule "${rule.id}"`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function main(): number {
|
|
139
|
+
const rules = (rulesFile as { rules: Rule[] }).rules;
|
|
140
|
+
let evaluated = 0;
|
|
141
|
+
let deferred = 0;
|
|
142
|
+
const violations: Violation[] = [];
|
|
143
|
+
|
|
144
|
+
for (const rule of rules) {
|
|
145
|
+
if (!rule.enabled) {
|
|
146
|
+
deferred++;
|
|
147
|
+
console.log(`[deferred] ${rule.id}: ${rule.description}`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
evaluated++;
|
|
151
|
+
violations.push(...evaluateRule(rule));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log(`\narchitecture-rules: ${evaluated} rule(s) evaluated, ${deferred} deferred, ${violations.length} violation(s)`);
|
|
155
|
+
for (const violation of violations) {
|
|
156
|
+
console.error(` [${violation.severity}] ${violation.ruleId}: ${violation.message}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return violations.length > 0 ? 1 : 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
process.exit(main());
|