@macedon-technologies/batman 1.17.3 → 1.18.1

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 (47) hide show
  1. package/.jsii +124 -17
  2. package/.swamp.yaml +6 -0
  3. package/API.md +107 -0
  4. package/CLAUDE.md +44 -0
  5. package/architecture-rules/README.md +42 -0
  6. package/architecture-rules/check.ts +162 -0
  7. package/architecture-rules/rules.json +3 -0
  8. package/architecture-rules/tsconfig.json +14 -0
  9. package/attestation/manifest.ts +40 -0
  10. package/attestation/tsconfig.json +13 -0
  11. package/attestation/verify.ts +142 -0
  12. package/lib/BaseApplicationStackFile.js +4 -3
  13. package/lib/BatmanProject.js +8 -2
  14. package/lib/BootcampBaseApplicationStackFile.js +4 -3
  15. package/lib/BootcampProject.js +8 -2
  16. package/lib/CodeOwnersFile.js +1 -1
  17. package/lib/ProductionDeployWorkflow.js +1 -1
  18. package/lib/SoftwareFactoryArchitectureRules.d.ts +10 -0
  19. package/lib/SoftwareFactoryArchitectureRules.js +245 -0
  20. package/lib/SoftwareFactoryAttestation.d.ts +18 -0
  21. package/lib/SoftwareFactoryAttestation.js +221 -0
  22. package/lib/SoftwareFactoryFiles.d.ts +45 -0
  23. package/lib/SoftwareFactoryFiles.js +102 -0
  24. package/lib/SoftwareFactoryModels.d.ts +25 -0
  25. package/lib/SoftwareFactoryModels.js +306 -0
  26. package/lib/SoftwareFactoryOpenSpecGates.d.ts +8 -0
  27. package/lib/SoftwareFactoryOpenSpecGates.js +75 -0
  28. package/lib/SoftwareFactoryWorkflows.d.ts +28 -0
  29. package/lib/SoftwareFactoryWorkflows.js +326 -0
  30. package/lib/StagingDeployWorkflow.js +1 -1
  31. package/lib/StaticWebsiteConstructFile.js +2 -2
  32. package/lib/WorkflowAutoDiscover.js +1 -1
  33. package/lib/index.d.ts +1 -0
  34. package/lib/index.js +2 -1
  35. package/lib/utils.js +29 -1
  36. package/models/@goodcraft/github/platform-common-pr.yaml +10 -0
  37. package/models/@swamp/software-factory/platform-common-factory.yaml +240 -0
  38. package/models/@webframp/github/platform-common-issues.yaml +8 -0
  39. package/models/command/shell/platform-common-shell-architecture.yaml +8 -0
  40. package/models/command/shell/platform-common-shell-manifest.yaml +8 -0
  41. package/models/command/shell/platform-common-shell.yaml +8 -0
  42. package/openspec-gates/check-tasks-complete.ts +44 -0
  43. package/openspec-gates/tsconfig.json +13 -0
  44. package/package.json +6 -1
  45. package/workflows/workflow-openspec-plan-verify.yaml +51 -0
  46. package/workflows/workflow-openspec-tasks-verify.yaml +51 -0
  47. package/workflows/workflow-pre-pr-verify.yaml +118 -0
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SoftwareFactoryFiles = void 0;
4
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
5
+ const SoftwareFactoryArchitectureRules_1 = require("./SoftwareFactoryArchitectureRules");
6
+ const SoftwareFactoryAttestation_1 = require("./SoftwareFactoryAttestation");
7
+ const SoftwareFactoryModels_1 = require("./SoftwareFactoryModels");
8
+ const SoftwareFactoryOpenSpecGates_1 = require("./SoftwareFactoryOpenSpecGates");
9
+ const SoftwareFactoryWorkflows_1 = require("./SoftwareFactoryWorkflows");
10
+ const GITHUB_OWNER = 'macedon-technologies';
11
+ /**
12
+ * Backports exman's swamp "software factory" pattern
13
+ * (macedon-technologies/exman#13) as generated scaffolding: a
14
+ * `@swamp/software-factory` state machine that drives a GitHub issue from
15
+ * intake through an opened PR, enforcing OpenSpec usage, an architecture
16
+ * rule registry, and a pre-PR verification gate whose attestation is
17
+ * re-checked at merge time.
18
+ *
19
+ * What swamp itself would generate (extension docs pulled via
20
+ * `swamp extension pull`, `.swamp.yaml`, the vault, and the "swamp managed
21
+ * section" in CLAUDE.md) is deliberately NOT hand-templated here — those are
22
+ * produced by the real `swamp` CLI. `swamp init` is idempotent (a no-op if
23
+ * the repo is already initialized), so it's wired into the project's
24
+ * `install`/`install:ci` tasks and runs automatically on every install,
25
+ * guarded so it's a silent no-op on a machine without `swamp` on PATH (e.g.
26
+ * CI). The extension pulls and vault creation are one-time, not idempotent
27
+ * in a way that's safe to repeat on every install, so they stay in the
28
+ * `swamp:bootstrap` task this construct adds. Only exman's own authored
29
+ * config (the factory's state machine, the architecture-rule engine, the
30
+ * attestation mechanism, the OpenSpec task-completion gate, and the 3 swamp
31
+ * workflows that wire them together) is templated.
32
+ */
33
+ class SoftwareFactoryFiles {
34
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@macedon-technologies/batman.SoftwareFactoryFiles", version: "1.18.1" };
35
+ constructor(project, options) {
36
+ const { repoName, actionVersions } = options;
37
+ const baseBranch = options.baseBranch || 'main';
38
+ const secretsVault = `${repoName}-secrets`;
39
+ // A single redirect only: projen's built-in cross-platform task shell
40
+ // (dax) rejects a command with more than one redirect (e.g. combining
41
+ // `>/dev/null` with `2>&1`) with "Multiple redirects are currently not
42
+ // supported" — confirmed by dogfooding this construct on this very repo.
43
+ const swampInitStep = 'command -v swamp >/dev/null && swamp init --tool claude || true';
44
+ new SoftwareFactoryModels_1.SoftwareFactoryModels(project, {
45
+ repoName,
46
+ githubOwner: GITHUB_OWNER,
47
+ baseBranch,
48
+ });
49
+ new SoftwareFactoryArchitectureRules_1.SoftwareFactoryArchitectureRules(project);
50
+ new SoftwareFactoryAttestation_1.SoftwareFactoryAttestation(project, { repoName });
51
+ new SoftwareFactoryOpenSpecGates_1.SoftwareFactoryOpenSpecGates(project);
52
+ new SoftwareFactoryWorkflows_1.SoftwareFactoryWorkflows(project, { repoName, actionVersions });
53
+ project.addTask('validate:architecture', {
54
+ description: 'Run the architecture rule registry (architecture-rules/rules.json) against the repo',
55
+ exec: 'ts-node --project architecture-rules/tsconfig.json architecture-rules/check.ts',
56
+ });
57
+ project.addTask('openspec:check-tasks-complete', {
58
+ description: 'Fail unless every task in the named OpenSpec change is complete (usage: -- <change-slug>)',
59
+ exec: 'ts-node --project openspec-gates/tsconfig.json openspec-gates/check-tasks-complete.ts',
60
+ receiveArgs: true,
61
+ });
62
+ project.addTask('attestation:manifest', {
63
+ description: 'Print SHA256 checksums of the files a PR attestation is verified against (see attestation/manifest.ts)',
64
+ exec: 'ts-node --project attestation/tsconfig.json attestation/manifest.ts',
65
+ });
66
+ project.addTask('attestation:verify', {
67
+ description: 'Verify a PR\'s embedded attestation-manifest against the current checkout (usage: -- --body-file <path> --commit <sha>)',
68
+ exec: 'ts-node --project attestation/tsconfig.json attestation/verify.ts',
69
+ receiveArgs: true,
70
+ });
71
+ project.addTask('swamp:bootstrap', {
72
+ description: 'One-time setup: pull the software-factory/github extensions and create the secrets vault (swamp init itself already runs on every install)',
73
+ steps: [
74
+ { exec: 'swamp extension pull @swamp/software-factory' },
75
+ { exec: 'swamp extension pull @webframp/github' },
76
+ { exec: 'swamp extension pull @goodcraft/github' },
77
+ { exec: `swamp vault create local_encryption ${secretsVault}` },
78
+ {
79
+ exec: `echo "Next: swamp vault put ${secretsVault} GITHUB_TOKEN --refresh-from 'gh auth token'"`,
80
+ },
81
+ ],
82
+ });
83
+ // `swamp init` is safe to re-run (idempotent when already initialized),
84
+ // so every install keeps the repo initialized without a separate manual
85
+ // step — including on a fresh clone that hasn't run swamp:bootstrap yet.
86
+ project.package.installTask.exec(swampInitStep);
87
+ project.package.installCiTask.exec(swampInitStep);
88
+ // Mirrors the patterns `swamp init` itself would append to .gitignore.
89
+ // projen's IgnoreFile fully regenerates .gitignore from its own tracked
90
+ // entries on every synth, so anything `swamp init` appends out-of-band
91
+ // gets silently wiped by the next `npx projen` run (caught by CI's
92
+ // self-mutation check) unless it's also added here.
93
+ project.addGitIgnore('.swamp/');
94
+ project.addGitIgnore('.swamp-sources.yaml');
95
+ project.addGitIgnore('.claude/worktrees/');
96
+ project.addGitIgnore('.claude/settings.local.json');
97
+ project.addGitIgnore('.claude/scheduled_tasks.lock');
98
+ project.addGitIgnore('.claude/scheduled_tasks.json');
99
+ }
100
+ }
101
+ exports.SoftwareFactoryFiles = SoftwareFactoryFiles;
102
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU29mdHdhcmVGYWN0b3J5RmlsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvU29mdHdhcmVGYWN0b3J5RmlsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUNBLHlGQUFzRjtBQUN0Riw2RUFBMEU7QUFDMUUsbUVBQWdFO0FBQ2hFLGlGQUE4RTtBQUM5RSx5RUFBc0U7QUFHdEUsTUFBTSxZQUFZLEdBQUcsc0JBQXNCLENBQUM7QUF1QjVDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxNQUFhLG9CQUFvQjs7SUFDL0IsWUFBWSxPQUFvQixFQUFFLE9BQW9DO1FBQ3BFLE1BQU0sRUFBRSxRQUFRLEVBQUUsY0FBYyxFQUFFLEdBQUcsT0FBTyxDQUFDO1FBQzdDLE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxVQUFVLElBQUksTUFBTSxDQUFDO1FBQ2hELE1BQU0sWUFBWSxHQUFHLEdBQUcsUUFBUSxVQUFVLENBQUM7UUFDM0Msc0VBQXNFO1FBQ3RFLHNFQUFzRTtRQUN0RSx1RUFBdUU7UUFDdkUseUVBQXlFO1FBQ3pFLE1BQU0sYUFBYSxHQUFHLGlFQUFpRSxDQUFDO1FBRXhGLElBQUksNkNBQXFCLENBQUMsT0FBTyxFQUFFO1lBQ2pDLFFBQVE7WUFDUixXQUFXLEVBQUUsWUFBWTtZQUN6QixVQUFVO1NBQ1gsQ0FBQyxDQUFDO1FBRUgsSUFBSSxtRUFBZ0MsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUU5QyxJQUFJLHVEQUEwQixDQUFDLE9BQU8sRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFFdEQsSUFBSSwyREFBNEIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUUxQyxJQUFJLG1EQUF3QixDQUFDLE9BQU8sRUFBRSxFQUFFLFFBQVEsRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUFDO1FBRXBFLE9BQU8sQ0FBQyxPQUFPLENBQUMsdUJBQXVCLEVBQUU7WUFDdkMsV0FBVyxFQUFFLHFGQUFxRjtZQUNsRyxJQUFJLEVBQUUsZ0ZBQWdGO1NBQ3ZGLENBQUMsQ0FBQztRQUVILE9BQU8sQ0FBQyxPQUFPLENBQUMsK0JBQStCLEVBQUU7WUFDL0MsV0FBVyxFQUFFLDJGQUEyRjtZQUN4RyxJQUFJLEVBQUUsdUZBQXVGO1lBQzdGLFdBQVcsRUFBRSxJQUFJO1NBQ2xCLENBQUMsQ0FBQztRQUVILE9BQU8sQ0FBQyxPQUFPLENBQUMsc0JBQXNCLEVBQUU7WUFDdEMsV0FBVyxFQUFFLHdHQUF3RztZQUNySCxJQUFJLEVBQUUscUVBQXFFO1NBQzVFLENBQUMsQ0FBQztRQUVILE9BQU8sQ0FBQyxPQUFPLENBQUMsb0JBQW9CLEVBQUU7WUFDcEMsV0FBVyxFQUFFLHlIQUF5SDtZQUN0SSxJQUFJLEVBQUUsbUVBQW1FO1lBQ3pFLFdBQVcsRUFBRSxJQUFJO1NBQ2xCLENBQUMsQ0FBQztRQUVILE9BQU8sQ0FBQyxPQUFPLENBQUMsaUJBQWlCLEVBQUU7WUFDakMsV0FBVyxFQUFFLDRJQUE0STtZQUN6SixLQUFLLEVBQUU7Z0JBQ0wsRUFBRSxJQUFJLEVBQUUsOENBQThDLEVBQUU7Z0JBQ3hELEVBQUUsSUFBSSxFQUFFLHVDQUF1QyxFQUFFO2dCQUNqRCxFQUFFLElBQUksRUFBRSx3Q0FBd0MsRUFBRTtnQkFDbEQsRUFBRSxJQUFJLEVBQUUsdUNBQXVDLFlBQVksRUFBRSxFQUFFO2dCQUMvRDtvQkFDRSxJQUFJLEVBQUUsK0JBQStCLFlBQVksK0NBQStDO2lCQUNqRzthQUNGO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsd0VBQXdFO1FBQ3hFLHdFQUF3RTtRQUN4RSx5RUFBeUU7UUFDekUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ2hELE9BQU8sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUVsRCx1RUFBdUU7UUFDdkUsd0VBQXdFO1FBQ3hFLHVFQUF1RTtRQUN2RSxtRUFBbUU7UUFDbkUsb0RBQW9EO1FBQ3BELE9BQU8sQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDaEMsT0FBTyxDQUFDLFlBQVksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1FBQzVDLE9BQU8sQ0FBQyxZQUFZLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUMzQyxPQUFPLENBQUMsWUFBWSxDQUFDLDZCQUE2QixDQUFDLENBQUM7UUFDcEQsT0FBTyxDQUFDLFlBQVksQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO1FBQ3JELE9BQU8sQ0FBQyxZQUFZLENBQUMsOEJBQThCLENBQUMsQ0FBQztJQUN2RCxDQUFDOztBQTdFSCxvREE4RUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBOb2RlUHJvamVjdCB9IGZyb20gJ3Byb2plbi9saWIvamF2YXNjcmlwdCc7XG5pbXBvcnQgeyBTb2Z0d2FyZUZhY3RvcnlBcmNoaXRlY3R1cmVSdWxlcyB9IGZyb20gJy4vU29mdHdhcmVGYWN0b3J5QXJjaGl0ZWN0dXJlUnVsZXMnO1xuaW1wb3J0IHsgU29mdHdhcmVGYWN0b3J5QXR0ZXN0YXRpb24gfSBmcm9tICcuL1NvZnR3YXJlRmFjdG9yeUF0dGVzdGF0aW9uJztcbmltcG9ydCB7IFNvZnR3YXJlRmFjdG9yeU1vZGVscyB9IGZyb20gJy4vU29mdHdhcmVGYWN0b3J5TW9kZWxzJztcbmltcG9ydCB7IFNvZnR3YXJlRmFjdG9yeU9wZW5TcGVjR2F0ZXMgfSBmcm9tICcuL1NvZnR3YXJlRmFjdG9yeU9wZW5TcGVjR2F0ZXMnO1xuaW1wb3J0IHsgU29mdHdhcmVGYWN0b3J5V29ya2Zsb3dzIH0gZnJvbSAnLi9Tb2Z0d2FyZUZhY3RvcnlXb3JrZmxvd3MnO1xuaW1wb3J0IHsgV29ya2Zsb3dBY3Rpb25WZXJzaW9ucyB9IGZyb20gJy4vV29ya2Zsb3dBY3Rpb25WZXJzaW9ucyc7XG5cbmNvbnN0IEdJVEhVQl9PV05FUiA9ICdtYWNlZG9uLXRlY2hub2xvZ2llcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU29mdHdhcmVGYWN0b3J5RmlsZXNPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBiYXJlIHJlcG8gbmFtZSAoZS5nLiBgZXhwZW5zZS10cmFja2VyYCksIHVzZWQgdG8gZGVyaXZlIHRoZSBmYWN0b3J5J3NcbiAgICogbW9kZWwgbmFtZXMgKGA8cmVwb05hbWU+LWZhY3RvcnlgLCBgPHJlcG9OYW1lPi1pc3N1ZXNgLCBgPHJlcG9OYW1lPi1wcmAsXG4gICAqIGA8cmVwb05hbWU+LXNoZWxsKmApIGFuZCB2YXVsdCBuYW1lIChgPHJlcG9OYW1lPi1zZWNyZXRzYCkuXG4gICAqL1xuICByZWFkb25seSByZXBvTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgYnJhbmNoIHRoZSBmYWN0b3J5IG9wZW5zIHB1bGwgcmVxdWVzdHMgYWdhaW5zdC5cbiAgICpcbiAgICogQGRlZmF1bHQgJ21haW4nXG4gICAqL1xuICByZWFkb25seSBiYXNlQnJhbmNoPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBPdmVycmlkZXMgZm9yIHRoZSBwaW5uZWQgYWN0aW9uIHZlcnNpb25zIHVzZWQgYnkgYHZlcmlmeS1hdHRlc3RhdGlvbi55bWxgLlxuICAgKi9cbiAgcmVhZG9ubHkgYWN0aW9uVmVyc2lvbnM/OiBXb3JrZmxvd0FjdGlvblZlcnNpb25zO1xufVxuXG4vKipcbiAqIEJhY2twb3J0cyBleG1hbidzIHN3YW1wIFwic29mdHdhcmUgZmFjdG9yeVwiIHBhdHRlcm5cbiAqIChtYWNlZG9uLXRlY2hub2xvZ2llcy9leG1hbiMxMykgYXMgZ2VuZXJhdGVkIHNjYWZmb2xkaW5nOiBhXG4gKiBgQHN3YW1wL3NvZnR3YXJlLWZhY3RvcnlgIHN0YXRlIG1hY2hpbmUgdGhhdCBkcml2ZXMgYSBHaXRIdWIgaXNzdWUgZnJvbVxuICogaW50YWtlIHRocm91Z2ggYW4gb3BlbmVkIFBSLCBlbmZvcmNpbmcgT3BlblNwZWMgdXNhZ2UsIGFuIGFyY2hpdGVjdHVyZVxuICogcnVsZSByZWdpc3RyeSwgYW5kIGEgcHJlLVBSIHZlcmlmaWNhdGlvbiBnYXRlIHdob3NlIGF0dGVzdGF0aW9uIGlzXG4gKiByZS1jaGVja2VkIGF0IG1lcmdlIHRpbWUuXG4gKlxuICogV2hhdCBzd2FtcCBpdHNlbGYgd291bGQgZ2VuZXJhdGUgKGV4dGVuc2lvbiBkb2NzIHB1bGxlZCB2aWFcbiAqIGBzd2FtcCBleHRlbnNpb24gcHVsbGAsIGAuc3dhbXAueWFtbGAsIHRoZSB2YXVsdCwgYW5kIHRoZSBcInN3YW1wIG1hbmFnZWRcbiAqIHNlY3Rpb25cIiBpbiBDTEFVREUubWQpIGlzIGRlbGliZXJhdGVseSBOT1QgaGFuZC10ZW1wbGF0ZWQgaGVyZSDigJQgdGhvc2UgYXJlXG4gKiBwcm9kdWNlZCBieSB0aGUgcmVhbCBgc3dhbXBgIENMSS4gYHN3YW1wIGluaXRgIGlzIGlkZW1wb3RlbnQgKGEgbm8tb3AgaWZcbiAqIHRoZSByZXBvIGlzIGFscmVhZHkgaW5pdGlhbGl6ZWQpLCBzbyBpdCdzIHdpcmVkIGludG8gdGhlIHByb2plY3Qnc1xuICogYGluc3RhbGxgL2BpbnN0YWxsOmNpYCB0YXNrcyBhbmQgcnVucyBhdXRvbWF0aWNhbGx5IG9uIGV2ZXJ5IGluc3RhbGwsXG4gKiBndWFyZGVkIHNvIGl0J3MgYSBzaWxlbnQgbm8tb3Agb24gYSBtYWNoaW5lIHdpdGhvdXQgYHN3YW1wYCBvbiBQQVRIIChlLmcuXG4gKiBDSSkuIFRoZSBleHRlbnNpb24gcHVsbHMgYW5kIHZhdWx0IGNyZWF0aW9uIGFyZSBvbmUtdGltZSwgbm90IGlkZW1wb3RlbnRcbiAqIGluIGEgd2F5IHRoYXQncyBzYWZlIHRvIHJlcGVhdCBvbiBldmVyeSBpbnN0YWxsLCBzbyB0aGV5IHN0YXkgaW4gdGhlXG4gKiBgc3dhbXA6Ym9vdHN0cmFwYCB0YXNrIHRoaXMgY29uc3RydWN0IGFkZHMuIE9ubHkgZXhtYW4ncyBvd24gYXV0aG9yZWRcbiAqIGNvbmZpZyAodGhlIGZhY3RvcnkncyBzdGF0ZSBtYWNoaW5lLCB0aGUgYXJjaGl0ZWN0dXJlLXJ1bGUgZW5naW5lLCB0aGVcbiAqIGF0dGVzdGF0aW9uIG1lY2hhbmlzbSwgdGhlIE9wZW5TcGVjIHRhc2stY29tcGxldGlvbiBnYXRlLCBhbmQgdGhlIDMgc3dhbXBcbiAqIHdvcmtmbG93cyB0aGF0IHdpcmUgdGhlbSB0b2dldGhlcikgaXMgdGVtcGxhdGVkLlxuICovXG5leHBvcnQgY2xhc3MgU29mdHdhcmVGYWN0b3J5RmlsZXMge1xuICBjb25zdHJ1Y3Rvcihwcm9qZWN0OiBOb2RlUHJvamVjdCwgb3B0aW9uczogU29mdHdhcmVGYWN0b3J5RmlsZXNPcHRpb25zKSB7XG4gICAgY29uc3QgeyByZXBvTmFtZSwgYWN0aW9uVmVyc2lvbnMgfSA9IG9wdGlvbnM7XG4gICAgY29uc3QgYmFzZUJyYW5jaCA9IG9wdGlvbnMuYmFzZUJyYW5jaCB8fCAnbWFpbic7XG4gICAgY29uc3Qgc2VjcmV0c1ZhdWx0ID0gYCR7cmVwb05hbWV9LXNlY3JldHNgO1xuICAgIC8vIEEgc2luZ2xlIHJlZGlyZWN0IG9ubHk6IHByb2plbidzIGJ1aWx0LWluIGNyb3NzLXBsYXRmb3JtIHRhc2sgc2hlbGxcbiAgICAvLyAoZGF4KSByZWplY3RzIGEgY29tbWFuZCB3aXRoIG1vcmUgdGhhbiBvbmUgcmVkaXJlY3QgKGUuZy4gY29tYmluaW5nXG4gICAgLy8gYD4vZGV2L251bGxgIHdpdGggYDI+JjFgKSB3aXRoIFwiTXVsdGlwbGUgcmVkaXJlY3RzIGFyZSBjdXJyZW50bHkgbm90XG4gICAgLy8gc3VwcG9ydGVkXCIg4oCUIGNvbmZpcm1lZCBieSBkb2dmb29kaW5nIHRoaXMgY29uc3RydWN0IG9uIHRoaXMgdmVyeSByZXBvLlxuICAgIGNvbnN0IHN3YW1wSW5pdFN0ZXAgPSAnY29tbWFuZCAtdiBzd2FtcCA+L2Rldi9udWxsICYmIHN3YW1wIGluaXQgLS10b29sIGNsYXVkZSB8fCB0cnVlJztcblxuICAgIG5ldyBTb2Z0d2FyZUZhY3RvcnlNb2RlbHMocHJvamVjdCwge1xuICAgICAgcmVwb05hbWUsXG4gICAgICBnaXRodWJPd25lcjogR0lUSFVCX09XTkVSLFxuICAgICAgYmFzZUJyYW5jaCxcbiAgICB9KTtcblxuICAgIG5ldyBTb2Z0d2FyZUZhY3RvcnlBcmNoaXRlY3R1cmVSdWxlcyhwcm9qZWN0KTtcblxuICAgIG5ldyBTb2Z0d2FyZUZhY3RvcnlBdHRlc3RhdGlvbihwcm9qZWN0LCB7IHJlcG9OYW1lIH0pO1xuXG4gICAgbmV3IFNvZnR3YXJlRmFjdG9yeU9wZW5TcGVjR2F0ZXMocHJvamVjdCk7XG5cbiAgICBuZXcgU29mdHdhcmVGYWN0b3J5V29ya2Zsb3dzKHByb2plY3QsIHsgcmVwb05hbWUsIGFjdGlvblZlcnNpb25zIH0pO1xuXG4gICAgcHJvamVjdC5hZGRUYXNrKCd2YWxpZGF0ZTphcmNoaXRlY3R1cmUnLCB7XG4gICAgICBkZXNjcmlwdGlvbjogJ1J1biB0aGUgYXJjaGl0ZWN0dXJlIHJ1bGUgcmVnaXN0cnkgKGFyY2hpdGVjdHVyZS1ydWxlcy9ydWxlcy5qc29uKSBhZ2FpbnN0IHRoZSByZXBvJyxcbiAgICAgIGV4ZWM6ICd0cy1ub2RlIC0tcHJvamVjdCBhcmNoaXRlY3R1cmUtcnVsZXMvdHNjb25maWcuanNvbiBhcmNoaXRlY3R1cmUtcnVsZXMvY2hlY2sudHMnLFxuICAgIH0pO1xuXG4gICAgcHJvamVjdC5hZGRUYXNrKCdvcGVuc3BlYzpjaGVjay10YXNrcy1jb21wbGV0ZScsIHtcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmFpbCB1bmxlc3MgZXZlcnkgdGFzayBpbiB0aGUgbmFtZWQgT3BlblNwZWMgY2hhbmdlIGlzIGNvbXBsZXRlICh1c2FnZTogLS0gPGNoYW5nZS1zbHVnPiknLFxuICAgICAgZXhlYzogJ3RzLW5vZGUgLS1wcm9qZWN0IG9wZW5zcGVjLWdhdGVzL3RzY29uZmlnLmpzb24gb3BlbnNwZWMtZ2F0ZXMvY2hlY2stdGFza3MtY29tcGxldGUudHMnLFxuICAgICAgcmVjZWl2ZUFyZ3M6IHRydWUsXG4gICAgfSk7XG5cbiAgICBwcm9qZWN0LmFkZFRhc2soJ2F0dGVzdGF0aW9uOm1hbmlmZXN0Jywge1xuICAgICAgZGVzY3JpcHRpb246ICdQcmludCBTSEEyNTYgY2hlY2tzdW1zIG9mIHRoZSBmaWxlcyBhIFBSIGF0dGVzdGF0aW9uIGlzIHZlcmlmaWVkIGFnYWluc3QgKHNlZSBhdHRlc3RhdGlvbi9tYW5pZmVzdC50cyknLFxuICAgICAgZXhlYzogJ3RzLW5vZGUgLS1wcm9qZWN0IGF0dGVzdGF0aW9uL3RzY29uZmlnLmpzb24gYXR0ZXN0YXRpb24vbWFuaWZlc3QudHMnLFxuICAgIH0pO1xuXG4gICAgcHJvamVjdC5hZGRUYXNrKCdhdHRlc3RhdGlvbjp2ZXJpZnknLCB7XG4gICAgICBkZXNjcmlwdGlvbjogJ1ZlcmlmeSBhIFBSXFwncyBlbWJlZGRlZCBhdHRlc3RhdGlvbi1tYW5pZmVzdCBhZ2FpbnN0IHRoZSBjdXJyZW50IGNoZWNrb3V0ICh1c2FnZTogLS0gLS1ib2R5LWZpbGUgPHBhdGg+IC0tY29tbWl0IDxzaGE+KScsXG4gICAgICBleGVjOiAndHMtbm9kZSAtLXByb2plY3QgYXR0ZXN0YXRpb24vdHNjb25maWcuanNvbiBhdHRlc3RhdGlvbi92ZXJpZnkudHMnLFxuICAgICAgcmVjZWl2ZUFyZ3M6IHRydWUsXG4gICAgfSk7XG5cbiAgICBwcm9qZWN0LmFkZFRhc2soJ3N3YW1wOmJvb3RzdHJhcCcsIHtcbiAgICAgIGRlc2NyaXB0aW9uOiAnT25lLXRpbWUgc2V0dXA6IHB1bGwgdGhlIHNvZnR3YXJlLWZhY3RvcnkvZ2l0aHViIGV4dGVuc2lvbnMgYW5kIGNyZWF0ZSB0aGUgc2VjcmV0cyB2YXVsdCAoc3dhbXAgaW5pdCBpdHNlbGYgYWxyZWFkeSBydW5zIG9uIGV2ZXJ5IGluc3RhbGwpJyxcbiAgICAgIHN0ZXBzOiBbXG4gICAgICAgIHsgZXhlYzogJ3N3YW1wIGV4dGVuc2lvbiBwdWxsIEBzd2FtcC9zb2Z0d2FyZS1mYWN0b3J5JyB9LFxuICAgICAgICB7IGV4ZWM6ICdzd2FtcCBleHRlbnNpb24gcHVsbCBAd2ViZnJhbXAvZ2l0aHViJyB9LFxuICAgICAgICB7IGV4ZWM6ICdzd2FtcCBleHRlbnNpb24gcHVsbCBAZ29vZGNyYWZ0L2dpdGh1YicgfSxcbiAgICAgICAgeyBleGVjOiBgc3dhbXAgdmF1bHQgY3JlYXRlIGxvY2FsX2VuY3J5cHRpb24gJHtzZWNyZXRzVmF1bHR9YCB9LFxuICAgICAgICB7XG4gICAgICAgICAgZXhlYzogYGVjaG8gXCJOZXh0OiBzd2FtcCB2YXVsdCBwdXQgJHtzZWNyZXRzVmF1bHR9IEdJVEhVQl9UT0tFTiAtLXJlZnJlc2gtZnJvbSAnZ2ggYXV0aCB0b2tlbidcImAsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuXG4gICAgLy8gYHN3YW1wIGluaXRgIGlzIHNhZmUgdG8gcmUtcnVuIChpZGVtcG90ZW50IHdoZW4gYWxyZWFkeSBpbml0aWFsaXplZCksXG4gICAgLy8gc28gZXZlcnkgaW5zdGFsbCBrZWVwcyB0aGUgcmVwbyBpbml0aWFsaXplZCB3aXRob3V0IGEgc2VwYXJhdGUgbWFudWFsXG4gICAgLy8gc3RlcCDigJQgaW5jbHVkaW5nIG9uIGEgZnJlc2ggY2xvbmUgdGhhdCBoYXNuJ3QgcnVuIHN3YW1wOmJvb3RzdHJhcCB5ZXQuXG4gICAgcHJvamVjdC5wYWNrYWdlLmluc3RhbGxUYXNrLmV4ZWMoc3dhbXBJbml0U3RlcCk7XG4gICAgcHJvamVjdC5wYWNrYWdlLmluc3RhbGxDaVRhc2suZXhlYyhzd2FtcEluaXRTdGVwKTtcblxuICAgIC8vIE1pcnJvcnMgdGhlIHBhdHRlcm5zIGBzd2FtcCBpbml0YCBpdHNlbGYgd291bGQgYXBwZW5kIHRvIC5naXRpZ25vcmUuXG4gICAgLy8gcHJvamVuJ3MgSWdub3JlRmlsZSBmdWxseSByZWdlbmVyYXRlcyAuZ2l0aWdub3JlIGZyb20gaXRzIG93biB0cmFja2VkXG4gICAgLy8gZW50cmllcyBvbiBldmVyeSBzeW50aCwgc28gYW55dGhpbmcgYHN3YW1wIGluaXRgIGFwcGVuZHMgb3V0LW9mLWJhbmRcbiAgICAvLyBnZXRzIHNpbGVudGx5IHdpcGVkIGJ5IHRoZSBuZXh0IGBucHggcHJvamVuYCBydW4gKGNhdWdodCBieSBDSSdzXG4gICAgLy8gc2VsZi1tdXRhdGlvbiBjaGVjaykgdW5sZXNzIGl0J3MgYWxzbyBhZGRlZCBoZXJlLlxuICAgIHByb2plY3QuYWRkR2l0SWdub3JlKCcuc3dhbXAvJyk7XG4gICAgcHJvamVjdC5hZGRHaXRJZ25vcmUoJy5zd2FtcC1zb3VyY2VzLnlhbWwnKTtcbiAgICBwcm9qZWN0LmFkZEdpdElnbm9yZSgnLmNsYXVkZS93b3JrdHJlZXMvJyk7XG4gICAgcHJvamVjdC5hZGRHaXRJZ25vcmUoJy5jbGF1ZGUvc2V0dGluZ3MubG9jYWwuanNvbicpO1xuICAgIHByb2plY3QuYWRkR2l0SWdub3JlKCcuY2xhdWRlL3NjaGVkdWxlZF90YXNrcy5sb2NrJyk7XG4gICAgcHJvamVjdC5hZGRHaXRJZ25vcmUoJy5jbGF1ZGUvc2NoZWR1bGVkX3Rhc2tzLmpzb24nKTtcbiAgfVxufVxuIl19
@@ -0,0 +1,25 @@
1
+ import { NodeProject } from 'projen/lib/javascript';
2
+ export interface SoftwareFactoryModelsOptions {
3
+ /**
4
+ * The bare repo name (e.g. `expense-tracker`), used to derive model names
5
+ * like `<repoName>-factory`, `<repoName>-shell`, `<repoName>-secrets`.
6
+ */
7
+ readonly repoName: string;
8
+ /**
9
+ * The GitHub org the repo lives in.
10
+ */
11
+ readonly githubOwner: string;
12
+ /**
13
+ * The branch the factory opens pull requests against.
14
+ */
15
+ readonly baseBranch: string;
16
+ }
17
+ /**
18
+ * Seed swamp model instances wiring the `@swamp/software-factory` state
19
+ * machine to this repo's GitHub issues/PRs and shell steps. These are
20
+ * `SampleFile`s (written once, then owned by the team) since the factory's
21
+ * stages/gates are the kind of thing a team tunes for its own workflow.
22
+ */
23
+ export declare class SoftwareFactoryModels {
24
+ constructor(project: NodeProject, options: SoftwareFactoryModelsOptions);
25
+ }
@@ -0,0 +1,306 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SoftwareFactoryModels = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const projen_1 = require("projen");
6
+ /**
7
+ * Seed swamp model instances wiring the `@swamp/software-factory` state
8
+ * machine to this repo's GitHub issues/PRs and shell steps. These are
9
+ * `SampleFile`s (written once, then owned by the team) since the factory's
10
+ * stages/gates are the kind of thing a team tunes for its own workflow.
11
+ */
12
+ class SoftwareFactoryModels {
13
+ constructor(project, options) {
14
+ const { repoName, githubOwner, baseBranch } = options;
15
+ const repo = `${githubOwner}/${repoName}`;
16
+ const issuesModel = `${repoName}-issues`;
17
+ const prModel = `${repoName}-pr`;
18
+ const shellModel = `${repoName}-shell`;
19
+ const shellArchitectureModel = `${repoName}-shell-architecture`;
20
+ const shellManifestModel = `${repoName}-shell-manifest`;
21
+ const secretsVault = `${repoName}-secrets`;
22
+ const factoryModel = `${repoName}-factory`;
23
+ new projen_1.SampleFile(project, `models/@goodcraft/github/${prModel}.yaml`, {
24
+ contents: `type: '@goodcraft/github'
25
+ typeVersion: 2026.06.14.1
26
+ id: ${(0, crypto_1.randomUUID)()}
27
+ name: ${prModel}
28
+ version: 1
29
+ tags: {}
30
+ globalArguments:
31
+ token: '\${{ vault.get(${secretsVault}, GITHUB_TOKEN) }}'
32
+ owner: ${githubOwner}
33
+ methods: {}
34
+ `,
35
+ });
36
+ new projen_1.SampleFile(project, `models/@webframp/github/${issuesModel}.yaml`, {
37
+ contents: `type: '@webframp/github'
38
+ typeVersion: 2026.08.28.1
39
+ id: ${(0, crypto_1.randomUUID)()}
40
+ name: ${issuesModel}
41
+ version: 1
42
+ tags: {}
43
+ globalArguments: {}
44
+ methods: {}
45
+ `,
46
+ });
47
+ for (const name of [shellModel, shellArchitectureModel, shellManifestModel]) {
48
+ new projen_1.SampleFile(project, `models/command/shell/${name}.yaml`, {
49
+ contents: `type: command/shell
50
+ typeVersion: 2026.02.09.1
51
+ id: ${(0, crypto_1.randomUUID)()}
52
+ name: ${name}
53
+ version: 1
54
+ tags: {}
55
+ globalArguments: {}
56
+ methods: {}
57
+ `,
58
+ });
59
+ }
60
+ new projen_1.SampleFile(project, `models/@swamp/software-factory/${factoryModel}.yaml`, {
61
+ contents: `type: '@swamp/software-factory'
62
+ typeVersion: 2026.06.24.1
63
+ id: ${(0, crypto_1.randomUUID)()}
64
+ name: ${factoryModel}
65
+ version: 1
66
+ tags: {}
67
+ reports:
68
+ require:
69
+ - name: "@swamp/software-factory/work-item-summary"
70
+ methods: [summary]
71
+ globalArguments:
72
+ stages:
73
+ - id: intake
74
+ initial: true
75
+ description: >-
76
+ Fetch the GitHub issue for this work item (workItem is the bare
77
+ issue number) and record its context.
78
+ work:
79
+ mode: interactive
80
+ systemPrompt: >-
81
+ Fetch the GitHub issue numbered \${{ self.workItem }} for
82
+ ${repo} using the ${issuesModel} model
83
+ (list_issues, then swamp data query filtered by number — see the
84
+ ${issuesModel} data), and record the issue-context artifact.
85
+ artifacts:
86
+ - name: issue-context
87
+ schema:
88
+ type: object
89
+ required: [number, title, url]
90
+ properties:
91
+ number: { type: integer }
92
+ title: { type: string, minLength: 1 }
93
+ body: { type: string }
94
+ url: { type: string, minLength: 1 }
95
+ labels: { type: array, items: { type: string } }
96
+ transitions:
97
+ - name: submit
98
+ to: planning
99
+ gates:
100
+ - type: artifact-exists
101
+ config: { artifact: issue-context }
102
+
103
+ - id: planning
104
+ description: >-
105
+ Turn the issue into a real OpenSpec change (proposal, design,
106
+ specs, tasks) — OpenSpec's task list is the plan, not a
107
+ freeform artifact.
108
+ work:
109
+ mode: interactive
110
+ systemPrompt: >-
111
+ Using the recorded issue-context artifact, use the
112
+ openspec-propose skill to create a complete OpenSpec change
113
+ (proposal.md, design.md, specs with deltas, tasks.md) for this
114
+ work item under openspec/changes/<changeSlug>/ — do not write a
115
+ freeform plan instead of this. Then record the plan artifact
116
+ with the change's slug and a one-line summary.
117
+ artifacts:
118
+ - name: plan
119
+ schema:
120
+ type: object
121
+ required: [changeSlug, summary]
122
+ properties:
123
+ changeSlug: { type: string, minLength: 1 }
124
+ summary: { type: string, minLength: 1 }
125
+ transitions:
126
+ - name: submit
127
+ to: openspec-plan-verify
128
+ gates:
129
+ - type: artifact-exists
130
+ config: { artifact: plan }
131
+
132
+ - id: openspec-plan-verify
133
+ description: >-
134
+ Verify the OpenSpec change is real and well-formed (not just an
135
+ artifact claiming one exists) before implementation starts.
136
+ work:
137
+ mode: workflow
138
+ workflow:
139
+ name: openspec-plan-verify
140
+ inputs:
141
+ changeSlug: '\${{ data.latest(self.name, "artifact-plan").payload.changeSlug }}'
142
+ resultEvidence: plan-verify-run
143
+ transitions:
144
+ - name: pass
145
+ to: implementing
146
+ gates:
147
+ - type: workflow-succeeded
148
+ config: { workflow: openspec-plan-verify }
149
+ - name: fail
150
+ to: planning
151
+ gates:
152
+ - type: evidence-recorded
153
+ config: { name: plan-verify-run, requireField: { status: failed } }
154
+
155
+ - id: implementing
156
+ description: Implement the OpenSpec change's tasks on a branch.
157
+ work:
158
+ mode: interactive
159
+ systemPrompt: >-
160
+ Use the openspec-apply-change skill against the change recorded
161
+ in the plan artifact's changeSlug — work through its tasks.md
162
+ one task at a time, checking each off (\`- [ ]\` -> \`- [x]\`) as
163
+ you complete it, until every task is done. Commit the work on a
164
+ feature branch. Record the change-summary artifact and the
165
+ change-request evidence (branch name and head commit sha — no
166
+ PR yet, that happens after pre-PR verification passes).
167
+ artifacts:
168
+ - name: change-summary
169
+ schema:
170
+ type: object
171
+ required: [summary, headSha]
172
+ properties:
173
+ summary: { type: string, minLength: 1 }
174
+ headSha: { type: string, minLength: 7 }
175
+ evidence:
176
+ - name: change-request
177
+ schema:
178
+ type: object
179
+ required: [branch, headSha]
180
+ properties:
181
+ branch: { type: string, minLength: 1 }
182
+ headSha: { type: string, minLength: 7 }
183
+ url: { type: string }
184
+ transitions:
185
+ - name: submit
186
+ to: openspec-tasks-verify
187
+ gates:
188
+ - type: artifact-exists
189
+ config: { artifact: change-summary }
190
+ - type: evidence-recorded
191
+ config: { name: change-request }
192
+
193
+ - id: openspec-tasks-verify
194
+ description: >-
195
+ Verify every task in the OpenSpec change is actually checked off
196
+ before pre-PR verification runs.
197
+ work:
198
+ mode: workflow
199
+ workflow:
200
+ name: openspec-tasks-verify
201
+ inputs:
202
+ changeSlug: '\${{ data.latest(self.name, "artifact-plan").payload.changeSlug }}'
203
+ resultEvidence: tasks-verify-run
204
+ transitions:
205
+ - name: pass
206
+ to: pre-pr-verify
207
+ gates:
208
+ - type: workflow-succeeded
209
+ config: { workflow: openspec-tasks-verify }
210
+ - name: fail
211
+ to: implementing
212
+ gates:
213
+ - type: evidence-recorded
214
+ config: { name: tasks-verify-run, requireField: { status: failed } }
215
+
216
+ - id: pre-pr-verify
217
+ description: >-
218
+ Pre-PR verification: build/synth/test/lint plus the architecture
219
+ rule registry, run before the PR is opened rather than relying on
220
+ CI after the fact.
221
+ work:
222
+ mode: workflow
223
+ workflow:
224
+ name: pre-pr-verify
225
+ inputs:
226
+ commit: '\${{ data.latest(self.name, "evidence-change-request").payload.headSha }}'
227
+ branch: '\${{ data.latest(self.name, "evidence-change-request").payload.branch }}'
228
+ resultEvidence: verify-run
229
+ transitions:
230
+ - name: pass
231
+ to: open-pr
232
+ gates:
233
+ - type: workflow-succeeded
234
+ config: { workflow: pre-pr-verify }
235
+ - name: fail
236
+ to: implementing
237
+ gates:
238
+ - type: evidence-recorded
239
+ config: { name: verify-run, requireField: { status: failed } }
240
+
241
+ - id: open-pr
242
+ description: Open the pull request now that pre-PR verification has passed.
243
+ work:
244
+ mode: interactive
245
+ systemPrompt: >-
246
+ Before opening the PR, fetch the real pre-pr-verify attestation
247
+ with \`swamp data get --workflow pre-pr-verify
248
+ report-swamp-verification-attestation --json\` and include its
249
+ \`content\` verbatim (as a markdown block, e.g. under a "Pre-PR
250
+ verification" heading) in the PR body — never just assert in
251
+ prose that checks passed. Also fetch this same run's manifest step
252
+ output (\`swamp data query 'modelName == "${shellManifestModel}" &&
253
+ name == "result"' --select attributes.stdout --json\`, take the
254
+ latest) and append it to the PR body as
255
+ \`<!-- attestation-manifest {"commit": "<headSha>", "status":
256
+ "succeeded", ...the manifest step's JSON, spread in...} -->\` — an
257
+ HTML comment so it's invisible when rendered but still present in
258
+ the raw body text verify-attestation.yml reads via the GitHub API.
259
+ Also fetch the plan artifact's changeSlug and include an explicit
260
+ "OpenSpec change" line in the PR body naming it and its path
261
+ (\`openspec/changes/<changeSlug>/\`) — every PR the factory opens
262
+ must call out which OpenSpec change(s) drove the session, not
263
+ just imply it. If planning cycled through more than one change
264
+ (a rework loop produced a new changeSlug), list every distinct
265
+ changeSlug recorded across the run's plan artifact versions, not
266
+ only the latest. Then call ${prModel}'s openPr method
267
+ (repo=${repo}, head=<the branch recorded in
268
+ change-request evidence>, base=${baseBranch}, dryRun=false), with
269
+ title/body referencing the intake stage's issue number, the
270
+ OpenSpec change(s), the attestation block, and the manifest
271
+ comment, then record the pr-opened evidence with the returned PR
272
+ url and number.
273
+ evidence:
274
+ - name: pr-opened
275
+ schema:
276
+ type: object
277
+ required: [url, number]
278
+ properties:
279
+ url: { type: string, minLength: 1 }
280
+ number: { type: integer }
281
+ transitions:
282
+ - name: submit
283
+ to: done
284
+ gates:
285
+ - type: evidence-recorded
286
+ config: { name: pr-opened }
287
+
288
+ - id: done
289
+ terminal: true
290
+
291
+ - id: aborted
292
+ terminal: true
293
+
294
+ globalTransitions:
295
+ - name: abort
296
+ to: aborted
297
+ gates:
298
+ - type: human-approval
299
+ config: { id: abort-confirmation }
300
+ methods: {}
301
+ `,
302
+ });
303
+ }
304
+ }
305
+ exports.SoftwareFactoryModels = SoftwareFactoryModels;
306
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU29mdHdhcmVGYWN0b3J5TW9kZWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1NvZnR3YXJlRmFjdG9yeU1vZGVscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxtQ0FBb0M7QUFDcEMsbUNBQW9DO0FBcUJwQzs7Ozs7R0FLRztBQUNILE1BQWEscUJBQXFCO0lBQ2hDLFlBQVksT0FBb0IsRUFBRSxPQUFxQztRQUNyRSxNQUFNLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsR0FBRyxPQUFPLENBQUM7UUFDdEQsTUFBTSxJQUFJLEdBQUcsR0FBRyxXQUFXLElBQUksUUFBUSxFQUFFLENBQUM7UUFDMUMsTUFBTSxXQUFXLEdBQUcsR0FBRyxRQUFRLFNBQVMsQ0FBQztRQUN6QyxNQUFNLE9BQU8sR0FBRyxHQUFHLFFBQVEsS0FBSyxDQUFDO1FBQ2pDLE1BQU0sVUFBVSxHQUFHLEdBQUcsUUFBUSxRQUFRLENBQUM7UUFDdkMsTUFBTSxzQkFBc0IsR0FBRyxHQUFHLFFBQVEscUJBQXFCLENBQUM7UUFDaEUsTUFBTSxrQkFBa0IsR0FBRyxHQUFHLFFBQVEsaUJBQWlCLENBQUM7UUFDeEQsTUFBTSxZQUFZLEdBQUcsR0FBRyxRQUFRLFVBQVUsQ0FBQztRQUMzQyxNQUFNLFlBQVksR0FBRyxHQUFHLFFBQVEsVUFBVSxDQUFDO1FBRTNDLElBQUksbUJBQVUsQ0FBQyxPQUFPLEVBQUUsNEJBQTRCLE9BQU8sT0FBTyxFQUFFO1lBQ2xFLFFBQVEsRUFBRTs7TUFFVixJQUFBLG1CQUFVLEdBQUU7UUFDVixPQUFPOzs7OzJCQUlZLFlBQVk7V0FDNUIsV0FBVzs7Q0FFckI7U0FDSSxDQUFDLENBQUM7UUFFSCxJQUFJLG1CQUFVLENBQUMsT0FBTyxFQUFFLDJCQUEyQixXQUFXLE9BQU8sRUFBRTtZQUNyRSxRQUFRLEVBQUU7O01BRVYsSUFBQSxtQkFBVSxHQUFFO1FBQ1YsV0FBVzs7Ozs7Q0FLbEI7U0FDSSxDQUFDLENBQUM7UUFFSCxLQUFLLE1BQU0sSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFLHNCQUFzQixFQUFFLGtCQUFrQixDQUFDLEVBQUUsQ0FBQztZQUM1RSxJQUFJLG1CQUFVLENBQUMsT0FBTyxFQUFFLHdCQUF3QixJQUFJLE9BQU8sRUFBRTtnQkFDM0QsUUFBUSxFQUFFOztNQUVaLElBQUEsbUJBQVUsR0FBRTtRQUNWLElBQUk7Ozs7O0NBS1g7YUFDTSxDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsSUFBSSxtQkFBVSxDQUFDLE9BQU8sRUFBRSxrQ0FBa0MsWUFBWSxPQUFPLEVBQUU7WUFDN0UsUUFBUSxFQUFFOztNQUVWLElBQUEsbUJBQVUsR0FBRTtRQUNWLFlBQVk7Ozs7Ozs7Ozs7Ozs7Ozs7OztZQWtCUixJQUFJLGNBQWMsV0FBVzs7WUFFN0IsV0FBVzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O3NEQXdLK0Isa0JBQWtCOzs7Ozs7Ozs7Ozs7Ozt1Q0FjakMsT0FBTztrQkFDNUIsSUFBSTsyQ0FDcUIsVUFBVTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0NBaUNwRDtTQUNJLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQXhTRCxzREF3U0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyByYW5kb21VVUlEIH0gZnJvbSAnY3J5cHRvJztcbmltcG9ydCB7IFNhbXBsZUZpbGUgfSBmcm9tICdwcm9qZW4nO1xuaW1wb3J0IHsgTm9kZVByb2plY3QgfSBmcm9tICdwcm9qZW4vbGliL2phdmFzY3JpcHQnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFNvZnR3YXJlRmFjdG9yeU1vZGVsc09wdGlvbnMge1xuICAvKipcbiAgICogVGhlIGJhcmUgcmVwbyBuYW1lIChlLmcuIGBleHBlbnNlLXRyYWNrZXJgKSwgdXNlZCB0byBkZXJpdmUgbW9kZWwgbmFtZXNcbiAgICogbGlrZSBgPHJlcG9OYW1lPi1mYWN0b3J5YCwgYDxyZXBvTmFtZT4tc2hlbGxgLCBgPHJlcG9OYW1lPi1zZWNyZXRzYC5cbiAgICovXG4gIHJlYWRvbmx5IHJlcG9OYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBHaXRIdWIgb3JnIHRoZSByZXBvIGxpdmVzIGluLlxuICAgKi9cbiAgcmVhZG9ubHkgZ2l0aHViT3duZXI6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGJyYW5jaCB0aGUgZmFjdG9yeSBvcGVucyBwdWxsIHJlcXVlc3RzIGFnYWluc3QuXG4gICAqL1xuICByZWFkb25seSBiYXNlQnJhbmNoOiBzdHJpbmc7XG59XG5cbi8qKlxuICogU2VlZCBzd2FtcCBtb2RlbCBpbnN0YW5jZXMgd2lyaW5nIHRoZSBgQHN3YW1wL3NvZnR3YXJlLWZhY3RvcnlgIHN0YXRlXG4gKiBtYWNoaW5lIHRvIHRoaXMgcmVwbydzIEdpdEh1YiBpc3N1ZXMvUFJzIGFuZCBzaGVsbCBzdGVwcy4gVGhlc2UgYXJlXG4gKiBgU2FtcGxlRmlsZWBzICh3cml0dGVuIG9uY2UsIHRoZW4gb3duZWQgYnkgdGhlIHRlYW0pIHNpbmNlIHRoZSBmYWN0b3J5J3NcbiAqIHN0YWdlcy9nYXRlcyBhcmUgdGhlIGtpbmQgb2YgdGhpbmcgYSB0ZWFtIHR1bmVzIGZvciBpdHMgb3duIHdvcmtmbG93LlxuICovXG5leHBvcnQgY2xhc3MgU29mdHdhcmVGYWN0b3J5TW9kZWxzIHtcbiAgY29uc3RydWN0b3IocHJvamVjdDogTm9kZVByb2plY3QsIG9wdGlvbnM6IFNvZnR3YXJlRmFjdG9yeU1vZGVsc09wdGlvbnMpIHtcbiAgICBjb25zdCB7IHJlcG9OYW1lLCBnaXRodWJPd25lciwgYmFzZUJyYW5jaCB9ID0gb3B0aW9ucztcbiAgICBjb25zdCByZXBvID0gYCR7Z2l0aHViT3duZXJ9LyR7cmVwb05hbWV9YDtcbiAgICBjb25zdCBpc3N1ZXNNb2RlbCA9IGAke3JlcG9OYW1lfS1pc3N1ZXNgO1xuICAgIGNvbnN0IHByTW9kZWwgPSBgJHtyZXBvTmFtZX0tcHJgO1xuICAgIGNvbnN0IHNoZWxsTW9kZWwgPSBgJHtyZXBvTmFtZX0tc2hlbGxgO1xuICAgIGNvbnN0IHNoZWxsQXJjaGl0ZWN0dXJlTW9kZWwgPSBgJHtyZXBvTmFtZX0tc2hlbGwtYXJjaGl0ZWN0dXJlYDtcbiAgICBjb25zdCBzaGVsbE1hbmlmZXN0TW9kZWwgPSBgJHtyZXBvTmFtZX0tc2hlbGwtbWFuaWZlc3RgO1xuICAgIGNvbnN0IHNlY3JldHNWYXVsdCA9IGAke3JlcG9OYW1lfS1zZWNyZXRzYDtcbiAgICBjb25zdCBmYWN0b3J5TW9kZWwgPSBgJHtyZXBvTmFtZX0tZmFjdG9yeWA7XG5cbiAgICBuZXcgU2FtcGxlRmlsZShwcm9qZWN0LCBgbW9kZWxzL0Bnb29kY3JhZnQvZ2l0aHViLyR7cHJNb2RlbH0ueWFtbGAsIHtcbiAgICAgIGNvbnRlbnRzOiBgdHlwZTogJ0Bnb29kY3JhZnQvZ2l0aHViJ1xudHlwZVZlcnNpb246IDIwMjYuMDYuMTQuMVxuaWQ6ICR7cmFuZG9tVVVJRCgpfVxubmFtZTogJHtwck1vZGVsfVxudmVyc2lvbjogMVxudGFnczoge31cbmdsb2JhbEFyZ3VtZW50czpcbiAgdG9rZW46ICdcXCR7eyB2YXVsdC5nZXQoJHtzZWNyZXRzVmF1bHR9LCBHSVRIVUJfVE9LRU4pIH19J1xuICBvd25lcjogJHtnaXRodWJPd25lcn1cbm1ldGhvZHM6IHt9XG5gLFxuICAgIH0pO1xuXG4gICAgbmV3IFNhbXBsZUZpbGUocHJvamVjdCwgYG1vZGVscy9Ad2ViZnJhbXAvZ2l0aHViLyR7aXNzdWVzTW9kZWx9LnlhbWxgLCB7XG4gICAgICBjb250ZW50czogYHR5cGU6ICdAd2ViZnJhbXAvZ2l0aHViJ1xudHlwZVZlcnNpb246IDIwMjYuMDguMjguMVxuaWQ6ICR7cmFuZG9tVVVJRCgpfVxubmFtZTogJHtpc3N1ZXNNb2RlbH1cbnZlcnNpb246IDFcbnRhZ3M6IHt9XG5nbG9iYWxBcmd1bWVudHM6IHt9XG5tZXRob2RzOiB7fVxuYCxcbiAgICB9KTtcblxuICAgIGZvciAoY29uc3QgbmFtZSBvZiBbc2hlbGxNb2RlbCwgc2hlbGxBcmNoaXRlY3R1cmVNb2RlbCwgc2hlbGxNYW5pZmVzdE1vZGVsXSkge1xuICAgICAgbmV3IFNhbXBsZUZpbGUocHJvamVjdCwgYG1vZGVscy9jb21tYW5kL3NoZWxsLyR7bmFtZX0ueWFtbGAsIHtcbiAgICAgICAgY29udGVudHM6IGB0eXBlOiBjb21tYW5kL3NoZWxsXG50eXBlVmVyc2lvbjogMjAyNi4wMi4wOS4xXG5pZDogJHtyYW5kb21VVUlEKCl9XG5uYW1lOiAke25hbWV9XG52ZXJzaW9uOiAxXG50YWdzOiB7fVxuZ2xvYmFsQXJndW1lbnRzOiB7fVxubWV0aG9kczoge31cbmAsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBuZXcgU2FtcGxlRmlsZShwcm9qZWN0LCBgbW9kZWxzL0Bzd2FtcC9zb2Z0d2FyZS1mYWN0b3J5LyR7ZmFjdG9yeU1vZGVsfS55YW1sYCwge1xuICAgICAgY29udGVudHM6IGB0eXBlOiAnQHN3YW1wL3NvZnR3YXJlLWZhY3RvcnknXG50eXBlVmVyc2lvbjogMjAyNi4wNi4yNC4xXG5pZDogJHtyYW5kb21VVUlEKCl9XG5uYW1lOiAke2ZhY3RvcnlNb2RlbH1cbnZlcnNpb246IDFcbnRhZ3M6IHt9XG5yZXBvcnRzOlxuICByZXF1aXJlOlxuICAgIC0gbmFtZTogXCJAc3dhbXAvc29mdHdhcmUtZmFjdG9yeS93b3JrLWl0ZW0tc3VtbWFyeVwiXG4gICAgICBtZXRob2RzOiBbc3VtbWFyeV1cbmdsb2JhbEFyZ3VtZW50czpcbiAgc3RhZ2VzOlxuICAgIC0gaWQ6IGludGFrZVxuICAgICAgaW5pdGlhbDogdHJ1ZVxuICAgICAgZGVzY3JpcHRpb246ID4tXG4gICAgICAgIEZldGNoIHRoZSBHaXRIdWIgaXNzdWUgZm9yIHRoaXMgd29yayBpdGVtICh3b3JrSXRlbSBpcyB0aGUgYmFyZVxuICAgICAgICBpc3N1ZSBudW1iZXIpIGFuZCByZWNvcmQgaXRzIGNvbnRleHQuXG4gICAgICB3b3JrOlxuICAgICAgICBtb2RlOiBpbnRlcmFjdGl2ZVxuICAgICAgICBzeXN0ZW1Qcm9tcHQ6ID4tXG4gICAgICAgICAgRmV0Y2ggdGhlIEdpdEh1YiBpc3N1ZSBudW1iZXJlZCBcXCR7eyBzZWxmLndvcmtJdGVtIH19IGZvclxuICAgICAgICAgICR7cmVwb30gdXNpbmcgdGhlICR7aXNzdWVzTW9kZWx9IG1vZGVsXG4gICAgICAgICAgKGxpc3RfaXNzdWVzLCB0aGVuIHN3YW1wIGRhdGEgcXVlcnkgZmlsdGVyZWQgYnkgbnVtYmVyIOKAlCBzZWUgdGhlXG4gICAgICAgICAgJHtpc3N1ZXNNb2RlbH0gZGF0YSksIGFuZCByZWNvcmQgdGhlIGlzc3VlLWNvbnRleHQgYXJ0aWZhY3QuXG4gICAgICBhcnRpZmFjdHM6XG4gICAgICAgIC0gbmFtZTogaXNzdWUtY29udGV4dFxuICAgICAgICAgIHNjaGVtYTpcbiAgICAgICAgICAgIHR5cGU6IG9iamVjdFxuICAgICAgICAgICAgcmVxdWlyZWQ6IFtudW1iZXIsIHRpdGxlLCB1cmxdXG4gICAgICAgICAgICBwcm9wZXJ0aWVzOlxuICAgICAgICAgICAgICBudW1iZXI6IHsgdHlwZTogaW50ZWdlciB9XG4gICAgICAgICAgICAgIHRpdGxlOiB7IHR5cGU6IHN0cmluZywgbWluTGVuZ3RoOiAxIH1cbiAgICAgICAgICAgICAgYm9keTogeyB0eXBlOiBzdHJpbmcgfVxuICAgICAgICAgICAgICB1cmw6IHsgdHlwZTogc3RyaW5nLCBtaW5MZW5ndGg6IDEgfVxuICAgICAgICAgICAgICBsYWJlbHM6IHsgdHlwZTogYXJyYXksIGl0ZW1zOiB7IHR5cGU6IHN0cmluZyB9IH1cbiAgICAgIHRyYW5zaXRpb25zOlxuICAgICAgICAtIG5hbWU6IHN1Ym1pdFxuICAgICAgICAgIHRvOiBwbGFubmluZ1xuICAgICAgICAgIGdhdGVzOlxuICAgICAgICAgICAgLSB0eXBlOiBhcnRpZmFjdC1leGlzdHNcbiAgICAgICAgICAgICAgY29uZmlnOiB7IGFydGlmYWN0OiBpc3N1ZS1jb250ZXh0IH1cblxuICAgIC0gaWQ6IHBsYW5uaW5nXG4gICAgICBkZXNjcmlwdGlvbjogPi1cbiAgICAgICAgVHVybiB0aGUgaXNzdWUgaW50byBhIHJlYWwgT3BlblNwZWMgY2hhbmdlIChwcm9wb3NhbCwgZGVzaWduLFxuICAgICAgICBzcGVjcywgdGFza3MpIOKAlCBPcGVuU3BlYydzIHRhc2sgbGlzdCBpcyB0aGUgcGxhbiwgbm90IGFcbiAgICAgICAgZnJlZWZvcm0gYXJ0aWZhY3QuXG4gICAgICB3b3JrOlxuICAgICAgICBtb2RlOiBpbnRlcmFjdGl2ZVxuICAgICAgICBzeXN0ZW1Qcm9tcHQ6ID4tXG4gICAgICAgICAgVXNpbmcgdGhlIHJlY29yZGVkIGlzc3VlLWNvbnRleHQgYXJ0aWZhY3QsIHVzZSB0aGVcbiAgICAgICAgICBvcGVuc3BlYy1wcm9wb3NlIHNraWxsIHRvIGNyZWF0ZSBhIGNvbXBsZXRlIE9wZW5TcGVjIGNoYW5nZVxuICAgICAgICAgIChwcm9wb3NhbC5tZCwgZGVzaWduLm1kLCBzcGVjcyB3aXRoIGRlbHRhcywgdGFza3MubWQpIGZvciB0aGlzXG4gICAgICAgICAgd29yayBpdGVtIHVuZGVyIG9wZW5zcGVjL2NoYW5nZXMvPGNoYW5nZVNsdWc+LyDigJQgZG8gbm90IHdyaXRlIGFcbiAgICAgICAgICBmcmVlZm9ybSBwbGFuIGluc3RlYWQgb2YgdGhpcy4gVGhlbiByZWNvcmQgdGhlIHBsYW4gYXJ0aWZhY3RcbiAgICAgICAgICB3aXRoIHRoZSBjaGFuZ2UncyBzbHVnIGFuZCBhIG9uZS1saW5lIHN1bW1hcnkuXG4gICAgICBhcnRpZmFjdHM6XG4gICAgICAgIC0gbmFtZTogcGxhblxuICAgICAgICAgIHNjaGVtYTpcbiAgICAgICAgICAgIHR5cGU6IG9iamVjdFxuICAgICAgICAgICAgcmVxdWlyZWQ6IFtjaGFuZ2VTbHVnLCBzdW1tYXJ5XVxuICAgICAgICAgICAgcHJvcGVydGllczpcbiAgICAgICAgICAgICAgY2hhbmdlU2x1ZzogeyB0eXBlOiBzdHJpbmcsIG1pbkxlbmd0aDogMSB9XG4gICAgICAgICAgICAgIHN1bW1hcnk6IHsgdHlwZTogc3RyaW5nLCBtaW5MZW5ndGg6IDEgfVxuICAgICAgdHJhbnNpdGlvbnM6XG4gICAgICAgIC0gbmFtZTogc3VibWl0XG4gICAgICAgICAgdG86IG9wZW5zcGVjLXBsYW4tdmVyaWZ5XG4gICAgICAgICAgZ2F0ZXM6XG4gICAgICAgICAgICAtIHR5cGU6IGFydGlmYWN0LWV4aXN0c1xuICAgICAgICAgICAgICBjb25maWc6IHsgYXJ0aWZhY3Q6IHBsYW4gfVxuXG4gICAgLSBpZDogb3BlbnNwZWMtcGxhbi12ZXJpZnlcbiAgICAgIGRlc2NyaXB0aW9uOiA+LVxuICAgICAgICBWZXJpZnkgdGhlIE9wZW5TcGVjIGNoYW5nZSBpcyByZWFsIGFuZCB3ZWxsLWZvcm1lZCAobm90IGp1c3QgYW5cbiAgICAgICAgYXJ0aWZhY3QgY2xhaW1pbmcgb25lIGV4aXN0cykgYmVmb3JlIGltcGxlbWVudGF0aW9uIHN0YXJ0cy5cbiAgICAgIHdvcms6XG4gICAgICAgIG1vZGU6IHdvcmtmbG93XG4gICAgICAgIHdvcmtmbG93OlxuICAgICAgICAgIG5hbWU6IG9wZW5zcGVjLXBsYW4tdmVyaWZ5XG4gICAgICAgICAgaW5wdXRzOlxuICAgICAgICAgICAgY2hhbmdlU2x1ZzogJ1xcJHt7IGRhdGEubGF0ZXN0KHNlbGYubmFtZSwgXCJhcnRpZmFjdC1wbGFuXCIpLnBheWxvYWQuY2hhbmdlU2x1ZyB9fSdcbiAgICAgICAgcmVzdWx0RXZpZGVuY2U6IHBsYW4tdmVyaWZ5LXJ1blxuICAgICAgdHJhbnNpdGlvbnM6XG4gICAgICAgIC0gbmFtZTogcGFzc1xuICAgICAgICAgIHRvOiBpbXBsZW1lbnRpbmdcbiAgICAgICAgICBnYXRlczpcbiAgICAgICAgICAgIC0gdHlwZTogd29ya2Zsb3ctc3VjY2VlZGVkXG4gICAgICAgICAgICAgIGNvbmZpZzogeyB3b3JrZmxvdzogb3BlbnNwZWMtcGxhbi12ZXJpZnkgfVxuICAgICAgICAtIG5hbWU6IGZhaWxcbiAgICAgICAgICB0bzogcGxhbm5pbmdcbiAgICAgICAgICBnYXRlczpcbiAgICAgICAgICAgIC0gdHlwZTogZXZpZGVuY2UtcmVjb3JkZWRcbiAgICAgICAgICAgICAgY29uZmlnOiB7IG5hbWU6IHBsYW4tdmVyaWZ5LXJ1biwgcmVxdWlyZUZpZWxkOiB7IHN0YXR1czogZmFpbGVkIH0gfVxuXG4gICAgLSBpZDogaW1wbGVtZW50aW5nXG4gICAgICBkZXNjcmlwdGlvbjogSW1wbGVtZW50IHRoZSBPcGVuU3BlYyBjaGFuZ2UncyB0YXNrcyBvbiBhIGJyYW5jaC5cbiAgICAgIHdvcms6XG4gICAgICAgIG1vZGU6IGludGVyYWN0aXZlXG4gICAgICAgIHN5c3RlbVByb21wdDogPi1cbiAgICAgICAgICBVc2UgdGhlIG9wZW5zcGVjLWFwcGx5LWNoYW5nZSBza2lsbCBhZ2FpbnN0IHRoZSBjaGFuZ2UgcmVjb3JkZWRcbiAgICAgICAgICBpbiB0aGUgcGxhbiBhcnRpZmFjdCdzIGNoYW5nZVNsdWcg4oCUIHdvcmsgdGhyb3VnaCBpdHMgdGFza3MubWRcbiAgICAgICAgICBvbmUgdGFzayBhdCBhIHRpbWUsIGNoZWNraW5nIGVhY2ggb2ZmIChcXGAtIFsgXVxcYCAtPiBcXGAtIFt4XVxcYCkgYXNcbiAgICAgICAgICB5b3UgY29tcGxldGUgaXQsIHVudGlsIGV2ZXJ5IHRhc2sgaXMgZG9uZS4gQ29tbWl0IHRoZSB3b3JrIG9uIGFcbiAgICAgICAgICBmZWF0dXJlIGJyYW5jaC4gUmVjb3JkIHRoZSBjaGFuZ2Utc3VtbWFyeSBhcnRpZmFjdCBhbmQgdGhlXG4gICAgICAgICAgY2hhbmdlLXJlcXVlc3QgZXZpZGVuY2UgKGJyYW5jaCBuYW1lIGFuZCBoZWFkIGNvbW1pdCBzaGEg4oCUIG5vXG4gICAgICAgICAgUFIgeWV0LCB0aGF0IGhhcHBlbnMgYWZ0ZXIgcHJlLVBSIHZlcmlmaWNhdGlvbiBwYXNzZXMpLlxuICAgICAgYXJ0aWZhY3RzOlxuICAgICAgICAtIG5hbWU6IGNoYW5nZS1zdW1tYXJ5XG4gICAgICAgICAgc2NoZW1hOlxuICAgICAgICAgICAgdHlwZTogb2JqZWN0XG4gICAgICAgICAgICByZXF1aXJlZDogW3N1bW1hcnksIGhlYWRTaGFdXG4gICAgICAgICAgICBwcm9wZXJ0aWVzOlxuICAgICAgICAgICAgICBzdW1tYXJ5OiB7IHR5cGU6IHN0cmluZywgbWluTGVuZ3RoOiAxIH1cbiAgICAgICAgICAgICAgaGVhZFNoYTogeyB0eXBlOiBzdHJpbmcsIG1pbkxlbmd0aDogNyB9XG4gICAgICBldmlkZW5jZTpcbiAgICAgICAgLSBuYW1lOiBjaGFuZ2UtcmVxdWVzdFxuICAgICAgICAgIHNjaGVtYTpcbiAgICAgICAgICAgIHR5cGU6IG9iamVjdFxuICAgICAgICAgICAgcmVxdWlyZWQ6IFticmFuY2gsIGhlYWRTaGFdXG4gICAgICAgICAgICBwcm9wZXJ0aWVzOlxuICAgICAgICAgICAgICBicmFuY2g6IHsgdHlwZTogc3RyaW5nLCBtaW5MZW5ndGg6IDEgfVxuICAgICAgICAgICAgICBoZWFkU2hhOiB7IHR5cGU6IHN0cmluZywgbWluTGVuZ3RoOiA3IH1cbiAgICAgICAgICAgICAgdXJsOiB7IHR5cGU6IHN0cmluZyB9XG4gICAgICB0cmFuc2l0aW9uczpcbiAgICAgICAgLSBuYW1lOiBzdWJtaXRcbiAgICAgICAgICB0bzogb3BlbnNwZWMtdGFza3MtdmVyaWZ5XG4gICAgICAgICAgZ2F0ZXM6XG4gICAgICAgICAgICAtIHR5cGU6IGFydGlmYWN0LWV4aXN0c1xuICAgICAgICAgICAgICBjb25maWc6IHsgYXJ0aWZhY3Q6IGNoYW5nZS1zdW1tYXJ5IH1cbiAgICAgICAgICAgIC0gdHlwZTogZXZpZGVuY2UtcmVjb3JkZWRcbiAgICAgICAgICAgICAgY29uZmlnOiB7IG5hbWU6IGNoYW5nZS1yZXF1ZXN0IH1cblxuICAgIC0gaWQ6IG9wZW5zcGVjLXRhc2tzLXZlcmlmeVxuICAgICAgZGVzY3JpcHRpb246ID4tXG4gICAgICAgIFZlcmlmeSBldmVyeSB0YXNrIGluIHRoZSBPcGVuU3BlYyBjaGFuZ2UgaXMgYWN0dWFsbHkgY2hlY2tlZCBvZmZcbiAgICAgICAgYmVmb3JlIHByZS1QUiB2ZXJpZmljYXRpb24gcnVucy5cbiAgICAgIHdvcms6XG4gICAgICAgIG1vZGU6IHdvcmtmbG93XG4gICAgICAgIHdvcmtmbG93OlxuICAgICAgICAgIG5hbWU6IG9wZW5zcGVjLXRhc2tzLXZlcmlmeVxuICAgICAgICAgIGlucHV0czpcbiAgICAgICAgICAgIGNoYW5nZVNsdWc6ICdcXCR7eyBkYXRhLmxhdGVzdChzZWxmLm5hbWUsIFwiYXJ0aWZhY3QtcGxhblwiKS5wYXlsb2FkLmNoYW5nZVNsdWcgfX0nXG4gICAgICAgIHJlc3VsdEV2aWRlbmNlOiB0YXNrcy12ZXJpZnktcnVuXG4gICAgICB0cmFuc2l0aW9uczpcbiAgICAgICAgLSBuYW1lOiBwYXNzXG4gICAgICAgICAgdG86IHByZS1wci12ZXJpZnlcbiAgICAgICAgICBnYXRlczpcbiAgICAgICAgICAgIC0gdHlwZTogd29ya2Zsb3ctc3VjY2VlZGVkXG4gICAgICAgICAgICAgIGNvbmZpZzogeyB3b3JrZmxvdzogb3BlbnNwZWMtdGFza3MtdmVyaWZ5IH1cbiAgICAgICAgLSBuYW1lOiBmYWlsXG4gICAgICAgICAgdG86IGltcGxlbWVudGluZ1xuICAgICAgICAgIGdhdGVzOlxuICAgICAgICAgICAgLSB0eXBlOiBldmlkZW5jZS1yZWNvcmRlZFxuICAgICAgICAgICAgICBjb25maWc6IHsgbmFtZTogdGFza3MtdmVyaWZ5LXJ1biwgcmVxdWlyZUZpZWxkOiB7IHN0YXR1czogZmFpbGVkIH0gfVxuXG4gICAgLSBpZDogcHJlLXByLXZlcmlmeVxuICAgICAgZGVzY3JpcHRpb246ID4tXG4gICAgICAgIFByZS1QUiB2ZXJpZmljYXRpb246IGJ1aWxkL3N5bnRoL3Rlc3QvbGludCBwbHVzIHRoZSBhcmNoaXRlY3R1cmVcbiAgICAgICAgcnVsZSByZWdpc3RyeSwgcnVuIGJlZm9yZSB0aGUgUFIgaXMgb3BlbmVkIHJhdGhlciB0aGFuIHJlbHlpbmcgb25cbiAgICAgICAgQ0kgYWZ0ZXIgdGhlIGZhY3QuXG4gICAgICB3b3JrOlxuICAgICAgICBtb2RlOiB3b3JrZmxvd1xuICAgICAgICB3b3JrZmxvdzpcbiAgICAgICAgICBuYW1lOiBwcmUtcHItdmVyaWZ5XG4gICAgICAgICAgaW5wdXRzOlxuICAgICAgICAgICAgY29tbWl0OiAnXFwke3sgZGF0YS5sYXRlc3Qoc2VsZi5uYW1lLCBcImV2aWRlbmNlLWNoYW5nZS1yZXF1ZXN0XCIpLnBheWxvYWQuaGVhZFNoYSB9fSdcbiAgICAgICAgICAgIGJyYW5jaDogJ1xcJHt7IGRhdGEubGF0ZXN0KHNlbGYubmFtZSwgXCJldmlkZW5jZS1jaGFuZ2UtcmVxdWVzdFwiKS5wYXlsb2FkLmJyYW5jaCB9fSdcbiAgICAgICAgcmVzdWx0RXZpZGVuY2U6IHZlcmlmeS1ydW5cbiAgICAgIHRyYW5zaXRpb25zOlxuICAgICAgICAtIG5hbWU6IHBhc3NcbiAgICAgICAgICB0bzogb3Blbi1wclxuICAgICAgICAgIGdhdGVzOlxuICAgICAgICAgICAgLSB0eXBlOiB3b3JrZmxvdy1zdWNjZWVkZWRcbiAgICAgICAgICAgICAgY29uZmlnOiB7IHdvcmtmbG93OiBwcmUtcHItdmVyaWZ5IH1cbiAgICAgICAgLSBuYW1lOiBmYWlsXG4gICAgICAgICAgdG86IGltcGxlbWVudGluZ1xuICAgICAgICAgIGdhdGVzOlxuICAgICAgICAgICAgLSB0eXBlOiBldmlkZW5jZS1yZWNvcmRlZFxuICAgICAgICAgICAgICBjb25maWc6IHsgbmFtZTogdmVyaWZ5LXJ1biwgcmVxdWlyZUZpZWxkOiB7IHN0YXR1czogZmFpbGVkIH0gfVxuXG4gICAgLSBpZDogb3Blbi1wclxuICAgICAgZGVzY3JpcHRpb246IE9wZW4gdGhlIHB1bGwgcmVxdWVzdCBub3cgdGhhdCBwcmUtUFIgdmVyaWZpY2F0aW9uIGhhcyBwYXNzZWQuXG4gICAgICB3b3JrOlxuICAgICAgICBtb2RlOiBpbnRlcmFjdGl2ZVxuICAgICAgICBzeXN0ZW1Qcm9tcHQ6ID4tXG4gICAgICAgICAgQmVmb3JlIG9wZW5pbmcgdGhlIFBSLCBmZXRjaCB0aGUgcmVhbCBwcmUtcHItdmVyaWZ5IGF0dGVzdGF0aW9uXG4gICAgICAgICAgd2l0aCBcXGBzd2FtcCBkYXRhIGdldCAtLXdvcmtmbG93IHByZS1wci12ZXJpZnlcbiAgICAgICAgICByZXBvcnQtc3dhbXAtdmVyaWZpY2F0aW9uLWF0dGVzdGF0aW9uIC0tanNvblxcYCBhbmQgaW5jbHVkZSBpdHNcbiAgICAgICAgICBcXGBjb250ZW50XFxgIHZlcmJhdGltIChhcyBhIG1hcmtkb3duIGJsb2NrLCBlLmcuIHVuZGVyIGEgXCJQcmUtUFJcbiAgICAgICAgICB2ZXJpZmljYXRpb25cIiBoZWFkaW5nKSBpbiB0aGUgUFIgYm9keSDigJQgbmV2ZXIganVzdCBhc3NlcnQgaW5cbiAgICAgICAgICBwcm9zZSB0aGF0IGNoZWNrcyBwYXNzZWQuIEFsc28gZmV0Y2ggdGhpcyBzYW1lIHJ1bidzIG1hbmlmZXN0IHN0ZXBcbiAgICAgICAgICBvdXRwdXQgKFxcYHN3YW1wIGRhdGEgcXVlcnkgJ21vZGVsTmFtZSA9PSBcIiR7c2hlbGxNYW5pZmVzdE1vZGVsfVwiICYmXG4gICAgICAgICAgbmFtZSA9PSBcInJlc3VsdFwiJyAtLXNlbGVjdCBhdHRyaWJ1dGVzLnN0ZG91dCAtLWpzb25cXGAsIHRha2UgdGhlXG4gICAgICAgICAgbGF0ZXN0KSBhbmQgYXBwZW5kIGl0IHRvIHRoZSBQUiBib2R5IGFzXG4gICAgICAgICAgXFxgPCEtLSBhdHRlc3RhdGlvbi1tYW5pZmVzdCB7XCJjb21taXRcIjogXCI8aGVhZFNoYT5cIiwgXCJzdGF0dXNcIjpcbiAgICAgICAgICBcInN1Y2NlZWRlZFwiLCAuLi50aGUgbWFuaWZlc3Qgc3RlcCdzIEpTT04sIHNwcmVhZCBpbi4uLn0gLS0+XFxgIOKAlCBhblxuICAgICAgICAgIEhUTUwgY29tbWVudCBzbyBpdCdzIGludmlzaWJsZSB3aGVuIHJlbmRlcmVkIGJ1dCBzdGlsbCBwcmVzZW50IGluXG4gICAgICAgICAgdGhlIHJhdyBib2R5IHRleHQgdmVyaWZ5LWF0dGVzdGF0aW9uLnltbCByZWFkcyB2aWEgdGhlIEdpdEh1YiBBUEkuXG4gICAgICAgICAgQWxzbyBmZXRjaCB0aGUgcGxhbiBhcnRpZmFjdCdzIGNoYW5nZVNsdWcgYW5kIGluY2x1ZGUgYW4gZXhwbGljaXRcbiAgICAgICAgICBcIk9wZW5TcGVjIGNoYW5nZVwiIGxpbmUgaW4gdGhlIFBSIGJvZHkgbmFtaW5nIGl0IGFuZCBpdHMgcGF0aFxuICAgICAgICAgIChcXGBvcGVuc3BlYy9jaGFuZ2VzLzxjaGFuZ2VTbHVnPi9cXGApIOKAlCBldmVyeSBQUiB0aGUgZmFjdG9yeSBvcGVuc1xuICAgICAgICAgIG11c3QgY2FsbCBvdXQgd2hpY2ggT3BlblNwZWMgY2hhbmdlKHMpIGRyb3ZlIHRoZSBzZXNzaW9uLCBub3RcbiAgICAgICAgICBqdXN0IGltcGx5IGl0LiBJZiBwbGFubmluZyBjeWNsZWQgdGhyb3VnaCBtb3JlIHRoYW4gb25lIGNoYW5nZVxuICAgICAgICAgIChhIHJld29yayBsb29wIHByb2R1Y2VkIGEgbmV3IGNoYW5nZVNsdWcpLCBsaXN0IGV2ZXJ5IGRpc3RpbmN0XG4gICAgICAgICAgY2hhbmdlU2x1ZyByZWNvcmRlZCBhY3Jvc3MgdGhlIHJ1bidzIHBsYW4gYXJ0aWZhY3QgdmVyc2lvbnMsIG5vdFxuICAgICAgICAgIG9ubHkgdGhlIGxhdGVzdC4gVGhlbiBjYWxsICR7cHJNb2RlbH0ncyBvcGVuUHIgbWV0aG9kXG4gICAgICAgICAgKHJlcG89JHtyZXBvfSwgaGVhZD08dGhlIGJyYW5jaCByZWNvcmRlZCBpblxuICAgICAgICAgIGNoYW5nZS1yZXF1ZXN0IGV2aWRlbmNlPiwgYmFzZT0ke2Jhc2VCcmFuY2h9LCBkcnlSdW49ZmFsc2UpLCB3aXRoXG4gICAgICAgICAgdGl0bGUvYm9keSByZWZlcmVuY2luZyB0aGUgaW50YWtlIHN0YWdlJ3MgaXNzdWUgbnVtYmVyLCB0aGVcbiAgICAgICAgICBPcGVuU3BlYyBjaGFuZ2UocyksIHRoZSBhdHRlc3RhdGlvbiBibG9jaywgYW5kIHRoZSBtYW5pZmVzdFxuICAgICAgICAgIGNvbW1lbnQsIHRoZW4gcmVjb3JkIHRoZSBwci1vcGVuZWQgZXZpZGVuY2Ugd2l0aCB0aGUgcmV0dXJuZWQgUFJcbiAgICAgICAgICB1cmwgYW5kIG51bWJlci5cbiAgICAgIGV2aWRlbmNlOlxuICAgICAgICAtIG5hbWU6IHByLW9wZW5lZFxuICAgICAgICAgIHNjaGVtYTpcbiAgICAgICAgICAgIHR5cGU6IG9iamVjdFxuICAgICAgICAgICAgcmVxdWlyZWQ6IFt1cmwsIG51bWJlcl1cbiAgICAgICAgICAgIHByb3BlcnRpZXM6XG4gICAgICAgICAgICAgIHVybDogeyB0eXBlOiBzdHJpbmcsIG1pbkxlbmd0aDogMSB9XG4gICAgICAgICAgICAgIG51bWJlcjogeyB0eXBlOiBpbnRlZ2VyIH1cbiAgICAgIHRyYW5zaXRpb25zOlxuICAgICAgICAtIG5hbWU6IHN1Ym1pdFxuICAgICAgICAgIHRvOiBkb25lXG4gICAgICAgICAgZ2F0ZXM6XG4gICAgICAgICAgICAtIHR5cGU6IGV2aWRlbmNlLXJlY29yZGVkXG4gICAgICAgICAgICAgIGNvbmZpZzogeyBuYW1lOiBwci1vcGVuZWQgfVxuXG4gICAgLSBpZDogZG9uZVxuICAgICAgdGVybWluYWw6IHRydWVcblxuICAgIC0gaWQ6IGFib3J0ZWRcbiAgICAgIHRlcm1pbmFsOiB0cnVlXG5cbiAgZ2xvYmFsVHJhbnNpdGlvbnM6XG4gICAgLSBuYW1lOiBhYm9ydFxuICAgICAgdG86IGFib3J0ZWRcbiAgICAgIGdhdGVzOlxuICAgICAgICAtIHR5cGU6IGh1bWFuLWFwcHJvdmFsXG4gICAgICAgICAgY29uZmlnOiB7IGlkOiBhYm9ydC1jb25maXJtYXRpb24gfVxubWV0aG9kczoge31cbmAsXG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,8 @@
1
+ import { NodeProject } from 'projen/lib/javascript';
2
+ /**
3
+ * Deterministic gate: fails unless every task in the named OpenSpec change's
4
+ * tasks.md is checked off. Fully generic — no per-repo parameterization.
5
+ */
6
+ export declare class SoftwareFactoryOpenSpecGates {
7
+ constructor(project: NodeProject);
8
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SoftwareFactoryOpenSpecGates = void 0;
4
+ const projen_1 = require("projen");
5
+ /**
6
+ * Deterministic gate: fails unless every task in the named OpenSpec change's
7
+ * tasks.md is checked off. Fully generic — no per-repo parameterization.
8
+ */
9
+ class SoftwareFactoryOpenSpecGates {
10
+ constructor(project) {
11
+ new projen_1.TextFile(project, 'openspec-gates/check-tasks-complete.ts', {
12
+ marker: true,
13
+ lines: [
14
+ '/**',
15
+ ' * Gate: fails unless every task in the named OpenSpec change\'s tasks.md is',
16
+ ' * checked off. `openspec validate`/`openspec status` don\'t check this (an',
17
+ ' * in-progress change is a normal, valid state) — this is the deterministic',
18
+ ' * check the pre-pr pipeline needs before letting implementation proceed.',
19
+ ' */',
20
+ "import { execFileSync } from 'node:child_process';",
21
+ '',
22
+ 'interface OpenSpecChangeSummary {',
23
+ ' name: string;',
24
+ ' completedTasks: number;',
25
+ ' totalTasks: number;',
26
+ ' status: string;',
27
+ '}',
28
+ '',
29
+ 'function main(): number {',
30
+ ' // pnpm\'s `-- <args>` forwarding (and projen\'s receiveArgs) can pass a',
31
+ ' // literal "--" through as an argv token ahead of the real argument.',
32
+ " const slug = process.argv.slice(2).find((arg) => arg !== '--');",
33
+ ' if (!slug) {',
34
+ " console.error('Usage: check-tasks-complete <change-slug>');",
35
+ ' return 1;',
36
+ ' }',
37
+ '',
38
+ " const raw = execFileSync('openspec', ['list', '--json'], { encoding: 'utf8' });",
39
+ ' const { changes } = JSON.parse(raw) as { changes: OpenSpecChangeSummary[] };',
40
+ ' const change = changes.find((c) => c.name === slug);',
41
+ '',
42
+ ' if (!change) {',
43
+ ' console.error(`OpenSpec change "${slug}" not found (openspec list --json)`);',
44
+ ' return 1;',
45
+ ' }',
46
+ " if (change.status !== 'complete') {",
47
+ ' console.error(',
48
+ ' `OpenSpec change "${slug}" has incomplete tasks: ${change.completedTasks}/${change.totalTasks}`,',
49
+ ' );',
50
+ ' return 1;',
51
+ ' }',
52
+ '',
53
+ ' console.log(`OpenSpec change "${slug}": all ${change.totalTasks} tasks complete`);',
54
+ ' return 0;',
55
+ '}',
56
+ '',
57
+ 'process.exit(main());',
58
+ ],
59
+ });
60
+ new projen_1.JsonFile(project, 'openspec-gates/tsconfig.json', {
61
+ marker: false,
62
+ obj: {
63
+ extends: '../tsconfig.json',
64
+ compilerOptions: {
65
+ noEmit: true,
66
+ rootDir: '.',
67
+ },
68
+ include: ['*.ts'],
69
+ exclude: ['node_modules'],
70
+ },
71
+ });
72
+ }
73
+ }
74
+ exports.SoftwareFactoryOpenSpecGates = SoftwareFactoryOpenSpecGates;
75
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU29mdHdhcmVGYWN0b3J5T3BlblNwZWNHYXRlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9Tb2Z0d2FyZUZhY3RvcnlPcGVuU3BlY0dhdGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1DQUE0QztBQUc1Qzs7O0dBR0c7QUFDSCxNQUFhLDRCQUE0QjtJQUN2QyxZQUFZLE9BQW9CO1FBQzlCLElBQUksaUJBQVEsQ0FBQyxPQUFPLEVBQUUsd0NBQXdDLEVBQUU7WUFDOUQsTUFBTSxFQUFFLElBQUk7WUFDWixLQUFLLEVBQUU7Z0JBQ0wsS0FBSztnQkFDTCw4RUFBOEU7Z0JBQzlFLDZFQUE2RTtnQkFDN0UsNkVBQTZFO2dCQUM3RSwyRUFBMkU7Z0JBQzNFLEtBQUs7Z0JBQ0wsb0RBQW9EO2dCQUNwRCxFQUFFO2dCQUNGLG1DQUFtQztnQkFDbkMsaUJBQWlCO2dCQUNqQiwyQkFBMkI7Z0JBQzNCLHVCQUF1QjtnQkFDdkIsbUJBQW1CO2dCQUNuQixHQUFHO2dCQUNILEVBQUU7Z0JBQ0YsMkJBQTJCO2dCQUMzQiw0RUFBNEU7Z0JBQzVFLHdFQUF3RTtnQkFDeEUsbUVBQW1FO2dCQUNuRSxnQkFBZ0I7Z0JBQ2hCLGlFQUFpRTtnQkFDakUsZUFBZTtnQkFDZixLQUFLO2dCQUNMLEVBQUU7Z0JBQ0YsbUZBQW1GO2dCQUNuRixnRkFBZ0Y7Z0JBQ2hGLHdEQUF3RDtnQkFDeEQsRUFBRTtnQkFDRixrQkFBa0I7Z0JBQ2xCLGtGQUFrRjtnQkFDbEYsZUFBZTtnQkFDZixLQUFLO2dCQUNMLHVDQUF1QztnQkFDdkMsb0JBQW9CO2dCQUNwQix3R0FBd0c7Z0JBQ3hHLFFBQVE7Z0JBQ1IsZUFBZTtnQkFDZixLQUFLO2dCQUNMLEVBQUU7Z0JBQ0Ysc0ZBQXNGO2dCQUN0RixhQUFhO2dCQUNiLEdBQUc7Z0JBQ0gsRUFBRTtnQkFDRix1QkFBdUI7YUFDeEI7U0FDRixDQUFDLENBQUM7UUFFSCxJQUFJLGlCQUFRLENBQUMsT0FBTyxFQUFFLDhCQUE4QixFQUFFO1lBQ3BELE1BQU0sRUFBRSxLQUFLO1lBQ2IsR0FBRyxFQUFFO2dCQUNILE9BQU8sRUFBRSxrQkFBa0I7Z0JBQzNCLGVBQWUsRUFBRTtvQkFDZixNQUFNLEVBQUUsSUFBSTtvQkFDWixPQUFPLEVBQUUsR0FBRztpQkFDYjtnQkFDRCxPQUFPLEVBQUUsQ0FBQyxNQUFNLENBQUM7Z0JBQ2pCLE9BQU8sRUFBRSxDQUFDLGNBQWMsQ0FBQzthQUMxQjtTQUNGLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQWpFRCxvRUFpRUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBKc29uRmlsZSwgVGV4dEZpbGUgfSBmcm9tICdwcm9qZW4nO1xuaW1wb3J0IHsgTm9kZVByb2plY3QgfSBmcm9tICdwcm9qZW4vbGliL2phdmFzY3JpcHQnO1xuXG4vKipcbiAqIERldGVybWluaXN0aWMgZ2F0ZTogZmFpbHMgdW5sZXNzIGV2ZXJ5IHRhc2sgaW4gdGhlIG5hbWVkIE9wZW5TcGVjIGNoYW5nZSdzXG4gKiB0YXNrcy5tZCBpcyBjaGVja2VkIG9mZi4gRnVsbHkgZ2VuZXJpYyDigJQgbm8gcGVyLXJlcG8gcGFyYW1ldGVyaXphdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIFNvZnR3YXJlRmFjdG9yeU9wZW5TcGVjR2F0ZXMge1xuICBjb25zdHJ1Y3Rvcihwcm9qZWN0OiBOb2RlUHJvamVjdCkge1xuICAgIG5ldyBUZXh0RmlsZShwcm9qZWN0LCAnb3BlbnNwZWMtZ2F0ZXMvY2hlY2stdGFza3MtY29tcGxldGUudHMnLCB7XG4gICAgICBtYXJrZXI6IHRydWUsXG4gICAgICBsaW5lczogW1xuICAgICAgICAnLyoqJyxcbiAgICAgICAgJyAqIEdhdGU6IGZhaWxzIHVubGVzcyBldmVyeSB0YXNrIGluIHRoZSBuYW1lZCBPcGVuU3BlYyBjaGFuZ2VcXCdzIHRhc2tzLm1kIGlzJyxcbiAgICAgICAgJyAqIGNoZWNrZWQgb2ZmLiBgb3BlbnNwZWMgdmFsaWRhdGVgL2BvcGVuc3BlYyBzdGF0dXNgIGRvblxcJ3QgY2hlY2sgdGhpcyAoYW4nLFxuICAgICAgICAnICogaW4tcHJvZ3Jlc3MgY2hhbmdlIGlzIGEgbm9ybWFsLCB2YWxpZCBzdGF0ZSkg4oCUIHRoaXMgaXMgdGhlIGRldGVybWluaXN0aWMnLFxuICAgICAgICAnICogY2hlY2sgdGhlIHByZS1wciBwaXBlbGluZSBuZWVkcyBiZWZvcmUgbGV0dGluZyBpbXBsZW1lbnRhdGlvbiBwcm9jZWVkLicsXG4gICAgICAgICcgKi8nLFxuICAgICAgICBcImltcG9ydCB7IGV4ZWNGaWxlU3luYyB9IGZyb20gJ25vZGU6Y2hpbGRfcHJvY2Vzcyc7XCIsXG4gICAgICAgICcnLFxuICAgICAgICAnaW50ZXJmYWNlIE9wZW5TcGVjQ2hhbmdlU3VtbWFyeSB7JyxcbiAgICAgICAgJyAgbmFtZTogc3RyaW5nOycsXG4gICAgICAgICcgIGNvbXBsZXRlZFRhc2tzOiBudW1iZXI7JyxcbiAgICAgICAgJyAgdG90YWxUYXNrczogbnVtYmVyOycsXG4gICAgICAgICcgIHN0YXR1czogc3RyaW5nOycsXG4gICAgICAgICd9JyxcbiAgICAgICAgJycsXG4gICAgICAgICdmdW5jdGlvbiBtYWluKCk6IG51bWJlciB7JyxcbiAgICAgICAgJyAgLy8gcG5wbVxcJ3MgYC0tIDxhcmdzPmAgZm9yd2FyZGluZyAoYW5kIHByb2plblxcJ3MgcmVjZWl2ZUFyZ3MpIGNhbiBwYXNzIGEnLFxuICAgICAgICAnICAvLyBsaXRlcmFsIFwiLS1cIiB0aHJvdWdoIGFzIGFuIGFyZ3YgdG9rZW4gYWhlYWQgb2YgdGhlIHJlYWwgYXJndW1lbnQuJyxcbiAgICAgICAgXCIgIGNvbnN0IHNsdWcgPSBwcm9jZXNzLmFyZ3Yuc2xpY2UoMikuZmluZCgoYXJnKSA9PiBhcmcgIT09ICctLScpO1wiLFxuICAgICAgICAnICBpZiAoIXNsdWcpIHsnLFxuICAgICAgICBcIiAgICBjb25zb2xlLmVycm9yKCdVc2FnZTogY2hlY2stdGFza3MtY29tcGxldGUgPGNoYW5nZS1zbHVnPicpO1wiLFxuICAgICAgICAnICAgIHJldHVybiAxOycsXG4gICAgICAgICcgIH0nLFxuICAgICAgICAnJyxcbiAgICAgICAgXCIgIGNvbnN0IHJhdyA9IGV4ZWNGaWxlU3luYygnb3BlbnNwZWMnLCBbJ2xpc3QnLCAnLS1qc29uJ10sIHsgZW5jb2Rpbmc6ICd1dGY4JyB9KTtcIixcbiAgICAgICAgJyAgY29uc3QgeyBjaGFuZ2VzIH0gPSBKU09OLnBhcnNlKHJhdykgYXMgeyBjaGFuZ2VzOiBPcGVuU3BlY0NoYW5nZVN1bW1hcnlbXSB9OycsXG4gICAgICAgICcgIGNvbnN0IGNoYW5nZSA9IGNoYW5nZXMuZmluZCgoYykgPT4gYy5uYW1lID09PSBzbHVnKTsnLFxuICAgICAgICAnJyxcbiAgICAgICAgJyAgaWYgKCFjaGFuZ2UpIHsnLFxuICAgICAgICAnICAgIGNvbnNvbGUuZXJyb3IoYE9wZW5TcGVjIGNoYW5nZSBcIiR7c2x1Z31cIiBub3QgZm91bmQgKG9wZW5zcGVjIGxpc3QgLS1qc29uKWApOycsXG4gICAgICAgICcgICAgcmV0dXJuIDE7JyxcbiAgICAgICAgJyAgfScsXG4gICAgICAgIFwiICBpZiAoY2hhbmdlLnN0YXR1cyAhPT0gJ2NvbXBsZXRlJykge1wiLFxuICAgICAgICAnICAgIGNvbnNvbGUuZXJyb3IoJyxcbiAgICAgICAgJyAgICAgIGBPcGVuU3BlYyBjaGFuZ2UgXCIke3NsdWd9XCIgaGFzIGluY29tcGxldGUgdGFza3M6ICR7Y2hhbmdlLmNvbXBsZXRlZFRhc2tzfS8ke2NoYW5nZS50b3RhbFRhc2tzfWAsJyxcbiAgICAgICAgJyAgICApOycsXG4gICAgICAgICcgICAgcmV0dXJuIDE7JyxcbiAgICAgICAgJyAgfScsXG4gICAgICAgICcnLFxuICAgICAgICAnICBjb25zb2xlLmxvZyhgT3BlblNwZWMgY2hhbmdlIFwiJHtzbHVnfVwiOiBhbGwgJHtjaGFuZ2UudG90YWxUYXNrc30gdGFza3MgY29tcGxldGVgKTsnLFxuICAgICAgICAnICByZXR1cm4gMDsnLFxuICAgICAgICAnfScsXG4gICAgICAgICcnLFxuICAgICAgICAncHJvY2Vzcy5leGl0KG1haW4oKSk7JyxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBuZXcgSnNvbkZpbGUocHJvamVjdCwgJ29wZW5zcGVjLWdhdGVzL3RzY29uZmlnLmpzb24nLCB7XG4gICAgICBtYXJrZXI6IGZhbHNlLFxuICAgICAgb2JqOiB7XG4gICAgICAgIGV4dGVuZHM6ICcuLi90c2NvbmZpZy5qc29uJyxcbiAgICAgICAgY29tcGlsZXJPcHRpb25zOiB7XG4gICAgICAgICAgbm9FbWl0OiB0cnVlLFxuICAgICAgICAgIHJvb3REaXI6ICcuJyxcbiAgICAgICAgfSxcbiAgICAgICAgaW5jbHVkZTogWycqLnRzJ10sXG4gICAgICAgIGV4Y2x1ZGU6IFsnbm9kZV9tb2R1bGVzJ10sXG4gICAgICB9LFxuICAgIH0pO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,28 @@
1
+ import { NodeProject } from 'projen/lib/javascript';
2
+ import { WorkflowActionVersions } from './WorkflowActionVersions';
3
+ export interface SoftwareFactoryWorkflowsOptions {
4
+ /**
5
+ * The bare repo name, used to derive the `<repoName>-shell[-architecture|-manifest]`
6
+ * model names these workflows dispatch shell commands through.
7
+ */
8
+ readonly repoName: string;
9
+ /**
10
+ * Overrides for the pinned action versions used by `verify-attestation.yml`.
11
+ */
12
+ readonly actionVersions?: WorkflowActionVersions;
13
+ }
14
+ /**
15
+ * The 3 swamp workflows the factory's gate stages run (openspec-plan-verify,
16
+ * openspec-tasks-verify, pre-pr-verify), plus the GitHub Action that
17
+ * re-verifies a PR's embedded attestation at merge time.
18
+ *
19
+ * The swamp workflow YAMLs carry a swamp-assigned `id` that must stay stable
20
+ * across synths (swamp uses it as the workflow's identity), so — like the
21
+ * model instances in `SoftwareFactoryModels` — they're `SampleFile`s, written
22
+ * once and then owned by the team. `verify-attestation.yml` has no such
23
+ * identity constraint and is a plain GitHub Actions workflow, so it's built
24
+ * the same managed way `PrDeployWorkflow` is.
25
+ */
26
+ export declare class SoftwareFactoryWorkflows {
27
+ constructor(project: NodeProject, options: SoftwareFactoryWorkflowsOptions);
28
+ }