@paths.design/caws-cli 3.2.4 → 3.3.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.js"],"names":[],"mappings":"AAkKA;;;GAGG;AACH,6DA6TC;AAhdD;;;;GAIG;AACH,mDAHW,MAAM;;;GA8HhB;AAMD;;;GAGG;AACH,yDAGC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.js"],"names":[],"mappings":"AAkKA;;;GAGG;AACH,6DA0UC;AA7dD;;;;GAIG;AACH,mDAHW,MAAM;;;GA8HhB;AAMD;;;GAGG;AACH,yDAGC"}
@@ -320,6 +320,19 @@ async function scaffoldProject(options) {
320
320
  });
321
321
  }
322
322
 
323
+ // Add AGENTS.md guide for agent workflow instructions
324
+ if (
325
+ !fs.existsSync(path.join(currentDir, 'agents.md')) &&
326
+ !fs.existsSync(path.join(currentDir, 'AGENTS.md')) &&
327
+ !fs.existsSync(path.join(currentDir, 'caws.md'))
328
+ ) {
329
+ enhancements.push({
330
+ name: 'agents.md',
331
+ description: 'CAWS agent workflow guide',
332
+ required: false,
333
+ });
334
+ }
335
+
323
336
  // Add OIDC setup guide if requested or not minimal
324
337
  if (
325
338
  (options.withOidc || (!options.minimal && !options.withOidc)) &&
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Detect if project is using TypeScript
3
+ * @param {string} projectDir - Project directory path
4
+ * @returns {Object} TypeScript detection result
5
+ */
6
+ export function detectTypeScript(projectDir?: string): any;
7
+ /**
8
+ * Detect testing framework in use
9
+ * @param {string} projectDir - Project directory path
10
+ * @param {Object} packageJson - Parsed package.json (optional)
11
+ * @returns {Object} Testing framework detection result
12
+ */
13
+ export function detectTestFramework(projectDir?: string, packageJson?: any): any;
14
+ /**
15
+ * Check if TypeScript project needs test configuration
16
+ * @param {string} projectDir - Project directory path
17
+ * @returns {Object} Configuration status
18
+ */
19
+ export function checkTypeScriptTestConfig(projectDir?: string): any;
20
+ /**
21
+ * Generate configuration recommendations
22
+ * @param {Object} tsDetection - TypeScript detection result
23
+ * @param {Object} testDetection - Test framework detection result
24
+ * @returns {string[]} Array of recommendations
25
+ */
26
+ export function generateRecommendations(tsDetection: any, testDetection: any): string[];
27
+ /**
28
+ * Display TypeScript detection results
29
+ * @param {Object} detection - Detection result from checkTypeScriptTestConfig
30
+ */
31
+ export function displayTypeScriptDetection(detection: any): void;
32
+ //# sourceMappingURL=typescript-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typescript-detector.d.ts","sourceRoot":"","sources":["../../src/utils/typescript-detector.js"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,8CAHW,MAAM,OAkChB;AAED;;;;;GAKG;AACH,iDAJW,MAAM,0BAkDhB;AAED;;;;GAIG;AACH,uDAHW,MAAM,OAiBhB;AAED;;;;;GAKG;AACH,+EAFa,MAAM,EAAE,CAuBpB;AAED;;;GAGG;AACH,iEAoBC"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * @fileoverview TypeScript Project Detection and Configuration
3
+ * Auto-detects TypeScript projects and configures testing frameworks
4
+ * @author @darianrosebrook
5
+ */
6
+
7
+ const fs = require('fs-extra');
8
+ const path = require('path');
9
+ const chalk = require('chalk');
10
+
11
+ /**
12
+ * Detect if project is using TypeScript
13
+ * @param {string} projectDir - Project directory path
14
+ * @returns {Object} TypeScript detection result
15
+ */
16
+ function detectTypeScript(projectDir = process.cwd()) {
17
+ const tsconfigPath = path.join(projectDir, 'tsconfig.json');
18
+ const packageJsonPath = path.join(projectDir, 'package.json');
19
+
20
+ const hasTsConfig = fs.existsSync(tsconfigPath);
21
+
22
+ let hasTypeScriptDep = false;
23
+ let packageJson = null;
24
+
25
+ if (fs.existsSync(packageJsonPath)) {
26
+ try {
27
+ packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
28
+ const allDeps = {
29
+ ...packageJson.dependencies,
30
+ ...packageJson.devDependencies,
31
+ };
32
+ hasTypeScriptDep = 'typescript' in allDeps;
33
+ } catch (error) {
34
+ // Ignore parse errors
35
+ }
36
+ }
37
+
38
+ const isTypeScript = hasTsConfig || hasTypeScriptDep;
39
+
40
+ return {
41
+ isTypeScript,
42
+ hasTsConfig,
43
+ hasTypeScriptDep,
44
+ packageJson,
45
+ tsconfigPath: hasTsConfig ? tsconfigPath : null,
46
+ };
47
+ }
48
+
49
+ /**
50
+ * Detect testing framework in use
51
+ * @param {string} projectDir - Project directory path
52
+ * @param {Object} packageJson - Parsed package.json (optional)
53
+ * @returns {Object} Testing framework detection result
54
+ */
55
+ function detectTestFramework(projectDir = process.cwd(), packageJson = null) {
56
+ if (!packageJson) {
57
+ const packageJsonPath = path.join(projectDir, 'package.json');
58
+ if (fs.existsSync(packageJsonPath)) {
59
+ packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
60
+ }
61
+ }
62
+
63
+ const hasJestConfig =
64
+ fs.existsSync(path.join(projectDir, 'jest.config.js')) ||
65
+ fs.existsSync(path.join(projectDir, 'jest.config.ts')) ||
66
+ fs.existsSync(path.join(projectDir, 'jest.config.json')) ||
67
+ packageJson?.jest;
68
+
69
+ const hasVitestConfig =
70
+ fs.existsSync(path.join(projectDir, 'vitest.config.js')) ||
71
+ fs.existsSync(path.join(projectDir, 'vitest.config.ts'));
72
+
73
+ const allDeps = {
74
+ ...packageJson?.dependencies,
75
+ ...packageJson?.devDependencies,
76
+ };
77
+
78
+ const hasJestDep = 'jest' in allDeps || '@types/jest' in allDeps;
79
+ const hasVitestDep = 'vitest' in allDeps;
80
+ const hasTsJest = 'ts-jest' in allDeps;
81
+
82
+ let framework = 'none';
83
+ let isConfigured = false;
84
+
85
+ if (hasJestConfig || hasJestDep) {
86
+ framework = 'jest';
87
+ isConfigured = hasJestConfig;
88
+ } else if (hasVitestConfig || hasVitestDep) {
89
+ framework = 'vitest';
90
+ isConfigured = hasVitestConfig;
91
+ }
92
+
93
+ return {
94
+ framework,
95
+ isConfigured,
96
+ hasJest: hasJestDep,
97
+ hasVitest: hasVitestDep,
98
+ hasTsJest,
99
+ needsTypeScriptConfig: false, // Will be set by checkTypeScriptTestConfig
100
+ };
101
+ }
102
+
103
+ /**
104
+ * Check if TypeScript project needs test configuration
105
+ * @param {string} projectDir - Project directory path
106
+ * @returns {Object} Configuration status
107
+ */
108
+ function checkTypeScriptTestConfig(projectDir = process.cwd()) {
109
+ const tsDetection = detectTypeScript(projectDir);
110
+ const testDetection = detectTestFramework(projectDir, tsDetection.packageJson);
111
+
112
+ const needsConfig =
113
+ tsDetection.isTypeScript && testDetection.framework === 'jest' && !testDetection.hasTsJest;
114
+
115
+ return {
116
+ ...tsDetection,
117
+ testFramework: testDetection,
118
+ needsJestConfig: tsDetection.isTypeScript && !testDetection.isConfigured,
119
+ needsTsJest: needsConfig,
120
+ recommendations: generateRecommendations(tsDetection, testDetection),
121
+ };
122
+ }
123
+
124
+ /**
125
+ * Generate configuration recommendations
126
+ * @param {Object} tsDetection - TypeScript detection result
127
+ * @param {Object} testDetection - Test framework detection result
128
+ * @returns {string[]} Array of recommendations
129
+ */
130
+ function generateRecommendations(tsDetection, testDetection) {
131
+ const recommendations = [];
132
+
133
+ if (tsDetection.isTypeScript && testDetection.framework === 'none') {
134
+ recommendations.push('No testing framework detected');
135
+ recommendations.push('Recommended: Install Jest with ts-jest');
136
+ recommendations.push('Run: npm install --save-dev jest @types/jest ts-jest');
137
+ }
138
+
139
+ if (tsDetection.isTypeScript && testDetection.framework === 'jest' && !testDetection.hasTsJest) {
140
+ recommendations.push('Jest detected but missing TypeScript support');
141
+ recommendations.push('Install ts-jest: npm install --save-dev ts-jest');
142
+ recommendations.push('Or run: caws diagnose to auto-configure');
143
+ }
144
+
145
+ if (tsDetection.isTypeScript && !testDetection.isConfigured) {
146
+ recommendations.push('Testing framework not configured');
147
+ recommendations.push('Run: caws scaffold to add test configuration');
148
+ }
149
+
150
+ return recommendations;
151
+ }
152
+
153
+ /**
154
+ * Display TypeScript detection results
155
+ * @param {Object} detection - Detection result from checkTypeScriptTestConfig
156
+ */
157
+ function displayTypeScriptDetection(detection) {
158
+ if (!detection.isTypeScript) {
159
+ return;
160
+ }
161
+
162
+ console.log(chalk.cyan('\n📦 TypeScript Project Detected'));
163
+ console.log(chalk.gray(` tsconfig.json: ${detection.hasTsConfig ? '✅' : '❌'}`));
164
+ console.log(chalk.gray(` typescript dependency: ${detection.hasTypeScriptDep ? '✅' : '❌'}`));
165
+
166
+ if (detection.testFramework.framework !== 'none') {
167
+ console.log(chalk.gray(` Test framework: ${detection.testFramework.framework}`));
168
+ console.log(chalk.gray(` Configured: ${detection.testFramework.isConfigured ? '✅' : '❌'}`));
169
+ }
170
+
171
+ if (detection.recommendations.length > 0) {
172
+ console.log(chalk.yellow('\n💡 Recommendations:'));
173
+ detection.recommendations.forEach((rec) => {
174
+ console.log(chalk.yellow(` ${rec}`));
175
+ });
176
+ }
177
+ }
178
+
179
+ module.exports = {
180
+ detectTypeScript,
181
+ detectTestFramework,
182
+ checkTypeScriptTestConfig,
183
+ generateRecommendations,
184
+ displayTypeScriptDetection,
185
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paths.design/caws-cli",
3
- "version": "3.2.4",
3
+ "version": "3.3.1",
4
4
  "description": "CAWS CLI - Coding Agent Workflow System command line tools",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -52,9 +52,11 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "ajv": "^8.12.0",
55
+ "chalk": "4.1.2",
55
56
  "commander": "^11.0.0",
56
57
  "fs-extra": "^11.0.0",
57
- "inquirer": "8.2.7"
58
+ "inquirer": "8.2.7",
59
+ "js-yaml": "4.1.0"
58
60
  },
59
61
  "devDependencies": {
60
62
  "@eslint/js": "^9.0.0",
@@ -66,10 +68,8 @@
66
68
  "@types/inquirer": "^8.2.6",
67
69
  "@types/js-yaml": "^4.0.0",
68
70
  "@types/node": "^20.0.0",
69
- "chalk": "4.1.2",
70
71
  "eslint": "^9.0.0",
71
72
  "jest": "30.1.3",
72
- "js-yaml": "4.1.0",
73
73
  "lint-staged": "15.5.2",
74
74
  "prettier": "^3.0.0",
75
75
  "semantic-release": "25.0.0-beta.6",
@@ -0,0 +1,300 @@
1
+ # OIDC Trusted Publisher Setup
2
+
3
+ This guide helps you set up OIDC (OpenID Connect) trusted publisher for automated publishing to package registries.
4
+
5
+ ## Overview
6
+
7
+ OIDC trusted publisher allows you to publish packages without storing long-lived tokens or passwords in your CI/CD environment. Instead, it uses short-lived tokens issued by the OIDC provider.
8
+
9
+ ## Supported Registries
10
+
11
+ - **npm**: npm Registry
12
+ - **PyPI**: Python Package Index
13
+ - **Maven Central**: Java packages
14
+ - **NuGet**: .NET packages
15
+
16
+ ## Setup Process
17
+
18
+ ### 1. Configure OIDC Provider
19
+
20
+ Most CI/CD platforms (GitHub Actions, GitLab CI, etc.) provide built-in OIDC support.
21
+
22
+ **GitHub Actions Example:**
23
+
24
+ ```yaml
25
+ # .github/workflows/publish.yml
26
+ name: Publish Package
27
+
28
+ on:
29
+ release:
30
+ types: [published]
31
+
32
+ jobs:
33
+ publish:
34
+ runs-on: ubuntu-latest
35
+ permissions:
36
+ contents: read
37
+ id-token: write
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+ - name: Setup Node.js
41
+ uses: actions/setup-node@v4
42
+ with:
43
+ node-version: '20'
44
+ registry-url: 'https://registry.npmjs.org'
45
+ - name: Install dependencies
46
+ run: npm ci
47
+ - name: Build package
48
+ run: npm run build
49
+ - name: Publish to npm
50
+ run: npm publish
51
+ env:
52
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
53
+ ```
54
+
55
+ ### 2. Registry Configuration
56
+
57
+ #### npm Registry
58
+
59
+ 1. **Create OIDC Integration**:
60
+
61
+ ```bash
62
+ # Using npm CLI
63
+ npm profile enable-2fa auth-and-writes
64
+ ```
65
+
66
+ 2. **Configure Trusted Publisher**:
67
+ - Go to npmjs.com → Account Settings → Access Tokens
68
+ - Create "Automation" token
69
+ - Configure OIDC integration
70
+
71
+ 3. **Repository Settings**:
72
+ ```json
73
+ // package.json
74
+ {
75
+ "publishConfig": {
76
+ "registry": "https://registry.npmjs.org/"
77
+ }
78
+ }
79
+ ```
80
+
81
+ #### PyPI (Python)
82
+
83
+ 1. **Create API Token**:
84
+
85
+ ```bash
86
+ # Using twine
87
+ twine upload --config-file ~/.pypirc dist/*
88
+ ```
89
+
90
+ 2. **OIDC Configuration**:
91
+ ```yaml
92
+ # .github/workflows/publish.yml
93
+ - name: Publish to PyPI
94
+ uses: pypa/gh-action-pypi-publish@release/v1
95
+ with:
96
+ password: ${{ secrets.PYPI_API_TOKEN }}
97
+ ```
98
+
99
+ ### 3. Security Best Practices
100
+
101
+ #### Token Management
102
+
103
+ - ✅ **Use short-lived tokens** (1-6 hours)
104
+ - ✅ **Scope tokens to specific repositories**
105
+ - ✅ **Rotate tokens regularly**
106
+ - ❌ **Never store long-lived tokens in code**
107
+ - ❌ **Never commit tokens to version control**
108
+
109
+ #### Environment Variables
110
+
111
+ ```bash
112
+ # Good: Short-lived, scoped token
113
+ NODE_AUTH_TOKEN=gho_shortlivedtoken123
114
+
115
+ # Bad: Long-lived, broad token
116
+ NPM_TOKEN=longlivedbroadtoken456
117
+ ```
118
+
119
+ #### Repository Secrets
120
+
121
+ Store sensitive tokens in repository secrets:
122
+
123
+ **GitHub**: Settings → Secrets and variables → Actions
124
+ **GitLab**: Settings → CI/CD → Variables
125
+ **Azure DevOps**: Pipelines → Library → Variable groups
126
+
127
+ ### 4. Testing the Setup
128
+
129
+ #### Local Testing
130
+
131
+ ```bash
132
+ # Test with dry run
133
+ npm publish --dry-run
134
+
135
+ # Test with local registry
136
+ npm publish --registry http://localhost:4873
137
+ ```
138
+
139
+ #### CI/CD Testing
140
+
141
+ ```yaml
142
+ # Add to your workflow for testing
143
+ - name: Test publish (dry run)
144
+ run: npm publish --dry-run
145
+ env:
146
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
147
+ ```
148
+
149
+ ### 5. Troubleshooting
150
+
151
+ #### Common Issues
152
+
153
+ **Token Expired**:
154
+
155
+ ```
156
+ npm ERR! code E401
157
+ npm ERR! Unable to authenticate, need: Basic
158
+ ```
159
+
160
+ **Solution**: Check token expiration and refresh if needed.
161
+
162
+ **Insufficient Permissions**:
163
+
164
+ ```
165
+ npm ERR! code E403
166
+ npm ERR! Forbidden
167
+ ```
168
+
169
+ **Solution**: Verify token has publish permissions for the package.
170
+
171
+ **OIDC Provider Issues**:
172
+
173
+ ```
174
+ Error: Failed to get OIDC token
175
+ ```
176
+
177
+ **Solution**: Check OIDC provider configuration and permissions.
178
+
179
+ #### Debug Mode
180
+
181
+ Enable debug logging:
182
+
183
+ ```bash
184
+ # npm
185
+ npm config set loglevel verbose
186
+
187
+ # Python
188
+ export TWINE_VERBOSE=1
189
+
190
+ # Maven
191
+ mvn deploy -X
192
+ ```
193
+
194
+ ### 6. Migration from Legacy Tokens
195
+
196
+ If you're migrating from username/password or long-lived tokens:
197
+
198
+ 1. **Audit existing tokens**:
199
+
200
+ ```bash
201
+ # npm
202
+ npm profile get
203
+
204
+ # List all tokens
205
+ npm token list
206
+ ```
207
+
208
+ 2. **Revoke old tokens**:
209
+
210
+ ```bash
211
+ npm token delete <token-id>
212
+ ```
213
+
214
+ 3. **Update CI/CD workflows**:
215
+ - Replace `NPM_TOKEN` with `NODE_AUTH_TOKEN`
216
+ - Add OIDC permissions
217
+ - Test in staging environment
218
+
219
+ ### 7. Monitoring and Alerts
220
+
221
+ Set up monitoring for:
222
+
223
+ - **Publish failures**: Alert on failed deployments
224
+ - **Token expiration**: Proactive token renewal
225
+ - **Security events**: Unusual publish patterns
226
+ - **Registry status**: External service health
227
+
228
+ #### Example Monitoring
229
+
230
+ ```yaml
231
+ # .github/workflows/monitor.yml
232
+ name: Monitor Publishing
233
+
234
+ on:
235
+ workflow_run:
236
+ workflows: ['Publish Package']
237
+ types: [completed]
238
+
239
+ jobs:
240
+ monitor:
241
+ runs-on: ubuntu-latest
242
+ steps:
243
+ - name: Check publish status
244
+ if: ${{ github.event.workflow_run.conclusion == 'failure' }}
245
+ run: |
246
+ echo "Publish failed! Check logs."
247
+ # Send alert to Slack/Teams/etc.
248
+ ```
249
+
250
+ ## CAWS Integration
251
+
252
+ For CAWS projects, OIDC setup integrates with:
253
+
254
+ - **Provenance tracking**: Automatic attestation of published packages
255
+ - **Security scanning**: Validation of published artifacts
256
+ - **Quality gates**: Ensure packages meet standards before publish
257
+
258
+ ### CAWS-Specific Configuration
259
+
260
+ ```yaml
261
+ # .caws/working-spec.yaml
262
+ non_functional:
263
+ security:
264
+ - 'oidc-authentication'
265
+ - 'token-rotation'
266
+ - 'publish-attestation'
267
+ ```
268
+
269
+ ### Automated Provenance
270
+
271
+ CAWS automatically generates provenance information:
272
+
273
+ ```bash
274
+ # Generate SBOM and attestation
275
+ caws attest --format=slsa
276
+
277
+ # Validate before publish
278
+ caws validate --security-scan
279
+ ```
280
+
281
+ ## Resources
282
+
283
+ - [npm OIDC Documentation](https://docs.npmjs.com/about-access-tokens)
284
+ - [GitHub Actions OIDC](https://docs.github.com/en/actions/deployment/security/hardening-your-deployments/about-security-hardening-with-openid-connect)
285
+ - [PyPI Trusted Publishing](https://docs.pypi.org/trusted-publishing/)
286
+ - [OIDC Specification](https://openid.net/connect/)
287
+
288
+ ## Support
289
+
290
+ For issues with OIDC setup:
291
+
292
+ 1. Check the troubleshooting section above
293
+ 2. Review registry-specific documentation
294
+ 3. Open an issue in the CAWS repository
295
+ 4. Contact your organization's security team
296
+
297
+ ---
298
+
299
+ **Note**: This guide provides general OIDC setup instructions. Always follow your organization's specific security policies and procedures.
300
+