@stackbilt/cli 0.7.0 → 0.9.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 (71) hide show
  1. package/dist/__tests__/adf-context.test.d.ts +2 -0
  2. package/dist/__tests__/adf-context.test.d.ts.map +1 -0
  3. package/dist/__tests__/adf-context.test.js +60 -0
  4. package/dist/__tests__/adf-context.test.js.map +1 -0
  5. package/dist/__tests__/integration/evidence-contracts.test.js +15 -15
  6. package/dist/__tests__/integration/precommit-hook.test.js +45 -45
  7. package/dist/__tests__/integration/sync-bundle.test.js +31 -31
  8. package/dist/__tests__/integration/vendor-bloat.test.js +74 -74
  9. package/dist/commands/adf-context.d.ts +14 -0
  10. package/dist/commands/adf-context.d.ts.map +1 -0
  11. package/dist/commands/adf-context.js +149 -0
  12. package/dist/commands/adf-context.js.map +1 -0
  13. package/dist/commands/adf-migrate.d.ts +11 -1
  14. package/dist/commands/adf-migrate.d.ts.map +1 -1
  15. package/dist/commands/adf-migrate.js +176 -10
  16. package/dist/commands/adf-migrate.js.map +1 -1
  17. package/dist/commands/adf-populate.d.ts +12 -0
  18. package/dist/commands/adf-populate.d.ts.map +1 -0
  19. package/dist/commands/adf-populate.js +362 -0
  20. package/dist/commands/adf-populate.js.map +1 -0
  21. package/dist/commands/adf-sync.d.ts.map +1 -1
  22. package/dist/commands/adf-sync.js +3 -0
  23. package/dist/commands/adf-sync.js.map +1 -1
  24. package/dist/commands/adf-tidy.d.ts.map +1 -1
  25. package/dist/commands/adf-tidy.js +38 -1
  26. package/dist/commands/adf-tidy.js.map +1 -1
  27. package/dist/commands/adf.d.ts +8 -1
  28. package/dist/commands/adf.d.ts.map +1 -1
  29. package/dist/commands/adf.js +120 -11
  30. package/dist/commands/adf.js.map +1 -1
  31. package/dist/commands/architect.d.ts +12 -0
  32. package/dist/commands/architect.d.ts.map +1 -0
  33. package/dist/commands/architect.js +161 -0
  34. package/dist/commands/architect.js.map +1 -0
  35. package/dist/commands/bootstrap.d.ts.map +1 -1
  36. package/dist/commands/bootstrap.js +26 -12
  37. package/dist/commands/bootstrap.js.map +1 -1
  38. package/dist/commands/doctor.d.ts.map +1 -1
  39. package/dist/commands/doctor.js +16 -1
  40. package/dist/commands/doctor.js.map +1 -1
  41. package/dist/commands/login.d.ts +10 -0
  42. package/dist/commands/login.d.ts.map +1 -0
  43. package/dist/commands/login.js +64 -0
  44. package/dist/commands/login.js.map +1 -0
  45. package/dist/commands/run.d.ts +18 -0
  46. package/dist/commands/run.d.ts.map +1 -0
  47. package/dist/commands/run.js +238 -0
  48. package/dist/commands/run.js.map +1 -0
  49. package/dist/commands/scaffold.d.ts +11 -0
  50. package/dist/commands/scaffold.d.ts.map +1 -0
  51. package/dist/commands/scaffold.js +110 -0
  52. package/dist/commands/scaffold.js.map +1 -0
  53. package/dist/commands/setup.d.ts.map +1 -1
  54. package/dist/commands/setup.js +25 -2
  55. package/dist/commands/setup.js.map +1 -1
  56. package/dist/credentials.d.ts +13 -0
  57. package/dist/credentials.d.ts.map +1 -0
  58. package/dist/credentials.js +74 -0
  59. package/dist/credentials.js.map +1 -0
  60. package/dist/git-helpers.d.ts +7 -7
  61. package/dist/git-helpers.d.ts.map +1 -1
  62. package/dist/git-helpers.js +7 -8
  63. package/dist/git-helpers.js.map +1 -1
  64. package/dist/http-client.d.ts +105 -0
  65. package/dist/http-client.d.ts.map +1 -0
  66. package/dist/http-client.js +68 -0
  67. package/dist/http-client.js.map +1 -0
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +24 -0
  70. package/dist/index.js.map +1 -1
  71. package/package.json +11 -10
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adf-context.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adf-context.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/adf-context.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const adf_context_1 = require("../commands/adf-context");
5
+ (0, vitest_1.describe)('filePathToKeywords', () => {
6
+ (0, vitest_1.it)('extracts react/frontend keywords from .tsx files', () => {
7
+ const kw = (0, adf_context_1.filePathToKeywords)(['src/components/Button.tsx']);
8
+ (0, vitest_1.expect)(kw).toContain('react');
9
+ (0, vitest_1.expect)(kw).toContain('frontend');
10
+ });
11
+ (0, vitest_1.it)('extracts css/frontend keywords from .css files', () => {
12
+ const kw = (0, adf_context_1.filePathToKeywords)(['src/styles/main.css']);
13
+ (0, vitest_1.expect)(kw).toContain('css');
14
+ (0, vitest_1.expect)(kw).toContain('frontend');
15
+ });
16
+ (0, vitest_1.it)('extracts api/backend keywords from api directory paths', () => {
17
+ const kw = (0, adf_context_1.filePathToKeywords)(['src/api/handler.ts']);
18
+ (0, vitest_1.expect)(kw).toContain('api');
19
+ (0, vitest_1.expect)(kw).toContain('backend');
20
+ });
21
+ (0, vitest_1.it)('extracts test/qa keywords from test directory paths', () => {
22
+ const kw = (0, adf_context_1.filePathToKeywords)(['src/__tests__/foo.test.ts']);
23
+ (0, vitest_1.expect)(kw).toContain('test');
24
+ (0, vitest_1.expect)(kw).toContain('qa');
25
+ });
26
+ (0, vitest_1.it)('extracts deploy/infra keywords from infra directories', () => {
27
+ const kw = (0, adf_context_1.filePathToKeywords)(['deploy/Dockerfile']);
28
+ (0, vitest_1.expect)(kw).toContain('deploy');
29
+ (0, vitest_1.expect)(kw).toContain('infra');
30
+ });
31
+ (0, vitest_1.it)('extracts auth/security keywords from auth directories', () => {
32
+ const kw = (0, adf_context_1.filePathToKeywords)(['src/auth/session.ts']);
33
+ (0, vitest_1.expect)(kw).toContain('auth');
34
+ (0, vitest_1.expect)(kw).toContain('security');
35
+ });
36
+ (0, vitest_1.it)('extracts db/backend keywords from .prisma files', () => {
37
+ const kw = (0, adf_context_1.filePathToKeywords)(['prisma/schema.prisma']);
38
+ (0, vitest_1.expect)(kw).toContain('db');
39
+ (0, vitest_1.expect)(kw).toContain('backend');
40
+ });
41
+ (0, vitest_1.it)('deduplicates keywords across multiple files', () => {
42
+ const kw = (0, adf_context_1.filePathToKeywords)(['src/components/A.tsx', 'src/components/B.tsx']);
43
+ const reactCount = kw.filter(k => k === 'react').length;
44
+ (0, vitest_1.expect)(reactCount).toBe(1);
45
+ });
46
+ (0, vitest_1.it)('returns empty array for unknown file types and directories', () => {
47
+ const kw = (0, adf_context_1.filePathToKeywords)(['README.md']);
48
+ (0, vitest_1.expect)(kw).toHaveLength(0);
49
+ });
50
+ (0, vitest_1.it)('extracts cloudflare/deploy keywords from wrangler.toml', () => {
51
+ const kw = (0, adf_context_1.filePathToKeywords)(['wrangler.toml']);
52
+ (0, vitest_1.expect)(kw).toContain('deploy');
53
+ (0, vitest_1.expect)(kw).toContain('cloudflare');
54
+ });
55
+ (0, vitest_1.it)('handles component directory signal', () => {
56
+ const kw = (0, adf_context_1.filePathToKeywords)(['src/ui/widget/DatePicker.ts']);
57
+ (0, vitest_1.expect)(kw).toContain('frontend');
58
+ });
59
+ });
60
+ //# sourceMappingURL=adf-context.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adf-context.test.js","sourceRoot":"","sources":["../../src/__tests__/adf-context.test.ts"],"names":[],"mappings":"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"}
@@ -77,22 +77,22 @@ const ciOptions = {
77
77
  function writeEvidenceFixture(tmp, actualLines, baseline, ceiling) {
78
78
  fs.mkdirSync(path.join(tmp, '.ai'), { recursive: true });
79
79
  fs.mkdirSync(path.join(tmp, 'src'), { recursive: true });
80
- fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
81
-
82
- 📦 DEFAULT_LOAD:
83
- - core.adf
84
- - state.adf
85
-
86
- 💰 BUDGET:
87
- MAX_TOKENS: 4000
88
-
89
- 📊 METRICS:
90
- APP_LOC: src/app.ts
80
+ fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
81
+
82
+ 📦 DEFAULT_LOAD:
83
+ - core.adf
84
+ - state.adf
85
+
86
+ 💰 BUDGET:
87
+ MAX_TOKENS: 4000
88
+
89
+ 📊 METRICS:
90
+ APP_LOC: src/app.ts
91
91
  `);
92
- fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
93
-
94
- 📊 METRICS:
95
- app_loc: ${baseline} / ${ceiling} [lines]
92
+ fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
93
+
94
+ 📊 METRICS:
95
+ app_loc: ${baseline} / ${ceiling} [lines]
96
96
  `);
97
97
  fs.writeFileSync(path.join(tmp, '.ai', 'state.adf'), 'ADF: 0.1\n\n📋 STATE:\n - CURRENT: testing\n');
98
98
  // Write a source file with exactly `actualLines` lines
@@ -77,39 +77,39 @@ function writeHookFixtureRepo(tmp) {
77
77
  // ADF structure
78
78
  fs.mkdirSync(path.join(tmp, '.ai'), { recursive: true });
79
79
  fs.mkdirSync(path.join(tmp, '.charter'), { recursive: true });
80
- fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
81
-
82
- 📦 DEFAULT_LOAD:
83
- - core.adf
84
- - state.adf
85
-
86
- 📂 ON_DEMAND:
87
- - backend.adf (Triggers on: database, API, migration)
88
-
89
- 💰 BUDGET:
90
- MAX_TOKENS: 4000
80
+ fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
81
+
82
+ 📦 DEFAULT_LOAD:
83
+ - core.adf
84
+ - state.adf
85
+
86
+ 📂 ON_DEMAND:
87
+ - backend.adf (Triggers on: database, API, migration)
88
+
89
+ 💰 BUDGET:
90
+ MAX_TOKENS: 4000
91
91
  `);
92
- fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
93
-
94
- 📐 RULES:
95
- - All changes require tests
92
+ fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
93
+
94
+ 📐 RULES:
95
+ - All changes require tests
96
96
  `);
97
97
  fs.writeFileSync(path.join(tmp, '.ai', 'state.adf'), 'ADF: 0.1\n\n📋 STATE:\n - CURRENT: testing\n');
98
- fs.writeFileSync(path.join(tmp, '.ai', 'backend.adf'), `ADF: 0.1
99
-
100
- 📐 RULES:
101
- - Database access through repository pattern
98
+ fs.writeFileSync(path.join(tmp, '.ai', 'backend.adf'), `ADF: 0.1
99
+
100
+ 📐 RULES:
101
+ - Database access through repository pattern
102
102
  `);
103
103
  // Clean thin pointer
104
- fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), `# CLAUDE.md
105
-
106
- > **DO NOT add rules, constraints, or context to this file.**
107
- > This file is auto-managed by Charter. All project rules live in \`.ai/\`.
108
- > New rules should be added to the appropriate \`.ai/*.adf\` module.
109
- > See \`.ai/manifest.adf\` for the module routing manifest.
110
-
111
- ## Environment
112
- - Node 20
104
+ fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), `# CLAUDE.md
105
+
106
+ > **DO NOT add rules, constraints, or context to this file.**
107
+ > This file is auto-managed by Charter. All project rules live in \`.ai/\`.
108
+ > New rules should be added to the appropriate \`.ai/*.adf\` module.
109
+ > See \`.ai/manifest.adf\` for the module routing manifest.
110
+
111
+ ## Environment
112
+ - Node 20
113
113
  `);
114
114
  // Pre-commit hook — simplified version that just runs tidy
115
115
  const hookDir = path.join(tmp, '.githooks');
@@ -174,15 +174,15 @@ function writeHookFixtureRepo(tmp) {
174
174
  const tmp = makeTempDir('hook-tidy');
175
175
  writeHookFixtureRepo(tmp);
176
176
  // Inject bloat into CLAUDE.md
177
- const bloatedContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8') + `
178
- ## Architecture
179
- - Layered architecture with repository pattern
180
- - All database queries go through the repository layer
181
- - API endpoints validate input before processing
182
-
183
- ## Database Rules
184
- - All database migrations must be reversible
185
- - Schema changes require migration scripts
177
+ const bloatedContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8') + `
178
+ ## Architecture
179
+ - Layered architecture with repository pattern
180
+ - All database queries go through the repository layer
181
+ - API endpoints validate input before processing
182
+
183
+ ## Database Rules
184
+ - All database migrations must be reversible
185
+ - Schema changes require migration scripts
186
186
  `;
187
187
  fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), bloatedContent);
188
188
  // Stage and commit — hook should auto-tidy
@@ -214,9 +214,9 @@ function writeHookFixtureRepo(tmp) {
214
214
  const tmp = makeTempDir('hook-skip');
215
215
  writeHookFixtureRepo(tmp);
216
216
  // Inject bloat
217
- const bloatedContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8') + `
218
- ## Architecture
219
- - Layered architecture pattern
217
+ const bloatedContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8') + `
218
+ ## Architecture
219
+ - Layered architecture pattern
220
220
  `;
221
221
  fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), bloatedContent);
222
222
  // Stage and commit with skip flag
@@ -241,11 +241,11 @@ function writeHookFixtureRepo(tmp) {
241
241
  const tmp = makeTempDir('hook-restage');
242
242
  writeHookFixtureRepo(tmp);
243
243
  // Inject bloat with trigger keywords that route to backend.adf
244
- const bloatedContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8') + `
245
- ## Database Rules
246
- - All database migrations must be reversible
247
- - Schema changes require migration scripts
248
- - API rate limiting applies to all database endpoints
244
+ const bloatedContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8') + `
245
+ ## Database Rules
246
+ - All database migrations must be reversible
247
+ - Schema changes require migration scripts
248
+ - API rate limiting applies to all database endpoints
249
249
  `;
250
250
  fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), bloatedContent);
251
251
  // Record pre-commit state of backend.adf
@@ -67,48 +67,48 @@ const jsonOptions = {
67
67
  /** Write a minimal ADF repo with SYNC entries */
68
68
  function writeSyncFixture(tmp) {
69
69
  fs.mkdirSync(path.join(tmp, '.ai'), { recursive: true });
70
- fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
71
-
72
- 📦 DEFAULT_LOAD:
73
- - core.adf
74
- - state.adf
75
-
76
- 🔄 SYNC:
77
- - core.adf -> CLAUDE.md
70
+ fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
71
+
72
+ 📦 DEFAULT_LOAD:
73
+ - core.adf
74
+ - state.adf
75
+
76
+ 🔄 SYNC:
77
+ - core.adf -> CLAUDE.md
78
78
  `);
79
- fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
80
-
81
- 📐 RULES:
82
- - All changes require tests
79
+ fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
80
+
81
+ 📐 RULES:
82
+ - All changes require tests
83
83
  `);
84
84
  fs.writeFileSync(path.join(tmp, '.ai', 'state.adf'), 'ADF: 0.1\n\n📋 STATE:\n - CURRENT: testing\n');
85
85
  }
86
86
  /** Write a bundle fixture with on-demand modules */
87
87
  function writeBundleFixture(tmp, opts = {}) {
88
88
  fs.mkdirSync(path.join(tmp, '.ai'), { recursive: true });
89
- fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
90
-
91
- 📦 DEFAULT_LOAD:
92
- - core.adf
93
- - state.adf
94
-
95
- 📂 ON_DEMAND:
96
- - backend.adf (Triggers on: database, API, migration)
97
-
98
- 💰 BUDGET:
99
- MAX_TOKENS: 4000
89
+ fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
90
+
91
+ 📦 DEFAULT_LOAD:
92
+ - core.adf
93
+ - state.adf
94
+
95
+ 📂 ON_DEMAND:
96
+ - backend.adf (Triggers on: database, API, migration)
97
+
98
+ 💰 BUDGET:
99
+ MAX_TOKENS: 4000
100
100
  `);
101
- fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
102
-
103
- 📐 RULES:
104
- - All changes require tests
101
+ fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
102
+
103
+ 📐 RULES:
104
+ - All changes require tests
105
105
  `);
106
106
  fs.writeFileSync(path.join(tmp, '.ai', 'state.adf'), 'ADF: 0.1\n\n📋 STATE:\n - CURRENT: testing\n');
107
107
  if (opts.includeOnDemandFile) {
108
- fs.writeFileSync(path.join(tmp, '.ai', 'backend.adf'), `ADF: 0.1
109
-
110
- 📐 RULES:
111
- - Database access through repository pattern
108
+ fs.writeFileSync(path.join(tmp, '.ai', 'backend.adf'), `ADF: 0.1
109
+
110
+ 📐 RULES:
111
+ - Database access through repository pattern
112
112
  `);
113
113
  }
114
114
  }
@@ -78,61 +78,61 @@ const ciOptions = {
78
78
  function writeFixtureRepo(tmp) {
79
79
  fs.mkdirSync(path.join(tmp, '.ai'), { recursive: true });
80
80
  fs.mkdirSync(path.join(tmp, '.charter'), { recursive: true });
81
- fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
82
-
83
- 📐 RULES:
84
- - Test manifest
85
-
86
- 📦 DEFAULT_LOAD:
87
- - core.adf
88
- - state.adf
89
-
90
- 📂 ON_DEMAND:
91
- - backend.adf (Triggers on: database, API, migration, schema)
92
- - frontend.adf (Triggers on: component, React, CSS, layout)
93
-
94
- 💰 BUDGET:
95
- MAX_TOKENS: 4000
81
+ fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
82
+
83
+ 📐 RULES:
84
+ - Test manifest
85
+
86
+ 📦 DEFAULT_LOAD:
87
+ - core.adf
88
+ - state.adf
89
+
90
+ 📂 ON_DEMAND:
91
+ - backend.adf (Triggers on: database, API, migration, schema)
92
+ - frontend.adf (Triggers on: component, React, CSS, layout)
93
+
94
+ 💰 BUDGET:
95
+ MAX_TOKENS: 4000
96
96
  `);
97
- fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
98
-
99
- 📁 STRUCTURE:
100
- - src/ — source code
101
-
102
- 📐 CONSTRAINTS: [load-bearing]
103
- - All changes require tests
97
+ fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
98
+
99
+ 📁 STRUCTURE:
100
+ - src/ — source code
101
+
102
+ 📐 CONSTRAINTS: [load-bearing]
103
+ - All changes require tests
104
104
  `);
105
- fs.writeFileSync(path.join(tmp, '.ai', 'state.adf'), `ADF: 0.1
106
-
107
- 📋 STATE:
108
- - CURRENT: testing
105
+ fs.writeFileSync(path.join(tmp, '.ai', 'state.adf'), `ADF: 0.1
106
+
107
+ 📋 STATE:
108
+ - CURRENT: testing
109
109
  `);
110
110
  // On-demand module stubs (so doctor doesn't warn about missing modules)
111
- fs.writeFileSync(path.join(tmp, '.ai', 'backend.adf'), `ADF: 0.1
112
-
113
- 📐 RULES:
114
- - Database access goes through repository layer
111
+ fs.writeFileSync(path.join(tmp, '.ai', 'backend.adf'), `ADF: 0.1
112
+
113
+ 📐 RULES:
114
+ - Database access goes through repository layer
115
115
  `);
116
- fs.writeFileSync(path.join(tmp, '.ai', 'frontend.adf'), `ADF: 0.1
117
-
118
- 📐 RULES:
119
- - Components use .tsx extension
116
+ fs.writeFileSync(path.join(tmp, '.ai', 'frontend.adf'), `ADF: 0.1
117
+
118
+ 📐 RULES:
119
+ - Components use .tsx extension
120
120
  `);
121
121
  // Init git repo so doctor's git check passes
122
122
  (0, node_child_process_1.execFileSync)('git', ['init'], { cwd: tmp, stdio: 'ignore' });
123
123
  }
124
124
  /** Write a clean thin-pointer CLAUDE.md */
125
125
  function writeCleanPointer(tmp) {
126
- fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), `# CLAUDE.md
127
-
128
- > **DO NOT add rules, constraints, or context to this file.**
129
- > This file is auto-managed by Charter. All project rules live in \`.ai/\`.
130
- > New rules should be added to the appropriate \`.ai/*.adf\` module.
131
- > See \`.ai/manifest.adf\` for the module routing manifest.
132
-
133
- ## Environment
134
- - Node 20
135
- - pnpm 9
126
+ fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), `# CLAUDE.md
127
+
128
+ > **DO NOT add rules, constraints, or context to this file.**
129
+ > This file is auto-managed by Charter. All project rules live in \`.ai/\`.
130
+ > New rules should be added to the appropriate \`.ai/*.adf\` module.
131
+ > See \`.ai/manifest.adf\` for the module routing manifest.
132
+
133
+ ## Environment
134
+ - Node 20
135
+ - pnpm 9
136
136
  `);
137
137
  }
138
138
  /**
@@ -140,36 +140,36 @@ function writeCleanPointer(tmp) {
140
140
  * architecture rules, trigger-heavy content, and non-Environment H2s.
141
141
  */
142
142
  function writeBloatedPointer(tmp) {
143
- fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), `# CLAUDE.md
144
-
145
- > **DO NOT add rules, constraints, or context to this file.**
146
- > This file is auto-managed by Charter. All project rules live in \`.ai/\`.
147
- > New rules should be added to the appropriate \`.ai/*.adf\` module.
148
- > See \`.ai/manifest.adf\` for the module routing manifest.
149
-
150
- ## Environment
151
- - Node 20
152
- - pnpm 9
153
-
154
- ## Architecture
155
- - The project uses a layered architecture pattern
156
- - All database queries go through the repository layer
157
- - API endpoints must validate input before processing
158
-
159
- ## Build Commands
160
- - Run \`pnpm build\` for production
161
- - Run \`pnpm test\` for the test suite
162
-
163
- ## Database Rules
164
- - All database migrations must be reversible
165
- - Schema changes require migration scripts
166
- - Database connections use connection pooling
167
- - API rate limiting applies to all database endpoints
168
-
169
- ## Frontend Standards
170
- - All React component files use .tsx extension
171
- - CSS modules for component-scoped styles
172
- - Layout components handle responsive breakpoints
143
+ fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), `# CLAUDE.md
144
+
145
+ > **DO NOT add rules, constraints, or context to this file.**
146
+ > This file is auto-managed by Charter. All project rules live in \`.ai/\`.
147
+ > New rules should be added to the appropriate \`.ai/*.adf\` module.
148
+ > See \`.ai/manifest.adf\` for the module routing manifest.
149
+
150
+ ## Environment
151
+ - Node 20
152
+ - pnpm 9
153
+
154
+ ## Architecture
155
+ - The project uses a layered architecture pattern
156
+ - All database queries go through the repository layer
157
+ - API endpoints must validate input before processing
158
+
159
+ ## Build Commands
160
+ - Run \`pnpm build\` for production
161
+ - Run \`pnpm test\` for the test suite
162
+
163
+ ## Database Rules
164
+ - All database migrations must be reversible
165
+ - Schema changes require migration scripts
166
+ - Database connections use connection pooling
167
+ - API rate limiting applies to all database endpoints
168
+
169
+ ## Frontend Standards
170
+ - All React component files use .tsx extension
171
+ - CSS modules for component-scoped styles
172
+ - Layout components handle responsive breakpoints
173
173
  `);
174
174
  }
175
175
  /** Capture console.log output during a command invocation */
@@ -0,0 +1,14 @@
1
+ /**
2
+ * charter adf context
3
+ *
4
+ * Resolves ADF modules based on file paths and/or explicit keywords.
5
+ * Outputs the resolved module list and optionally the bundled context.
6
+ */
7
+ import type { CLIOptions } from '../index';
8
+ /**
9
+ * Extract keywords from file paths using extension and directory signals.
10
+ * Maps file system structure to domain keywords for module resolution.
11
+ */
12
+ export declare function filePathToKeywords(filePaths: string[]): string[];
13
+ export declare function adfContextCommand(options: CLIOptions, args: string[]): number;
14
+ //# sourceMappingURL=adf-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adf-context.d.ts","sourceRoot":"","sources":["../../src/commands/adf-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAI3C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAqBhE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CA0E7E"}
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ /**
3
+ * charter adf context
4
+ *
5
+ * Resolves ADF modules based on file paths and/or explicit keywords.
6
+ * Outputs the resolved module list and optionally the bundled context.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.filePathToKeywords = filePathToKeywords;
43
+ exports.adfContextCommand = adfContextCommand;
44
+ const fs = __importStar(require("node:fs"));
45
+ const path = __importStar(require("node:path"));
46
+ const adf_1 = require("@stackbilt/adf");
47
+ const index_1 = require("../index");
48
+ const flags_1 = require("../flags");
49
+ /**
50
+ * Extract keywords from file paths using extension and directory signals.
51
+ * Maps file system structure to domain keywords for module resolution.
52
+ */
53
+ function filePathToKeywords(filePaths) {
54
+ const keywords = [];
55
+ for (const fp of filePaths) {
56
+ const ext = path.extname(fp).slice(1).toLowerCase();
57
+ const dir = path.dirname(fp).toLowerCase();
58
+ // Extension signals
59
+ if (['tsx', 'jsx'].includes(ext))
60
+ keywords.push('react', 'ui', 'frontend');
61
+ if (['css', 'scss', 'sass', 'less'].includes(ext))
62
+ keywords.push('css', 'ui', 'frontend');
63
+ if (['prisma'].includes(ext))
64
+ keywords.push('db', 'backend');
65
+ if (['sql'].includes(ext))
66
+ keywords.push('db', 'migration');
67
+ if (ext === 'toml' && fp.includes('wrangler'))
68
+ keywords.push('deploy', 'cloudflare');
69
+ // Directory signals
70
+ if (/\b(component|ui|widget|page|layout|view)\b/.test(dir))
71
+ keywords.push('frontend', 'ui');
72
+ if (/\b(api|server|handler|route|middleware|controller)\b/.test(dir))
73
+ keywords.push('api', 'backend');
74
+ if (/\b(test|spec|__tests__|e2e)\b/.test(dir))
75
+ keywords.push('test', 'qa');
76
+ if (/\b(deploy|infra|docker|ci|\.github)\b/.test(dir))
77
+ keywords.push('deploy', 'infra');
78
+ if (/\b(auth|session|permission)\b/.test(dir))
79
+ keywords.push('auth', 'security');
80
+ }
81
+ return [...new Set(keywords)];
82
+ }
83
+ function adfContextCommand(options, args) {
84
+ const filesFlag = (0, flags_1.getFlag)(args, '--files');
85
+ const keywordsFlag = (0, flags_1.getFlag)(args, '--keywords');
86
+ const aiDir = (0, flags_1.getFlag)(args, '--ai-dir') || '.ai';
87
+ const bundle = args.includes('--bundle');
88
+ if (!filesFlag && !keywordsFlag) {
89
+ throw new index_1.CLIError('adf context requires --files <path,...> and/or --keywords <kw,...>.\n' +
90
+ 'Usage: charter adf context --files src/components/Button.tsx,src/api/handler.ts');
91
+ }
92
+ const manifestPath = path.join(aiDir, 'manifest.adf');
93
+ if (!fs.existsSync(manifestPath)) {
94
+ throw new index_1.CLIError(`manifest.adf not found at ${manifestPath}. Run: charter adf init`);
95
+ }
96
+ // Collect keywords from both sources
97
+ const allKeywords = [];
98
+ if (filesFlag) {
99
+ const filePaths = filesFlag.split(',').map(f => f.trim()).filter(Boolean);
100
+ allKeywords.push(...filePathToKeywords(filePaths));
101
+ }
102
+ if (keywordsFlag) {
103
+ allKeywords.push(...(0, flags_1.tokenizeTask)(keywordsFlag));
104
+ }
105
+ const dedupKeywords = [...new Set(allKeywords)];
106
+ const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
107
+ const manifestDoc = (0, adf_1.parseAdf)(manifestContent);
108
+ const manifest = (0, adf_1.parseManifest)(manifestDoc);
109
+ const resolvedModules = (0, adf_1.resolveModules)(manifest, dedupKeywords);
110
+ if (bundle) {
111
+ // Full bundle output
112
+ const readFile = (modulePath) => {
113
+ const fullPath = path.join(aiDir, modulePath);
114
+ return fs.readFileSync(fullPath, 'utf-8');
115
+ };
116
+ const result = (0, adf_1.bundleModules)(aiDir, resolvedModules, readFile, dedupKeywords, manifest);
117
+ if (options.format === 'json') {
118
+ console.log(JSON.stringify({
119
+ keywords: dedupKeywords,
120
+ resolvedModules: result.resolvedModules,
121
+ tokenEstimate: result.tokenEstimate,
122
+ triggerMatches: result.triggerMatches,
123
+ content: (0, adf_1.formatAdf)(result.mergedDocument),
124
+ }, null, 2));
125
+ }
126
+ else {
127
+ console.log((0, adf_1.formatAdf)(result.mergedDocument));
128
+ }
129
+ }
130
+ else {
131
+ // Module list only
132
+ if (options.format === 'json') {
133
+ console.log(JSON.stringify({
134
+ keywords: dedupKeywords,
135
+ resolvedModules,
136
+ }, null, 2));
137
+ }
138
+ else {
139
+ console.log(` Keywords: ${dedupKeywords.join(', ')}`);
140
+ console.log(` Resolved modules:`);
141
+ for (const mod of resolvedModules) {
142
+ const isDefault = manifest.defaultLoad.includes(mod);
143
+ console.log(` ${mod} (${isDefault ? 'DEFAULT' : 'ON_DEMAND'})`);
144
+ }
145
+ }
146
+ }
147
+ return index_1.EXIT_CODE.SUCCESS;
148
+ }
149
+ //# sourceMappingURL=adf-context.js.map