azcodr 1.5.1 → 2.0.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.
Files changed (91) hide show
  1. package/.agents/hooks.json.example +42 -42
  2. package/.agents/scripts/safety_guard.sh +143 -34
  3. package/.agents/scripts/verify_completion.sh +90 -27
  4. package/.agents/skills/agentic-architect/SKILL.md +125 -125
  5. package/.agents/skills/agentic-architect/references/agents_md_template.md +62 -62
  6. package/.agents/skills/agentic-architect/references/refinement_workflow.md +32 -32
  7. package/.agents/skills/agentic-architect/references/skill_architecture_inquiry.md +63 -63
  8. package/.agents/skills/agentic-architect/references/skill_template.md +56 -56
  9. package/.agents/skills/agentic-architect/scripts/validate_agentic_configs.sh +402 -401
  10. package/.agents/skills/clean-code-refactor/SKILL.md +91 -91
  11. package/.agents/skills/clean-code-refactor/references/clean_code_smells.md +27 -27
  12. package/.agents/skills/clean-code-refactor/references/design_patterns_ts.md +65 -65
  13. package/.agents/skills/compliance-audit/SKILL.md +120 -120
  14. package/.agents/skills/compliance-audit/references/owasp_top10_controls.md +16 -16
  15. package/.agents/skills/compliance-audit/references/soc2_iso_controls.md +28 -28
  16. package/.agents/skills/lets-build/SKILL.md +173 -173
  17. package/.agents/skills/lets-build/references/architecture_interview_matrix.md +115 -115
  18. package/.agents/skills/lets-build/references/hexagonal_bootstrap_scaffolds.md +160 -160
  19. package/.agents/skills/lets-build/references/project_readme_template.md +79 -79
  20. package/.agents/skills/lets-build/scripts/bootstrap_workspace.sh +419 -255
  21. package/.agents/skills/product-analyst/SKILL.md +154 -154
  22. package/.agents/skills/product-analyst/references/backlog_ordering_techniques.md +107 -107
  23. package/.agents/skills/product-analyst/references/gherkin_patterns.md +46 -46
  24. package/.agents/skills/product-analyst/references/invest_checklist.md +38 -38
  25. package/.agents/skills/product-analyst/references/okr_alignment_guide.md +76 -76
  26. package/.agents/skills/product-analyst/references/smart_tasks.md +59 -59
  27. package/.agents/skills/relentless-questioner/SKILL.md +128 -128
  28. package/.agents/skills/relentless-questioner/references/adaptive_question_trees.md +102 -102
  29. package/.editorconfig +19 -19
  30. package/.github/workflows/ci.yml +167 -56
  31. package/.github/workflows/publish.yml +200 -0
  32. package/.gitignore +40 -25
  33. package/AGENTS.md +103 -102
  34. package/LICENSE +21 -21
  35. package/README.md +168 -154
  36. package/bin/azcodr.js +14 -228
  37. package/docs/knowledge/ubiquitous_language.md +31 -18
  38. package/docs/rules/agentic_configuration.md +259 -259
  39. package/docs/rules/api_architecture.md +179 -179
  40. package/docs/rules/authentication.md +76 -76
  41. package/docs/rules/authorization.md +75 -75
  42. package/docs/rules/caching.md +69 -69
  43. package/docs/rules/clean_code.md +62 -62
  44. package/docs/rules/cloud_native.md +41 -41
  45. package/docs/rules/cqrs.md +203 -203
  46. package/docs/rules/database_design.md +125 -125
  47. package/docs/rules/database_operations.md +69 -69
  48. package/docs/rules/design_patterns.md +98 -98
  49. package/docs/rules/devops_ci_cd.md +76 -76
  50. package/docs/rules/domain_driven_design.md +122 -122
  51. package/docs/rules/error_handling.md +54 -52
  52. package/docs/rules/feature_flags.md +59 -59
  53. package/docs/rules/frontend_architecture.md +157 -157
  54. package/docs/rules/multitenancy_architecture.md +98 -98
  55. package/docs/rules/product_ownership.md +127 -127
  56. package/docs/rules/project_management.md +49 -49
  57. package/docs/rules/relentless_questioning.md +52 -52
  58. package/docs/rules/requirements_engineering.md +98 -98
  59. package/docs/rules/security_compliance.md +53 -53
  60. package/docs/rules/server_driven_ui.md +88 -88
  61. package/docs/rules/test_driven_development.md +185 -185
  62. package/docs/rules/transactional_email.md +27 -27
  63. package/docs/rules/type_safety.md +65 -65
  64. package/docs/rules/ui_ux_architecture.md +150 -150
  65. package/docs/rules/workflow_state_machines.md +117 -117
  66. package/lib/cli-parse.js +51 -0
  67. package/lib/cli-target.js +109 -0
  68. package/lib/cli.js +180 -0
  69. package/lib/errors.js +28 -0
  70. package/lib/git.js +29 -0
  71. package/lib/guards.js +96 -0
  72. package/lib/index.d.ts +199 -134
  73. package/lib/index.js +5 -5
  74. package/lib/links.js +123 -0
  75. package/lib/permissions.js +44 -0
  76. package/lib/repo.js +90 -0
  77. package/lib/scaffold.js +238 -399
  78. package/memory.md +119 -36
  79. package/package.json +65 -62
  80. package/scripts/test_coverage.js +66 -38
  81. package/scripts/validate/adr.js +151 -0
  82. package/scripts/validate/io.js +84 -0
  83. package/scripts/validate/links.js +167 -0
  84. package/scripts/validate/parity.js +124 -0
  85. package/scripts/validate/root.js +184 -0
  86. package/scripts/validate/rules.js +44 -0
  87. package/scripts/validate/skills.js +96 -0
  88. package/scripts/validate/text.js +29 -0
  89. package/scripts/validate-cli.js +13 -0
  90. package/scripts/validate.js +112 -218
  91. package/.github/copilot-instructions.md +0 -1
@@ -1,102 +1,102 @@
1
- # Adaptive Questioning Trees & Contextual Branching Matrices
2
-
3
- > **Core Purpose:** Detailed decision trees for the `relentless-questioner` skill, demonstrating how subsequent questions adapt dynamically based on previous user responses.
4
-
5
- ---
6
-
7
- ## Decision Tree 1: Mutating Operations & State Changes
8
-
9
- ```mermaid
10
- flowchart TD
11
- Q1["Does the operation mutate database state?"]
12
- Q1 -->|Yes| Q2["Does it involve multiple tables, monetary balances, or inventory?"]
13
- Q1 -->|No / Read Only| Q_Read["Branch: Read Performance & Consistency"]
14
-
15
- Q2 -->|Yes: Financial / Inventory| Q_Acid["1. Transaction Isolation: REPEATABLE READ or SERIALIZABLE?\n2. Lock Ordering: How to prevent deadlocks?\n3. Concurrency: Optimistic Concurrency Control (version) or pessimistic locking?"]
16
- Q2 -->|No: Standard Entity CRUD| Q_Crud["1. Soft delete or hard delete?\n2. Unique constraints across tenant?\n3. Cascading relations?"]
17
-
18
- Q_Acid --> Q3["Does the mutation emit domain events or notify external systems?"]
19
- Q_Crud --> Q3
20
-
21
- Q3 -->|Yes| Q_Outbox["How is the dual-write avoided?\n(Enforce Transactional Outbox pattern before broker publish)"]
22
- Q3 -->|No| Q4["Idempotency: Is an Idempotency-Key header required to guard against network retries?"]
23
- ```
24
-
25
- ---
26
-
27
- ## Decision Tree 2: Multi-Tenancy & Authorization Boundaries
28
-
29
- ```mermaid
30
- flowchart TD
31
- Q1["Who executes this action and across which boundary?"]
32
- Q1 -->|End User via Web/API| Q_Auth["1. What roles are permitted (ADMIN, MEMBER, CUSTOMER)?\n2. Are dynamic ABAC attributes involved (e.g. order value threshold)?\n3. Can a user act across multiple tenants (switch tenant)?"]
33
- Q1 -->|System / Background Job| Q_Worker["1. How is tenant context established without an HTTP session?\n2. What service principal / token credentials are used?"]
34
-
35
- Q_Auth --> Q2["What happens if an unauthorized tenant accesses this resource ID?"]
36
- Q2 --> Q_Sec["1. Return 404 Not Found (enumeration masking) or 403 Forbidden?\n2. Is isolation enforced at the DB layer (RLS / AST interceptor)?"]
37
- ```
38
-
39
- ---
40
-
41
- ## Decision Tree 3: External Integrations & 3rd-Party APIs
42
-
43
- ```mermaid
44
- flowchart TD
45
- Q1["Does the feature integrate with an external SaaS or network endpoint?"]
46
- Q1 -->|Yes| Q2["What is the failure tolerance of the integration?"]
47
-
48
- Q2 -->|Synchronous / Critical| Q_Sync["1. What is the strict HTTP timeout (e.g. 3000ms)?\n2. What is the circuit breaker threshold before fast-failing?\n3. What fallback response is served if the 3rd-party is down?"]
49
- Q2 -->|Asynchronous / Event-Driven| Q_Async["1. Does the external system provide webhooks?\n2. How are webhook signatures cryptographically verified?\n3. What is the retry backoff and dead-letter queue (DLQ) policy?"]
50
-
51
- Q_Sync --> Q_Port["How is the external SDK isolated?\n(Enforce application-owned Port interface so domain never imports SDK)"]
52
- Q_Async --> Q_Port
53
- ```
54
-
55
- ---
56
-
57
- ## Decision Tree 4: Read Performance, Caching & Search
58
-
59
- ```mermaid
60
- flowchart TD
61
- Q1["What is the expected read volume and latency requirement?"]
62
- Q1 -->|High Volume / Sub-50ms Latency| Q2["Is stale data acceptable for seconds/minutes?"]
63
-
64
- Q2 -->|Yes| Q_Cache["1. What is the cache TTL and jitter window?\n2. What domain events trigger cache eviction?\n3. Is probabilistic early expiration (XFetch) needed?"]
65
- Q2 -->|No: Strict Read-After-Write Consistency| Q_Consistent["1. Read from primary database instance for 2s after mutation\n2. Bypass read replicas during write session"]
66
-
67
- Q_Cache --> Q_Page["Pagination Strategy: Enforce keyset/cursor pagination over OFFSET"]
68
- Q_Consistent --> Q_Page
69
- ```
70
-
71
- ---
72
-
73
- ## Decision Tree 5: User Interface, Experience Duality & Interaction Flows
74
-
75
- ```mermaid
76
- flowchart TD
77
- Q1["Does the feature introduce or modify a user interface?"]
78
- Q1 -->|Yes| Q2["Who is the primary actor and operational persona?"]
79
-
80
- Q2 -->|Operator / Admin| Q_Op["1. Information Density: Dense tabular grid with filters?\n2. Persistent App Shell: Left collapsible sidebar route?\n3. Actions: Inline row actions or full-page drawer?"]
81
- Q2 -->|Consumer / Member| Q_Member["1. Experience Duality: Consumer portal (/portal)?\n2. Touch Ergonomics: Clean cards & mobile drawer?\n3. Simplified self-service actions?"]
82
-
83
- Q_Op --> Q3["Navigation & State Synchronization"]
84
- Q_Member --> Q3
85
-
86
- Q3 --> Q_State["1. URL State: Deep-link query params (?tab=, ?q=, ?page=, ?modal=)?\n2. Server Cache: TanStack Query hook with automated invalidation?\n3. Accessibility: Accessible headless dialogs & ARIA live regions?"]
87
- ```
88
-
89
- ---
90
-
91
- ## Contextual Follow-Up Patterns
92
-
93
- When conducting the interview, use this exact syntax pattern to chain questions adaptively:
94
-
95
- 1. **Acknowledge and Pin Previous Answer**:
96
- `"Understood, you specified [Option A] for [Requirement X]."`
97
- 2. **Surface Immediate Architectural Implication**:
98
- `"Because of [Option A], [Potential Failure / Edge Case Y] becomes the primary risk."`
99
- 3. **Ask Context-Dependent Question**:
100
- `"How should the system behave when [Condition Y] occurs? Specifically:"`
101
- - *Sub-question 1*
102
- - *Sub-question 2*
1
+ # Adaptive Questioning Trees & Contextual Branching Matrices
2
+
3
+ > **Core Purpose:** Detailed decision trees for the `relentless-questioner` skill, demonstrating how subsequent questions adapt dynamically based on previous user responses.
4
+
5
+ ---
6
+
7
+ ## Decision Tree 1: Mutating Operations & State Changes
8
+
9
+ ```mermaid
10
+ flowchart TD
11
+ Q1["Does the operation mutate database state?"]
12
+ Q1 -->|Yes| Q2["Does it involve multiple tables, monetary balances, or inventory?"]
13
+ Q1 -->|No / Read Only| Q_Read["Branch: Read Performance & Consistency"]
14
+
15
+ Q2 -->|Yes: Financial / Inventory| Q_Acid["1. Transaction Isolation: REPEATABLE READ or SERIALIZABLE?\n2. Lock Ordering: How to prevent deadlocks?\n3. Concurrency: Optimistic Concurrency Control (version) or pessimistic locking?"]
16
+ Q2 -->|No: Standard Entity CRUD| Q_Crud["1. Soft delete or hard delete?\n2. Unique constraints across tenant?\n3. Cascading relations?"]
17
+
18
+ Q_Acid --> Q3["Does the mutation emit domain events or notify external systems?"]
19
+ Q_Crud --> Q3
20
+
21
+ Q3 -->|Yes| Q_Outbox["How is the dual-write avoided?\n(Enforce Transactional Outbox pattern before broker publish)"]
22
+ Q3 -->|No| Q4["Idempotency: Is an Idempotency-Key header required to guard against network retries?"]
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Decision Tree 2: Multi-Tenancy & Authorization Boundaries
28
+
29
+ ```mermaid
30
+ flowchart TD
31
+ Q1["Who executes this action and across which boundary?"]
32
+ Q1 -->|End User via Web/API| Q_Auth["1. What roles are permitted (ADMIN, MEMBER, CUSTOMER)?\n2. Are dynamic ABAC attributes involved (e.g. order value threshold)?\n3. Can a user act across multiple tenants (switch tenant)?"]
33
+ Q1 -->|System / Background Job| Q_Worker["1. How is tenant context established without an HTTP session?\n2. What service principal / token credentials are used?"]
34
+
35
+ Q_Auth --> Q2["What happens if an unauthorized tenant accesses this resource ID?"]
36
+ Q2 --> Q_Sec["1. Return 404 Not Found (enumeration masking) or 403 Forbidden?\n2. Is isolation enforced at the DB layer (RLS / AST interceptor)?"]
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Decision Tree 3: External Integrations & 3rd-Party APIs
42
+
43
+ ```mermaid
44
+ flowchart TD
45
+ Q1["Does the feature integrate with an external SaaS or network endpoint?"]
46
+ Q1 -->|Yes| Q2["What is the failure tolerance of the integration?"]
47
+
48
+ Q2 -->|Synchronous / Critical| Q_Sync["1. What is the strict HTTP timeout (e.g. 3000ms)?\n2. What is the circuit breaker threshold before fast-failing?\n3. What fallback response is served if the 3rd-party is down?"]
49
+ Q2 -->|Asynchronous / Event-Driven| Q_Async["1. Does the external system provide webhooks?\n2. How are webhook signatures cryptographically verified?\n3. What is the retry backoff and dead-letter queue (DLQ) policy?"]
50
+
51
+ Q_Sync --> Q_Port["How is the external SDK isolated?\n(Enforce application-owned Port interface so domain never imports SDK)"]
52
+ Q_Async --> Q_Port
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Decision Tree 4: Read Performance, Caching & Search
58
+
59
+ ```mermaid
60
+ flowchart TD
61
+ Q1["What is the expected read volume and latency requirement?"]
62
+ Q1 -->|High Volume / Sub-50ms Latency| Q2["Is stale data acceptable for seconds/minutes?"]
63
+
64
+ Q2 -->|Yes| Q_Cache["1. What is the cache TTL and jitter window?\n2. What domain events trigger cache eviction?\n3. Is probabilistic early expiration (XFetch) needed?"]
65
+ Q2 -->|No: Strict Read-After-Write Consistency| Q_Consistent["1. Read from primary database instance for 2s after mutation\n2. Bypass read replicas during write session"]
66
+
67
+ Q_Cache --> Q_Page["Pagination Strategy: Enforce keyset/cursor pagination over OFFSET"]
68
+ Q_Consistent --> Q_Page
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Decision Tree 5: User Interface, Experience Duality & Interaction Flows
74
+
75
+ ```mermaid
76
+ flowchart TD
77
+ Q1["Does the feature introduce or modify a user interface?"]
78
+ Q1 -->|Yes| Q2["Who is the primary actor and operational persona?"]
79
+
80
+ Q2 -->|Operator / Admin| Q_Op["1. Information Density: Dense tabular grid with filters?\n2. Persistent App Shell: Left collapsible sidebar route?\n3. Actions: Inline row actions or full-page drawer?"]
81
+ Q2 -->|Consumer / Member| Q_Member["1. Experience Duality: Consumer portal (/portal)?\n2. Touch Ergonomics: Clean cards & mobile drawer?\n3. Simplified self-service actions?"]
82
+
83
+ Q_Op --> Q3["Navigation & State Synchronization"]
84
+ Q_Member --> Q3
85
+
86
+ Q3 --> Q_State["1. URL State: Deep-link query params (?tab=, ?q=, ?page=, ?modal=)?\n2. Server Cache: TanStack Query hook with automated invalidation?\n3. Accessibility: Accessible headless dialogs & ARIA live regions?"]
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Contextual Follow-Up Patterns
92
+
93
+ When conducting the interview, use this exact syntax pattern to chain questions adaptively:
94
+
95
+ 1. **Acknowledge and Pin Previous Answer**:
96
+ `"Understood, you specified [Option A] for [Requirement X]."`
97
+ 2. **Surface Immediate Architectural Implication**:
98
+ `"Because of [Option A], [Potential Failure / Edge Case Y] becomes the primary risk."`
99
+ 3. **Ask Context-Dependent Question**:
100
+ `"How should the system behave when [Condition Y] occurs? Specifically:"`
101
+ - *Sub-question 1*
102
+ - *Sub-question 2*
package/.editorconfig CHANGED
@@ -1,19 +1,19 @@
1
- # http://editorconfig.org
2
- root = true
3
-
4
- [*]
5
- indent_style = space
6
- indent_size = 2
7
- end_of_line = lf
8
- charset = utf-8
9
- trim_trailing_whitespace = true
10
- insert_final_newline = true
11
-
12
- [*.md]
13
- trim_trailing_whitespace = false
14
-
15
- [Makefile]
16
- indent_style = tab
17
-
18
- [*.go]
19
- indent_style = tab
1
+ # http://editorconfig.org
2
+ root = true
3
+
4
+ [*]
5
+ indent_style = space
6
+ indent_size = 2
7
+ end_of_line = lf
8
+ charset = utf-8
9
+ trim_trailing_whitespace = true
10
+ insert_final_newline = true
11
+
12
+ [*.md]
13
+ trim_trailing_whitespace = false
14
+
15
+ [Makefile]
16
+ indent_style = tab
17
+
18
+ [*.go]
19
+ indent_style = tab
@@ -1,56 +1,167 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [ main ]
6
- pull_request:
7
- branches: [ main ]
8
-
9
- jobs:
10
- test:
11
- name: Node ${{ matrix.node-version }} on ${{ matrix.os }}
12
- runs-on: ${{ matrix.os }}
13
- strategy:
14
- fail-fast: false
15
- matrix:
16
- os: [ ubuntu-latest, macos-latest, windows-latest ]
17
- node-version: [ 18.x, 20.x, 22.x, 24.x ]
18
-
19
- steps:
20
- - name: Checkout Repository
21
- uses: actions/checkout@v4
22
-
23
- - name: Setup Node.js ${{ matrix.node-version }}
24
- uses: actions/setup-node@v4
25
- with:
26
- node-version: ${{ matrix.node-version }}
27
-
28
- - name: Verify Environment
29
- run: |
30
- node --version
31
- npm --version
32
-
33
- - name: Run Syntax & Lint Checks
34
- run: npm run lint
35
-
36
- - name: Validate Agentic Architecture
37
- run: npm run validate
38
-
39
- - name: Secret Scan (Gitleaks)
40
- uses: gitleaks/gitleaks-action@v2
41
- env:
42
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43
-
44
- - name: Filesystem Vulnerability Scan (Trivy)
45
- uses: aquasecurity/trivy-action@0.28.0
46
- with:
47
- scan-type: fs
48
- scan-ref: .
49
- severity: HIGH,CRITICAL
50
- exit-code: '1'
51
-
52
- - name: Run Test Suite
53
- run: npm test
54
-
55
- - name: Verify 100.00% Test Coverage Gates
56
- run: npm run test:coverage
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+ merge_group:
9
+ branches: [ main ]
10
+
11
+ # Least privilege by default. Every job here only needs to read the repository.
12
+ # A write-capable token executing `node --test` over PR-controlled content is a
13
+ # supply-chain exposure; grant write scopes only where a job genuinely needs them.
14
+ permissions:
15
+ contents: read
16
+
17
+ # Cancel superseded runs. Without this, five pushes to a PR queue five full
18
+ # matrix runs; with a publish workflow it also prevents two release runs racing
19
+ # the same version.
20
+ concurrency:
21
+ group: ci-${{ github.workflow }}-${{ github.ref }}
22
+ cancel-in-progress: true
23
+
24
+ jobs:
25
+ test:
26
+ name: Node ${{ matrix.node-version }} on ${{ matrix.os }}
27
+ runs-on: ${{ matrix.os }}
28
+ timeout-minutes: 15
29
+ strategy:
30
+ fail-fast: false
31
+ matrix:
32
+ os: [ ubuntu-24.04, macos-latest, windows-latest ]
33
+ # Node 18 (EOL 2025-04-30) and 20 (EOL 2026-04-30) are no longer
34
+ # patched. Half the matrix was verifying unpatched runtimes. Supported
35
+ # lines as of Oct 2026: 24 (Active LTS), 22 (Maintenance), 26 (Current).
36
+ node-version: [ 22.x, 24.x, 26.x ]
37
+
38
+ steps:
39
+ - name: Checkout Repository
40
+ uses: actions/checkout@v7
41
+
42
+ - name: Setup Node.js ${{ matrix.node-version }}
43
+ uses: actions/setup-node@v7
44
+ with:
45
+ node-version: ${{ matrix.node-version }}
46
+
47
+ # The repo has zero runtime dependencies, but contributor tooling
48
+ # (ESLint, ADR-012) is a devDependency and must be installed.
49
+ - name: Install dependencies
50
+ run: npm ci
51
+
52
+ - name: Verify Environment
53
+ run: |
54
+ node --version
55
+ npm --version
56
+
57
+ - name: Run Syntax & Lint Checks
58
+ run: npm run lint
59
+
60
+ - name: Validate Agentic Architecture
61
+ run: npm run validate
62
+
63
+ - name: Run Test Suite
64
+ run: npm test
65
+
66
+ coverage:
67
+ name: Coverage Gate (Node 24)
68
+ runs-on: ubuntu-24.04
69
+ timeout-minutes: 15
70
+ steps:
71
+ - name: Checkout Repository
72
+ uses: actions/checkout@v7
73
+
74
+ - name: Setup Node.js 24.x
75
+ uses: actions/setup-node@v7
76
+ with:
77
+ node-version: 24.x
78
+
79
+ - name: Install dependencies
80
+ run: npm ci
81
+
82
+ # Native threshold flags require Node >=22.8.0 (see scripts/test_coverage.js),
83
+ # so the coverage gate runs once on the newest runtime instead of every matrix cell.
84
+ - name: Verify Coverage Gates
85
+ run: npm run test:coverage
86
+
87
+ shell-syntax:
88
+ name: Shell Script Syntax (shipped hooks)
89
+ runs-on: ubuntu-24.04
90
+ timeout-minutes: 10
91
+ steps:
92
+ - name: Checkout Repository
93
+ uses: actions/checkout@v7
94
+
95
+ # The .sh files ship to every scaffolded project and auto-run as agent
96
+ # hooks. `bash -n` catches a CRLF checkout or a syntax slip that the
97
+ # Node-only lint is blind to.
98
+ - name: Parse every shipped shell script
99
+ run: |
100
+ set -euo pipefail
101
+ failed=0
102
+ while IFS= read -r script; do
103
+ if bash -n "$script"; then
104
+ echo "ok: $script"
105
+ else
106
+ echo "FAIL: $script"
107
+ failed=1
108
+ fi
109
+ done < <(find .agents -name '*.sh' -not -path './node_modules/*')
110
+ exit $failed
111
+
112
+ - name: Verify hooks use LF line endings
113
+ run: |
114
+ set -euo pipefail
115
+ bad=0
116
+ while IFS= read -r script; do
117
+ if grep -qU $'\r' "$script"; then
118
+ echo "CRLF found (breaks shebang + 'set -euo pipefail'): $script"
119
+ bad=1
120
+ fi
121
+ done < <(find .agents -name '*.sh' -not -path './node_modules/*')
122
+ [ "$bad" -eq 0 ] && echo "all hook scripts are LF"
123
+
124
+ security:
125
+ name: Secret & Vulnerability Scans
126
+ runs-on: ubuntu-24.04
127
+ timeout-minutes: 20
128
+ permissions:
129
+ contents: read
130
+ # gitleaks-action comments on PRs when it finds a leak; without these it
131
+ # degrades gracefully to scan-only.
132
+ pull-requests: write
133
+ steps:
134
+ - name: Checkout Repository (full history for secret scanning)
135
+ uses: actions/checkout@v7
136
+ with:
137
+ fetch-depth: 0
138
+
139
+ # gitleaks-action v2 runs on the Node 20 action runtime, which GitHub
140
+ # removed from hosted runners on 2026-09-16 -- the job was failing for
141
+ # every PR. v3 targets Node 24.
142
+ - name: Secret Scan (Gitleaks)
143
+ uses: gitleaks/gitleaks-action@v3
144
+ env:
145
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
146
+
147
+ - name: Filesystem Vulnerability Scan (Trivy)
148
+ uses: aquasecurity/trivy-action@v0.36.0
149
+ with:
150
+ scan-type: fs
151
+ scan-ref: .
152
+ scanners: vuln
153
+ severity: HIGH,CRITICAL
154
+ exit-code: '1'
155
+
156
+ - name: Software Bill of Materials (CycloneDX)
157
+ uses: anchore/sbom-action@v0
158
+ with:
159
+ format: cyclonedx-json
160
+ output-file: sbom.cdx.json
161
+ artifact-name: sbom.cdx.json
162
+
163
+ - name: Dependency Review
164
+ if: github.event_name == 'pull_request'
165
+ uses: actions/dependency-review-action@v4
166
+ with:
167
+ fail-on-severity: high
@@ -0,0 +1,200 @@
1
+ name: Publish
2
+
3
+ on:
4
+ release:
5
+ types: [ published ]
6
+ workflow_dispatch:
7
+ inputs:
8
+ dry-run:
9
+ description: "Verify the publishable tarball without uploading"
10
+ type: boolean
11
+ default: true
12
+
13
+ # Least privilege: read the repo, write only the npm registry.
14
+ permissions:
15
+ contents: read
16
+ id-token: write # npm trusted publishing / provenance attestation
17
+
18
+ # Never let two release runs race the same version.
19
+ concurrency:
20
+ group: publish-${{ github.ref }}
21
+ cancel-in-progress: false
22
+
23
+ jobs:
24
+ verify:
25
+ name: Verify Release Before Publishing
26
+ runs-on: ubuntu-24.04
27
+ timeout-minutes: 15
28
+ steps:
29
+ - name: Checkout Repository
30
+ uses: actions/checkout@v7
31
+
32
+ - name: Setup Node.js 24.x
33
+ uses: actions/setup-node@v7
34
+ with:
35
+ node-version: 24.x
36
+ registry-url: https://registry.npmjs.org
37
+
38
+ - name: Install dependencies
39
+ run: npm ci
40
+
41
+ - name: Verify Environment
42
+ run: |
43
+ node --version
44
+ npm --version
45
+
46
+ # Re-run the full gate on the exact release tag. prepublishOnly also runs
47
+ # on `npm publish`, but failing fast here avoids building a tarball at all.
48
+ - name: Run Syntax & Lint Checks
49
+ run: npm run lint
50
+
51
+ - name: Run Test Suite
52
+ run: npm test
53
+
54
+ - name: Verify Coverage Gates
55
+ run: npm run test:coverage
56
+
57
+ - name: Validate Agentic Architecture
58
+ run: npm run validate
59
+
60
+ - name: Verify version matches the release tag
61
+ if: github.event_name == 'release'
62
+ run: |
63
+ set -euo pipefail
64
+ pkg_version="$(node -p "require('./package.json').version")"
65
+ tag_version="${GITHUB_REF_NAME#v}"
66
+ if [ "$pkg_version" != "$tag_version" ]; then
67
+ echo "::error::package.json version ($pkg_version) does not match release tag ($GITHUB_REF_NAME)"
68
+ exit 1
69
+ fi
70
+ echo "version $pkg_version matches tag $GITHUB_REF_NAME"
71
+
72
+ - name: Inspect the publishable tarball
73
+ run: |
74
+ set -euo pipefail
75
+ npm pack --dry-run
76
+ # Prove the tarball actually carries the files the package promises,
77
+ # rather than trusting the files[] allowlist to be correct.
78
+ # npm writes UTF-16LE on Windows, so parse it as text, not via require.
79
+ npm pack --json > pack.json
80
+ node -e '
81
+ const fs = require("fs");
82
+ let raw = fs.readFileSync("pack.json", "utf-8");
83
+ if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1);
84
+ // npm writes UTF-16LE on Windows, so utf-8 decoding yields NUL
85
+ // padding. Detect it and re-read. Use an escape, never a literal
86
+ // NUL byte: an embedded 0x00 makes git classify this file as
87
+ // binary, which breaks the workflow.
88
+ if (raw.indexOf(String.fromCharCode(0)) !== -1) {
89
+ raw = fs.readFileSync("pack.json", "utf16le");
90
+ if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1);
91
+ }
92
+ const meta = JSON.parse(raw)[0];
93
+ const files = new Set(meta.files.map((f) => f.path));
94
+ const required = [
95
+ "package.json", "README.md", "LICENSE",
96
+ "bin/azcodr.js", "lib/index.js", "lib/index.d.ts", "lib/scaffold.js",
97
+ "scripts/validate.js", "scripts/validate-cli.js"
98
+ ];
99
+ const missing = required.filter((f) => !files.has(f));
100
+ if (missing.length) {
101
+ console.error("::error::missing from tarball: " + missing.join(", "));
102
+ process.exit(1);
103
+ }
104
+ console.log("tarball contains all " + required.length + " required paths");
105
+ '
106
+
107
+ - name: Install the packed tarball and smoke-test the CLI
108
+ run: |
109
+ set -euo pipefail
110
+ # The highest-value missing check: the published artifact must be
111
+ # runnable, not just constructible.
112
+ npm pack > /dev/null
113
+ mkdir -p /tmp/smoke && cd /tmp/smoke
114
+ npm init -y > /dev/null 2>&1
115
+ npm install "$GITHUB_WORKSPACE"/*.tgz --no-audit --no-fund
116
+ npx azcodr --version
117
+ npx azcodr --help > /dev/null
118
+ node -e '
119
+ const api = require("azcodr");
120
+ const required = ["scaffold", "copyTemplate", "validateTarget", "ERROR_CODES", "ScaffoldError"];
121
+ const missing = required.filter((k) => !(k in api));
122
+ if (missing.length) { console.error("missing exports: " + missing.join(", ")); process.exit(1); }
123
+ if (api.ERROR_CODES.E_GIT_BLOCKED !== "Blocked git subcommand") {
124
+ console.error("error-code contract changed unexpectedly");
125
+ process.exit(1);
126
+ }
127
+ console.log("programmatic API surface verified");
128
+ '
129
+
130
+ - name: Scaffold a real project from the packed tarball
131
+ run: |
132
+ set -euo pipefail
133
+ cd /tmp/smoke
134
+ npx azcodr ./generated --force --no-git
135
+ cd ./generated
136
+ npm run validate
137
+
138
+ publish-npm:
139
+ name: Publish to npm
140
+ needs: verify
141
+ runs-on: ubuntu-24.04
142
+ timeout-minutes: 15
143
+ steps:
144
+ - name: Checkout Repository
145
+ uses: actions/checkout@v7
146
+
147
+ - name: Setup Node.js 24.x
148
+ uses: actions/setup-node@v7
149
+ with:
150
+ node-version: 24.x
151
+ registry-url: https://registry.npmjs.org
152
+
153
+ - name: Verify the working tree is clean
154
+ run: |
155
+ set -euo pipefail
156
+ # Publishing from a dirty tree ships files that are not in any tag and
157
+ # cannot be reproduced later.
158
+ if [ -n "$(git status --porcelain)" ]; then
159
+ echo "::error::working tree is dirty; refusing to publish"
160
+ git status --porcelain
161
+ exit 1
162
+ fi
163
+
164
+ - name: Install dependencies
165
+ run: npm ci
166
+
167
+ - name: Re-run the publish gate
168
+ # prepublishOnly fires on npm publish: lint -> coverage -> validate.
169
+ run: npm run lint && npm run test:coverage && npm run validate
170
+
171
+ - name: Dry run (no upload)
172
+ if: inputs.dry-run == true
173
+ run: npm publish --dry-run --access public
174
+
175
+ - name: Publish to npm
176
+ if: inputs.dry-run != true
177
+ run: npm publish --access public --provenance
178
+ env:
179
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
180
+
181
+ publish-jsr:
182
+ name: Publish to JSR
183
+ needs: verify
184
+ # Requires a native ESM entrypoint. The npm package is CommonJS, which JSR
185
+ # explicitly forbids ("You cannot publish CommonJS modules"). Disabled with
186
+ # a stated reason rather than failing every release.
187
+ if: false
188
+ runs-on: ubuntu-24.04
189
+ timeout-minutes: 15
190
+ steps:
191
+ - name: Checkout Repository
192
+ uses: actions/checkout@v7
193
+
194
+ - name: Setup Deno
195
+ uses: denoland/setup-deno@v2
196
+ with:
197
+ deno-version: v2.x
198
+
199
+ - name: Publish to JSR
200
+ run: npx jsr publish