@nathapp/nax 0.50.3 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/nax.js +393 -197
- package/package.json +1 -3
- package/bin/nax.ts +0 -1195
- package/src/acceptance/fix-generator.ts +0 -322
- package/src/acceptance/generator.ts +0 -415
- package/src/acceptance/index.ts +0 -42
- package/src/acceptance/refinement.ts +0 -224
- package/src/acceptance/templates/cli.ts +0 -47
- package/src/acceptance/templates/component.ts +0 -78
- package/src/acceptance/templates/e2e.ts +0 -43
- package/src/acceptance/templates/index.ts +0 -21
- package/src/acceptance/templates/snapshot.ts +0 -50
- package/src/acceptance/templates/unit.ts +0 -48
- package/src/acceptance/types.ts +0 -138
- package/src/agents/acp/adapter.ts +0 -888
- package/src/agents/acp/cost.ts +0 -9
- package/src/agents/acp/index.ts +0 -7
- package/src/agents/acp/interaction-bridge.ts +0 -126
- package/src/agents/acp/parser.ts +0 -119
- package/src/agents/acp/spawn-client.ts +0 -373
- package/src/agents/acp/types.ts +0 -22
- package/src/agents/aider/adapter.ts +0 -135
- package/src/agents/claude/adapter.ts +0 -258
- package/src/agents/claude/complete.ts +0 -80
- package/src/agents/claude/cost.ts +0 -16
- package/src/agents/claude/execution.ts +0 -215
- package/src/agents/claude/index.ts +0 -3
- package/src/agents/claude/interactive.ts +0 -77
- package/src/agents/claude/plan.ts +0 -179
- package/src/agents/codex/adapter.ts +0 -153
- package/src/agents/cost/calculate.ts +0 -154
- package/src/agents/cost/index.ts +0 -10
- package/src/agents/cost/parse.ts +0 -97
- package/src/agents/cost/pricing.ts +0 -59
- package/src/agents/cost/types.ts +0 -45
- package/src/agents/gemini/adapter.ts +0 -177
- package/src/agents/index.ts +0 -18
- package/src/agents/opencode/adapter.ts +0 -106
- package/src/agents/registry.ts +0 -136
- package/src/agents/shared/decompose.ts +0 -154
- package/src/agents/shared/model-resolution.ts +0 -43
- package/src/agents/shared/types-extended.ts +0 -164
- package/src/agents/shared/validation.ts +0 -69
- package/src/agents/shared/version-detection.ts +0 -109
- package/src/agents/types.ts +0 -205
- package/src/analyze/classifier.ts +0 -282
- package/src/analyze/index.ts +0 -16
- package/src/analyze/scanner.ts +0 -171
- package/src/analyze/types.ts +0 -51
- package/src/cli/accept.ts +0 -108
- package/src/cli/agents.ts +0 -87
- package/src/cli/analyze-parser.ts +0 -291
- package/src/cli/analyze.ts +0 -352
- package/src/cli/config-descriptions.ts +0 -219
- package/src/cli/config-diff.ts +0 -103
- package/src/cli/config-display.ts +0 -285
- package/src/cli/config-get.ts +0 -55
- package/src/cli/config.ts +0 -14
- package/src/cli/constitution.ts +0 -17
- package/src/cli/diagnose-analysis.ts +0 -159
- package/src/cli/diagnose-formatter.ts +0 -87
- package/src/cli/diagnose.ts +0 -203
- package/src/cli/generate.ts +0 -250
- package/src/cli/index.ts +0 -42
- package/src/cli/init-context.ts +0 -405
- package/src/cli/init-detect.ts +0 -303
- package/src/cli/init.ts +0 -296
- package/src/cli/interact.ts +0 -295
- package/src/cli/plan.ts +0 -509
- package/src/cli/plugins.ts +0 -122
- package/src/cli/prompts-export.ts +0 -58
- package/src/cli/prompts-init.ts +0 -200
- package/src/cli/prompts-main.ts +0 -183
- package/src/cli/prompts-shared.ts +0 -70
- package/src/cli/prompts-tdd.ts +0 -88
- package/src/cli/prompts.ts +0 -17
- package/src/cli/runs.ts +0 -174
- package/src/cli/status-cost.ts +0 -151
- package/src/cli/status-features.ts +0 -405
- package/src/cli/status.ts +0 -13
- package/src/commands/common.ts +0 -171
- package/src/commands/diagnose.ts +0 -17
- package/src/commands/index.ts +0 -9
- package/src/commands/logs-formatter.ts +0 -201
- package/src/commands/logs-reader.ts +0 -171
- package/src/commands/logs.ts +0 -103
- package/src/commands/precheck.ts +0 -86
- package/src/commands/runs.ts +0 -220
- package/src/commands/unlock.ts +0 -96
- package/src/config/defaults.ts +0 -218
- package/src/config/index.ts +0 -22
- package/src/config/loader.ts +0 -143
- package/src/config/merge.ts +0 -106
- package/src/config/merger.ts +0 -147
- package/src/config/path-security.ts +0 -121
- package/src/config/paths.ts +0 -27
- package/src/config/permissions.ts +0 -63
- package/src/config/runtime-types.ts +0 -522
- package/src/config/schema-types.ts +0 -53
- package/src/config/schema.ts +0 -60
- package/src/config/schemas.ts +0 -426
- package/src/config/test-strategy.ts +0 -71
- package/src/config/types.ts +0 -57
- package/src/config/validate.ts +0 -103
- package/src/constitution/generator.ts +0 -158
- package/src/constitution/generators/aider.ts +0 -41
- package/src/constitution/generators/claude.ts +0 -35
- package/src/constitution/generators/cursor.ts +0 -36
- package/src/constitution/generators/opencode.ts +0 -38
- package/src/constitution/generators/types.ts +0 -33
- package/src/constitution/generators/windsurf.ts +0 -36
- package/src/constitution/index.ts +0 -11
- package/src/constitution/loader.ts +0 -121
- package/src/constitution/types.ts +0 -31
- package/src/context/auto-detect.ts +0 -228
- package/src/context/builder.ts +0 -299
- package/src/context/elements.ts +0 -122
- package/src/context/formatter.ts +0 -107
- package/src/context/generator.ts +0 -343
- package/src/context/generators/aider.ts +0 -34
- package/src/context/generators/claude.ts +0 -28
- package/src/context/generators/codex.ts +0 -28
- package/src/context/generators/cursor.ts +0 -28
- package/src/context/generators/gemini.ts +0 -28
- package/src/context/generators/opencode.ts +0 -30
- package/src/context/generators/windsurf.ts +0 -28
- package/src/context/greenfield.ts +0 -114
- package/src/context/index.ts +0 -34
- package/src/context/injector.ts +0 -279
- package/src/context/parent-context.ts +0 -39
- package/src/context/test-scanner.ts +0 -370
- package/src/context/types.ts +0 -98
- package/src/decompose/apply.ts +0 -50
- package/src/decompose/builder.ts +0 -181
- package/src/decompose/index.ts +0 -8
- package/src/decompose/sections/codebase.ts +0 -26
- package/src/decompose/sections/constraints.ts +0 -32
- package/src/decompose/sections/index.ts +0 -4
- package/src/decompose/sections/sibling-stories.ts +0 -25
- package/src/decompose/sections/target-story.ts +0 -31
- package/src/decompose/types.ts +0 -55
- package/src/decompose/validators/complexity.ts +0 -45
- package/src/decompose/validators/coverage.ts +0 -134
- package/src/decompose/validators/dependency.ts +0 -91
- package/src/decompose/validators/index.ts +0 -35
- package/src/decompose/validators/overlap.ts +0 -128
- package/src/errors.ts +0 -67
- package/src/execution/batching.ts +0 -157
- package/src/execution/crash-heartbeat.ts +0 -77
- package/src/execution/crash-recovery.ts +0 -79
- package/src/execution/crash-signals.ts +0 -165
- package/src/execution/crash-writer.ts +0 -154
- package/src/execution/deferred-review.ts +0 -105
- package/src/execution/dry-run.ts +0 -81
- package/src/execution/escalation/escalation.ts +0 -46
- package/src/execution/escalation/index.ts +0 -13
- package/src/execution/escalation/tier-escalation.ts +0 -346
- package/src/execution/escalation/tier-outcome.ts +0 -143
- package/src/execution/executor-types.ts +0 -73
- package/src/execution/helpers.ts +0 -38
- package/src/execution/index.ts +0 -27
- package/src/execution/iteration-runner.ts +0 -160
- package/src/execution/lifecycle/acceptance-loop.ts +0 -309
- package/src/execution/lifecycle/headless-formatter.ts +0 -83
- package/src/execution/lifecycle/index.ts +0 -11
- package/src/execution/lifecycle/parallel-lifecycle.ts +0 -101
- package/src/execution/lifecycle/precheck-runner.ts +0 -140
- package/src/execution/lifecycle/run-cleanup.ts +0 -81
- package/src/execution/lifecycle/run-completion.ts +0 -247
- package/src/execution/lifecycle/run-initialization.ts +0 -187
- package/src/execution/lifecycle/run-regression.ts +0 -305
- package/src/execution/lifecycle/run-setup.ts +0 -240
- package/src/execution/lifecycle/story-size-prompts.ts +0 -123
- package/src/execution/lock.ts +0 -129
- package/src/execution/parallel-coordinator.ts +0 -281
- package/src/execution/parallel-executor-rectification-pass.ts +0 -117
- package/src/execution/parallel-executor-rectify.ts +0 -136
- package/src/execution/parallel-executor.ts +0 -330
- package/src/execution/parallel-worker.ts +0 -149
- package/src/execution/parallel.ts +0 -13
- package/src/execution/pid-registry.ts +0 -275
- package/src/execution/pipeline-result-handler.ts +0 -221
- package/src/execution/progress.ts +0 -27
- package/src/execution/queue-handler.ts +0 -109
- package/src/execution/runner-completion.ts +0 -171
- package/src/execution/runner-execution.ts +0 -243
- package/src/execution/runner-setup.ts +0 -86
- package/src/execution/runner.ts +0 -265
- package/src/execution/sequential-executor.ts +0 -219
- package/src/execution/status-file.ts +0 -264
- package/src/execution/status-writer.ts +0 -181
- package/src/execution/story-context.ts +0 -266
- package/src/execution/story-selector.ts +0 -76
- package/src/execution/test-output-parser.ts +0 -14
- package/src/execution/timeout-handler.ts +0 -100
- package/src/hooks/index.ts +0 -2
- package/src/hooks/runner.ts +0 -280
- package/src/hooks/types.ts +0 -79
- package/src/interaction/chain.ts +0 -170
- package/src/interaction/index.ts +0 -61
- package/src/interaction/init.ts +0 -84
- package/src/interaction/plugins/auto.ts +0 -243
- package/src/interaction/plugins/cli.ts +0 -300
- package/src/interaction/plugins/telegram.ts +0 -384
- package/src/interaction/plugins/webhook.ts +0 -286
- package/src/interaction/state.ts +0 -171
- package/src/interaction/triggers.ts +0 -250
- package/src/interaction/types.ts +0 -170
- package/src/logger/formatters.ts +0 -84
- package/src/logger/index.ts +0 -16
- package/src/logger/logger.ts +0 -296
- package/src/logger/types.ts +0 -48
- package/src/logging/formatter.ts +0 -355
- package/src/logging/index.ts +0 -22
- package/src/logging/types.ts +0 -93
- package/src/metrics/aggregator.ts +0 -191
- package/src/metrics/index.ts +0 -14
- package/src/metrics/tracker.ts +0 -200
- package/src/metrics/types.ts +0 -115
- package/src/optimizer/index.ts +0 -63
- package/src/optimizer/noop.optimizer.ts +0 -24
- package/src/optimizer/rule-based.optimizer.ts +0 -248
- package/src/optimizer/types.ts +0 -53
- package/src/pipeline/event-bus.ts +0 -297
- package/src/pipeline/events.ts +0 -130
- package/src/pipeline/index.ts +0 -19
- package/src/pipeline/runner.ts +0 -149
- package/src/pipeline/stages/acceptance-setup.ts +0 -144
- package/src/pipeline/stages/acceptance.ts +0 -215
- package/src/pipeline/stages/autofix.ts +0 -262
- package/src/pipeline/stages/completion.ts +0 -110
- package/src/pipeline/stages/constitution.ts +0 -63
- package/src/pipeline/stages/context.ts +0 -122
- package/src/pipeline/stages/execution.ts +0 -359
- package/src/pipeline/stages/index.ts +0 -86
- package/src/pipeline/stages/optimizer.ts +0 -74
- package/src/pipeline/stages/prompt.ts +0 -79
- package/src/pipeline/stages/queue-check.ts +0 -103
- package/src/pipeline/stages/rectify.ts +0 -101
- package/src/pipeline/stages/regression.ts +0 -99
- package/src/pipeline/stages/review.ts +0 -94
- package/src/pipeline/stages/routing.ts +0 -276
- package/src/pipeline/stages/verify.ts +0 -286
- package/src/pipeline/subscribers/events-writer.ts +0 -135
- package/src/pipeline/subscribers/hooks.ts +0 -179
- package/src/pipeline/subscribers/interaction.ts +0 -103
- package/src/pipeline/subscribers/registry.ts +0 -73
- package/src/pipeline/subscribers/reporters.ts +0 -174
- package/src/pipeline/types.ts +0 -220
- package/src/plugins/extensions.ts +0 -225
- package/src/plugins/index.ts +0 -33
- package/src/plugins/loader.ts +0 -352
- package/src/plugins/plugin-logger.ts +0 -41
- package/src/plugins/registry.ts +0 -168
- package/src/plugins/types.ts +0 -206
- package/src/plugins/validator.ts +0 -352
- package/src/prd/index.ts +0 -220
- package/src/prd/schema.ts +0 -268
- package/src/prd/types.ts +0 -273
- package/src/prd/validate.ts +0 -41
- package/src/precheck/checks-agents.ts +0 -63
- package/src/precheck/checks-blockers.ts +0 -23
- package/src/precheck/checks-cli.ts +0 -68
- package/src/precheck/checks-config.ts +0 -102
- package/src/precheck/checks-git.ts +0 -117
- package/src/precheck/checks-system.ts +0 -101
- package/src/precheck/checks-warnings.ts +0 -221
- package/src/precheck/checks.ts +0 -36
- package/src/precheck/index.ts +0 -374
- package/src/precheck/story-size-gate.ts +0 -144
- package/src/precheck/types.ts +0 -31
- package/src/prompts/builder.ts +0 -166
- package/src/prompts/index.ts +0 -2
- package/src/prompts/loader.ts +0 -43
- package/src/prompts/sections/conventions.ts +0 -19
- package/src/prompts/sections/hermetic.ts +0 -41
- package/src/prompts/sections/index.ts +0 -12
- package/src/prompts/sections/isolation.ts +0 -70
- package/src/prompts/sections/role-task.ts +0 -182
- package/src/prompts/sections/story.ts +0 -55
- package/src/prompts/sections/verdict.ts +0 -70
- package/src/prompts/types.ts +0 -21
- package/src/queue/index.ts +0 -2
- package/src/queue/manager.ts +0 -254
- package/src/queue/types.ts +0 -54
- package/src/review/index.ts +0 -8
- package/src/review/orchestrator.ts +0 -154
- package/src/review/runner.ts +0 -303
- package/src/review/types.ts +0 -70
- package/src/routing/batch-route.ts +0 -35
- package/src/routing/builder.ts +0 -81
- package/src/routing/chain.ts +0 -75
- package/src/routing/content-hash.ts +0 -25
- package/src/routing/index.ts +0 -20
- package/src/routing/loader.ts +0 -62
- package/src/routing/router.ts +0 -305
- package/src/routing/strategies/adaptive.ts +0 -215
- package/src/routing/strategies/index.ts +0 -8
- package/src/routing/strategies/keyword.ts +0 -180
- package/src/routing/strategies/llm-prompts.ts +0 -224
- package/src/routing/strategies/llm.ts +0 -320
- package/src/routing/strategies/manual.ts +0 -50
- package/src/routing/strategy.ts +0 -102
- package/src/tdd/cleanup.ts +0 -120
- package/src/tdd/index.ts +0 -22
- package/src/tdd/isolation.ts +0 -117
- package/src/tdd/orchestrator.ts +0 -406
- package/src/tdd/prompts.ts +0 -40
- package/src/tdd/rectification-gate.ts +0 -274
- package/src/tdd/session-runner.ts +0 -263
- package/src/tdd/types.ts +0 -84
- package/src/tdd/verdict-reader.ts +0 -266
- package/src/tdd/verdict.ts +0 -152
- package/src/tui/App.tsx +0 -265
- package/src/tui/components/AgentPanel.tsx +0 -75
- package/src/tui/components/CostOverlay.tsx +0 -118
- package/src/tui/components/HelpOverlay.tsx +0 -107
- package/src/tui/components/StatusBar.tsx +0 -63
- package/src/tui/components/StoriesPanel.tsx +0 -177
- package/src/tui/hooks/useKeyboard.ts +0 -142
- package/src/tui/hooks/useLayout.ts +0 -137
- package/src/tui/hooks/usePipelineEvents.ts +0 -183
- package/src/tui/hooks/usePty.ts +0 -189
- package/src/tui/index.tsx +0 -38
- package/src/tui/types.ts +0 -76
- package/src/utils/errors.ts +0 -12
- package/src/utils/git.ts +0 -245
- package/src/utils/json-file.ts +0 -72
- package/src/utils/log-test-output.ts +0 -25
- package/src/utils/path-security.ts +0 -73
- package/src/utils/queue-writer.ts +0 -54
- package/src/verification/crash-detector.ts +0 -34
- package/src/verification/executor.ts +0 -250
- package/src/verification/index.ts +0 -12
- package/src/verification/orchestrator-types.ts +0 -154
- package/src/verification/orchestrator.ts +0 -76
- package/src/verification/parser.ts +0 -220
- package/src/verification/rectification-loop.ts +0 -172
- package/src/verification/rectification.ts +0 -108
- package/src/verification/runners.ts +0 -129
- package/src/verification/smart-runner.ts +0 -307
- package/src/verification/strategies/acceptance.ts +0 -136
- package/src/verification/strategies/regression.ts +0 -90
- package/src/verification/strategies/scoped.ts +0 -154
- package/src/verification/types.ts +0 -117
- package/src/version.ts +0 -40
- package/src/worktree/dispatcher.ts +0 -6
- package/src/worktree/index.ts +0 -2
- package/src/worktree/manager.ts +0 -193
- package/src/worktree/merge.ts +0 -302
- package/src/worktree/types.ts +0 -4
package/src/cli/init-context.ts
DELETED
|
@@ -1,405 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Context.md Generation (INIT-002)
|
|
3
|
-
*
|
|
4
|
-
* Generates context.md from filesystem scan with optional LLM enhancement.
|
|
5
|
-
* Default mode: template from scan (zero LLM cost)
|
|
6
|
-
* AI mode (--ai flag): LLM-powered narrative context
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { existsSync } from "node:fs";
|
|
10
|
-
import { mkdir } from "node:fs/promises";
|
|
11
|
-
import { basename, join } from "node:path";
|
|
12
|
-
import { getLogger } from "../logger";
|
|
13
|
-
|
|
14
|
-
/** Project scan results */
|
|
15
|
-
export interface ProjectScan {
|
|
16
|
-
projectName: string;
|
|
17
|
-
fileTree: string[];
|
|
18
|
-
packageManifest: {
|
|
19
|
-
name?: string;
|
|
20
|
-
description?: string;
|
|
21
|
-
scripts?: Record<string, string>;
|
|
22
|
-
dependencies?: Record<string, string>;
|
|
23
|
-
} | null;
|
|
24
|
-
readmeSnippet: string | null;
|
|
25
|
-
entryPoints: string[];
|
|
26
|
-
configFiles: string[];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Package manifest structure */
|
|
30
|
-
interface PackageManifest {
|
|
31
|
-
name?: string;
|
|
32
|
-
description?: string;
|
|
33
|
-
scripts?: Record<string, string>;
|
|
34
|
-
dependencies?: Record<string, string>;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** initContext options */
|
|
38
|
-
export interface InitContextOptions {
|
|
39
|
-
ai?: boolean;
|
|
40
|
-
force?: boolean;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Dependency injection for testing */
|
|
44
|
-
export const _deps = {
|
|
45
|
-
callLLM: async (_prompt: string): Promise<string> => {
|
|
46
|
-
// Placeholder implementation
|
|
47
|
-
// In production, this would call the nax LLM infrastructure
|
|
48
|
-
throw new Error("callLLM not implemented");
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Recursively find all files in a directory, excluding certain paths.
|
|
54
|
-
* Returns relative paths, limited to maxFiles entries.
|
|
55
|
-
*/
|
|
56
|
-
async function findFiles(dir: string, maxFiles = 200): Promise<string[]> {
|
|
57
|
-
// Use find command to locate files, excluding common directories
|
|
58
|
-
try {
|
|
59
|
-
const proc = Bun.spawnSync(
|
|
60
|
-
[
|
|
61
|
-
"find",
|
|
62
|
-
dir,
|
|
63
|
-
"-type",
|
|
64
|
-
"f",
|
|
65
|
-
"-not",
|
|
66
|
-
"-path",
|
|
67
|
-
"*/node_modules/*",
|
|
68
|
-
"-not",
|
|
69
|
-
"-path",
|
|
70
|
-
"*/.git/*",
|
|
71
|
-
"-not",
|
|
72
|
-
"-path",
|
|
73
|
-
"*/dist/*",
|
|
74
|
-
],
|
|
75
|
-
{ stdio: ["pipe", "pipe", "pipe"] },
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
if (proc.success) {
|
|
79
|
-
const output = new TextDecoder().decode(proc.stdout);
|
|
80
|
-
const files = output
|
|
81
|
-
.trim()
|
|
82
|
-
.split("\n")
|
|
83
|
-
.filter((f) => f.length > 0)
|
|
84
|
-
.map((f) => f.replace(`${dir}/`, ""))
|
|
85
|
-
.slice(0, maxFiles);
|
|
86
|
-
return files;
|
|
87
|
-
}
|
|
88
|
-
} catch {
|
|
89
|
-
// find command failed, use fallback
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return [];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Read and parse package.json if it exists
|
|
97
|
-
*/
|
|
98
|
-
async function readPackageManifest(projectRoot: string): Promise<PackageManifest | null> {
|
|
99
|
-
const packageJsonPath = join(projectRoot, "package.json");
|
|
100
|
-
|
|
101
|
-
if (!existsSync(packageJsonPath)) {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
const content = await Bun.file(packageJsonPath).text();
|
|
107
|
-
const manifest = JSON.parse(content) as PackageManifest;
|
|
108
|
-
return {
|
|
109
|
-
name: manifest.name,
|
|
110
|
-
description: manifest.description,
|
|
111
|
-
scripts: manifest.scripts,
|
|
112
|
-
dependencies: manifest.dependencies,
|
|
113
|
-
};
|
|
114
|
-
} catch {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Read first 100 lines of README.md if it exists
|
|
121
|
-
*/
|
|
122
|
-
async function readReadmeSnippet(projectRoot: string): Promise<string | null> {
|
|
123
|
-
const readmePath = join(projectRoot, "README.md");
|
|
124
|
-
|
|
125
|
-
if (!existsSync(readmePath)) {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
const content = await Bun.file(readmePath).text();
|
|
131
|
-
const lines = content.split("\n");
|
|
132
|
-
return lines.slice(0, 100).join("\n");
|
|
133
|
-
} catch {
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Detect entry points in the project
|
|
140
|
-
*/
|
|
141
|
-
async function detectEntryPoints(projectRoot: string): Promise<string[]> {
|
|
142
|
-
const candidates = ["src/index.ts", "src/main.ts", "main.go", "src/lib.rs"];
|
|
143
|
-
const found: string[] = [];
|
|
144
|
-
|
|
145
|
-
for (const candidate of candidates) {
|
|
146
|
-
const path = join(projectRoot, candidate);
|
|
147
|
-
if (existsSync(path)) {
|
|
148
|
-
found.push(candidate);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return found;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Detect config files in the project
|
|
157
|
-
*/
|
|
158
|
-
async function detectConfigFiles(projectRoot: string): Promise<string[]> {
|
|
159
|
-
const candidates = ["tsconfig.json", "biome.json", "turbo.json", ".env.example"];
|
|
160
|
-
const found: string[] = [];
|
|
161
|
-
|
|
162
|
-
for (const candidate of candidates) {
|
|
163
|
-
const path = join(projectRoot, candidate);
|
|
164
|
-
if (existsSync(path)) {
|
|
165
|
-
found.push(candidate);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return found;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Scan a project for context information
|
|
174
|
-
*/
|
|
175
|
-
export async function scanProject(projectRoot: string): Promise<ProjectScan> {
|
|
176
|
-
const fileTree = await findFiles(projectRoot, 200);
|
|
177
|
-
const packageManifest = await readPackageManifest(projectRoot);
|
|
178
|
-
const readmeSnippet = await readReadmeSnippet(projectRoot);
|
|
179
|
-
const entryPoints = await detectEntryPoints(projectRoot);
|
|
180
|
-
const configFiles = await detectConfigFiles(projectRoot);
|
|
181
|
-
|
|
182
|
-
// Determine project name from package.json or directory basename
|
|
183
|
-
const projectName = packageManifest?.name || basename(projectRoot);
|
|
184
|
-
|
|
185
|
-
return {
|
|
186
|
-
projectName,
|
|
187
|
-
fileTree,
|
|
188
|
-
packageManifest,
|
|
189
|
-
readmeSnippet,
|
|
190
|
-
entryPoints,
|
|
191
|
-
configFiles,
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Generate a markdown template for context.md from scan results
|
|
197
|
-
*/
|
|
198
|
-
export function generateContextTemplate(scan: ProjectScan): string {
|
|
199
|
-
const lines: string[] = [];
|
|
200
|
-
|
|
201
|
-
lines.push(`# ${scan.projectName}\n`);
|
|
202
|
-
|
|
203
|
-
if (scan.packageManifest?.description) {
|
|
204
|
-
lines.push(`${scan.packageManifest.description}\n`);
|
|
205
|
-
} else {
|
|
206
|
-
lines.push("<!-- TODO: Add project description -->\n");
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (scan.entryPoints.length > 0) {
|
|
210
|
-
lines.push("## Entry Points\n");
|
|
211
|
-
for (const ep of scan.entryPoints) {
|
|
212
|
-
lines.push(`- ${ep}`);
|
|
213
|
-
}
|
|
214
|
-
lines.push("");
|
|
215
|
-
} else {
|
|
216
|
-
lines.push("## Entry Points\n");
|
|
217
|
-
lines.push("<!-- TODO: Document entry points -->\n");
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (scan.fileTree.length > 0) {
|
|
221
|
-
lines.push("## Project Structure\n");
|
|
222
|
-
lines.push("```");
|
|
223
|
-
for (const file of scan.fileTree.slice(0, 20)) {
|
|
224
|
-
lines.push(file);
|
|
225
|
-
}
|
|
226
|
-
if (scan.fileTree.length > 20) {
|
|
227
|
-
lines.push(`... and ${scan.fileTree.length - 20} more files`);
|
|
228
|
-
}
|
|
229
|
-
lines.push("```\n");
|
|
230
|
-
} else {
|
|
231
|
-
lines.push("## Project Structure\n");
|
|
232
|
-
lines.push("<!-- TODO: Document project structure -->\n");
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (scan.configFiles.length > 0) {
|
|
236
|
-
lines.push("## Configuration Files\n");
|
|
237
|
-
for (const cf of scan.configFiles) {
|
|
238
|
-
lines.push(`- ${cf}`);
|
|
239
|
-
}
|
|
240
|
-
lines.push("");
|
|
241
|
-
} else {
|
|
242
|
-
lines.push("## Configuration Files\n");
|
|
243
|
-
lines.push("<!-- TODO: Document configuration files -->\n");
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (scan.packageManifest?.scripts) {
|
|
247
|
-
const hasScripts = Object.keys(scan.packageManifest.scripts).length > 0;
|
|
248
|
-
if (hasScripts) {
|
|
249
|
-
lines.push("## Scripts\n");
|
|
250
|
-
for (const [name, command] of Object.entries(scan.packageManifest.scripts)) {
|
|
251
|
-
lines.push(`- **${name}**: \`${command}\``);
|
|
252
|
-
}
|
|
253
|
-
lines.push("");
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (scan.packageManifest?.dependencies) {
|
|
258
|
-
const deps = Object.keys(scan.packageManifest.dependencies);
|
|
259
|
-
if (deps.length > 0) {
|
|
260
|
-
lines.push("## Dependencies\n");
|
|
261
|
-
lines.push("<!-- TODO: Document key dependencies and their purpose -->\n");
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
lines.push("## Development Guidelines\n");
|
|
266
|
-
lines.push("<!-- TODO: Document development guidelines and conventions -->\n");
|
|
267
|
-
|
|
268
|
-
return `${lines.join("\n").trim()}\n`;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Generate context.md with LLM enhancement
|
|
273
|
-
*/
|
|
274
|
-
async function generateContextWithLLM(scan: ProjectScan): Promise<string> {
|
|
275
|
-
const logger = getLogger();
|
|
276
|
-
|
|
277
|
-
// Build LLM prompt from scan results
|
|
278
|
-
const scanSummary = `
|
|
279
|
-
Project: ${scan.projectName}
|
|
280
|
-
Entry Points: ${scan.entryPoints.join(", ") || "None detected"}
|
|
281
|
-
Config Files: ${scan.configFiles.join(", ") || "None detected"}
|
|
282
|
-
Total Files: ${scan.fileTree.length}
|
|
283
|
-
Description: ${scan.packageManifest?.description || "Not provided"}
|
|
284
|
-
`;
|
|
285
|
-
|
|
286
|
-
const prompt = `
|
|
287
|
-
You are a technical documentation expert. Generate a concise, well-structured context.md file for a software project based on this scan:
|
|
288
|
-
|
|
289
|
-
${scanSummary}
|
|
290
|
-
|
|
291
|
-
The context.md should include:
|
|
292
|
-
1. Project overview (name, purpose, key technologies)
|
|
293
|
-
2. Entry points and main modules
|
|
294
|
-
3. Key dependencies and why they're used
|
|
295
|
-
4. Development setup and common commands
|
|
296
|
-
5. Architecture overview (brief)
|
|
297
|
-
6. Development guidelines
|
|
298
|
-
|
|
299
|
-
Keep it under 2000 tokens. Use markdown formatting. Be specific to the detected stack and structure.
|
|
300
|
-
`;
|
|
301
|
-
|
|
302
|
-
try {
|
|
303
|
-
const result = await _deps.callLLM(prompt);
|
|
304
|
-
logger.info("init", "Generated context.md with LLM");
|
|
305
|
-
return result;
|
|
306
|
-
} catch (err) {
|
|
307
|
-
logger.warn(
|
|
308
|
-
"init",
|
|
309
|
-
`LLM context generation failed, falling back to template: ${err instanceof Error ? err.message : String(err)}`,
|
|
310
|
-
);
|
|
311
|
-
return generateContextTemplate(scan);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Generate a minimal package context.md template.
|
|
317
|
-
*
|
|
318
|
-
* @param packagePath - Relative path of the package (e.g. "packages/api")
|
|
319
|
-
*/
|
|
320
|
-
export function generatePackageContextTemplate(packagePath: string): string {
|
|
321
|
-
const packageName = packagePath.split("/").pop() ?? packagePath;
|
|
322
|
-
return `# ${packageName} — Context
|
|
323
|
-
|
|
324
|
-
<!-- Package-specific conventions. Root context.md provides shared rules. -->
|
|
325
|
-
|
|
326
|
-
## Tech Stack
|
|
327
|
-
|
|
328
|
-
<!-- TODO: Document this package's tech stack -->
|
|
329
|
-
|
|
330
|
-
## Commands
|
|
331
|
-
|
|
332
|
-
| Command | Purpose |
|
|
333
|
-
|:--------|:--------|
|
|
334
|
-
| \`bun test\` | Unit tests |
|
|
335
|
-
|
|
336
|
-
## Development Guidelines
|
|
337
|
-
|
|
338
|
-
<!-- TODO: Document package-specific guidelines -->
|
|
339
|
-
`;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* Initialize per-package nax/context.md scaffold.
|
|
344
|
-
*
|
|
345
|
-
* Creates \`<packageDir>/nax/context.md\` with a minimal template.
|
|
346
|
-
* Does not overwrite an existing file unless force is set.
|
|
347
|
-
*
|
|
348
|
-
* @param repoRoot - Absolute path to repo root
|
|
349
|
-
* @param packagePath - Relative path of the package (e.g. "packages/api")
|
|
350
|
-
* @param force - Overwrite existing file
|
|
351
|
-
*/
|
|
352
|
-
export async function initPackage(repoRoot: string, packagePath: string, force = false): Promise<void> {
|
|
353
|
-
const logger = getLogger();
|
|
354
|
-
const packageDir = join(repoRoot, packagePath);
|
|
355
|
-
const naxDir = join(packageDir, "nax");
|
|
356
|
-
const contextPath = join(naxDir, "context.md");
|
|
357
|
-
|
|
358
|
-
if (existsSync(contextPath) && !force) {
|
|
359
|
-
logger.info("init", "Package context.md already exists (use --force to overwrite)", { path: contextPath });
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (!existsSync(naxDir)) {
|
|
364
|
-
await mkdir(naxDir, { recursive: true });
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
const content = generatePackageContextTemplate(packagePath);
|
|
368
|
-
await Bun.write(contextPath, content);
|
|
369
|
-
logger.info("init", "Created package context.md", { path: contextPath });
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Initialize context.md for a project
|
|
374
|
-
*/
|
|
375
|
-
export async function initContext(projectRoot: string, options: InitContextOptions = {}): Promise<void> {
|
|
376
|
-
const logger = getLogger();
|
|
377
|
-
const naxDir = join(projectRoot, "nax");
|
|
378
|
-
const contextPath = join(naxDir, "context.md");
|
|
379
|
-
|
|
380
|
-
// Check if context.md already exists
|
|
381
|
-
if (existsSync(contextPath) && !options.force) {
|
|
382
|
-
logger.info("init", "context.md already exists, skipping (use --force to overwrite)", { path: contextPath });
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Create nax directory if needed
|
|
387
|
-
if (!existsSync(naxDir)) {
|
|
388
|
-
await mkdir(naxDir, { recursive: true });
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// Scan the project
|
|
392
|
-
const scan = await scanProject(projectRoot);
|
|
393
|
-
|
|
394
|
-
// Generate content (template or LLM-enhanced)
|
|
395
|
-
let content: string;
|
|
396
|
-
if (options.ai) {
|
|
397
|
-
content = await generateContextWithLLM(scan);
|
|
398
|
-
} else {
|
|
399
|
-
content = generateContextTemplate(scan);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// Write context.md
|
|
403
|
-
await Bun.write(contextPath, content);
|
|
404
|
-
logger.info("init", "Generated nax/context.md template from project scan", { path: contextPath });
|
|
405
|
-
}
|
package/src/cli/init-detect.ts
DELETED
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project Stack Detection for nax init
|
|
3
|
-
*
|
|
4
|
-
* Scans the project root for stack indicators and builds quality.commands
|
|
5
|
-
* for nax/config.json.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
-
import { join } from "node:path";
|
|
10
|
-
|
|
11
|
-
/** Detected project runtime */
|
|
12
|
-
export type Runtime = "bun" | "node" | "unknown";
|
|
13
|
-
|
|
14
|
-
/** Detected UI framework */
|
|
15
|
-
export type UIFramework = "ink" | "react" | "vue" | "svelte";
|
|
16
|
-
|
|
17
|
-
/** Full stack info including UI framework and bin detection */
|
|
18
|
-
export interface StackInfo extends ProjectStack {
|
|
19
|
-
uiFramework?: UIFramework;
|
|
20
|
-
hasBin?: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** Shape of a parsed package.json for detection purposes */
|
|
24
|
-
interface PackageJson {
|
|
25
|
-
dependencies?: Record<string, string>;
|
|
26
|
-
devDependencies?: Record<string, string>;
|
|
27
|
-
peerDependencies?: Record<string, string>;
|
|
28
|
-
bin?: Record<string, string> | string;
|
|
29
|
-
workspaces?: string[] | { packages: string[] };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function readPackageJson(projectRoot: string): PackageJson | undefined {
|
|
33
|
-
const pkgPath = join(projectRoot, "package.json");
|
|
34
|
-
if (!existsSync(pkgPath)) return undefined;
|
|
35
|
-
try {
|
|
36
|
-
return JSON.parse(readFileSync(pkgPath, "utf-8")) as PackageJson;
|
|
37
|
-
} catch {
|
|
38
|
-
return undefined;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function allDeps(pkg: PackageJson): Record<string, string> {
|
|
43
|
-
return {
|
|
44
|
-
...pkg.dependencies,
|
|
45
|
-
...pkg.devDependencies,
|
|
46
|
-
...pkg.peerDependencies,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function detectUIFramework(pkg: PackageJson): UIFramework | undefined {
|
|
51
|
-
const deps = allDeps(pkg);
|
|
52
|
-
if ("ink" in deps) return "ink";
|
|
53
|
-
if ("react" in deps || "next" in deps) return "react";
|
|
54
|
-
if ("vue" in deps || "nuxt" in deps) return "vue";
|
|
55
|
-
if ("svelte" in deps || "@sveltejs/kit" in deps) return "svelte";
|
|
56
|
-
return undefined;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function detectHasBin(pkg: PackageJson): boolean {
|
|
60
|
-
return pkg.bin !== undefined;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Detect the project stack including UI framework from package.json.
|
|
65
|
-
*/
|
|
66
|
-
export function detectStack(projectRoot: string): StackInfo {
|
|
67
|
-
const base = detectProjectStack(projectRoot);
|
|
68
|
-
const pkg = readPackageJson(projectRoot);
|
|
69
|
-
if (!pkg) return base;
|
|
70
|
-
return {
|
|
71
|
-
...base,
|
|
72
|
-
uiFramework: detectUIFramework(pkg),
|
|
73
|
-
hasBin: detectHasBin(pkg) || undefined,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Detected project language */
|
|
78
|
-
export type Language = "typescript" | "python" | "rust" | "go" | "unknown";
|
|
79
|
-
|
|
80
|
-
/** Detected linter */
|
|
81
|
-
export type Linter = "biome" | "eslint" | "ruff" | "clippy" | "golangci-lint" | "unknown";
|
|
82
|
-
|
|
83
|
-
/** Detected monorepo tooling */
|
|
84
|
-
export type Monorepo = "turborepo" | "nx" | "pnpm-workspaces" | "bun-workspaces" | "none";
|
|
85
|
-
|
|
86
|
-
/** Full detected project stack */
|
|
87
|
-
export interface ProjectStack {
|
|
88
|
-
runtime: Runtime;
|
|
89
|
-
language: Language;
|
|
90
|
-
linter: Linter;
|
|
91
|
-
monorepo: Monorepo;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** Quality commands derived from stack detection */
|
|
95
|
-
export interface QualityCommands {
|
|
96
|
-
typecheck?: string;
|
|
97
|
-
lint?: string;
|
|
98
|
-
test?: string;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function detectRuntime(projectRoot: string): Runtime {
|
|
102
|
-
if (existsSync(join(projectRoot, "bun.lockb")) || existsSync(join(projectRoot, "bunfig.toml"))) {
|
|
103
|
-
return "bun";
|
|
104
|
-
}
|
|
105
|
-
if (
|
|
106
|
-
existsSync(join(projectRoot, "package-lock.json")) ||
|
|
107
|
-
existsSync(join(projectRoot, "yarn.lock")) ||
|
|
108
|
-
existsSync(join(projectRoot, "pnpm-lock.yaml"))
|
|
109
|
-
) {
|
|
110
|
-
return "node";
|
|
111
|
-
}
|
|
112
|
-
return "unknown";
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function detectLanguage(projectRoot: string): Language {
|
|
116
|
-
if (existsSync(join(projectRoot, "tsconfig.json"))) return "typescript";
|
|
117
|
-
if (existsSync(join(projectRoot, "pyproject.toml")) || existsSync(join(projectRoot, "setup.py"))) {
|
|
118
|
-
return "python";
|
|
119
|
-
}
|
|
120
|
-
if (existsSync(join(projectRoot, "Cargo.toml"))) return "rust";
|
|
121
|
-
if (existsSync(join(projectRoot, "go.mod"))) return "go";
|
|
122
|
-
return "unknown";
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function detectLinter(projectRoot: string): Linter {
|
|
126
|
-
if (existsSync(join(projectRoot, "biome.json")) || existsSync(join(projectRoot, "biome.jsonc"))) {
|
|
127
|
-
return "biome";
|
|
128
|
-
}
|
|
129
|
-
if (
|
|
130
|
-
existsSync(join(projectRoot, ".eslintrc.json")) ||
|
|
131
|
-
existsSync(join(projectRoot, ".eslintrc.js")) ||
|
|
132
|
-
existsSync(join(projectRoot, "eslint.config.js"))
|
|
133
|
-
) {
|
|
134
|
-
return "eslint";
|
|
135
|
-
}
|
|
136
|
-
return "unknown";
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function detectMonorepo(projectRoot: string): Monorepo {
|
|
140
|
-
if (existsSync(join(projectRoot, "turbo.json"))) return "turborepo";
|
|
141
|
-
if (existsSync(join(projectRoot, "nx.json"))) return "nx";
|
|
142
|
-
if (existsSync(join(projectRoot, "pnpm-workspace.yaml"))) return "pnpm-workspaces";
|
|
143
|
-
// Bun/npm/yarn workspaces: package.json with "workspaces" field
|
|
144
|
-
const pkg = readPackageJson(projectRoot);
|
|
145
|
-
if (pkg?.workspaces) return "bun-workspaces";
|
|
146
|
-
return "none";
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Detect the project stack by scanning for indicator files.
|
|
151
|
-
*/
|
|
152
|
-
export function detectProjectStack(projectRoot: string): ProjectStack {
|
|
153
|
-
return {
|
|
154
|
-
runtime: detectRuntime(projectRoot),
|
|
155
|
-
language: detectLanguage(projectRoot),
|
|
156
|
-
linter: detectLinter(projectRoot),
|
|
157
|
-
monorepo: detectMonorepo(projectRoot),
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function resolveLintCommand(stack: ProjectStack, fallback: string): string {
|
|
162
|
-
if (stack.linter === "biome") return "biome check .";
|
|
163
|
-
if (stack.linter === "eslint") return "eslint .";
|
|
164
|
-
return fallback;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Build quality.commands for monorepo orchestrators.
|
|
169
|
-
*
|
|
170
|
-
* Turborepo and Nx support change-aware filtering natively — delegate
|
|
171
|
-
* scoping to the tool rather than nax's smart test runner.
|
|
172
|
-
* pnpm/bun workspaces have no built-in affected detection, so nax's
|
|
173
|
-
* smart runner still applies; commands run across all packages.
|
|
174
|
-
*/
|
|
175
|
-
function buildMonorepoQualityCommands(stack: ProjectStack): QualityCommands | null {
|
|
176
|
-
if (stack.monorepo === "turborepo") {
|
|
177
|
-
return {
|
|
178
|
-
typecheck: "turbo run typecheck --filter=...[HEAD~1]",
|
|
179
|
-
lint: "turbo run lint --filter=...[HEAD~1]",
|
|
180
|
-
test: "turbo run test --filter=...[HEAD~1]",
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
if (stack.monorepo === "nx") {
|
|
184
|
-
return {
|
|
185
|
-
typecheck: "nx affected --target=typecheck",
|
|
186
|
-
lint: "nx affected --target=lint",
|
|
187
|
-
test: "nx affected --target=test",
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
if (stack.monorepo === "pnpm-workspaces") {
|
|
191
|
-
return {
|
|
192
|
-
lint: resolveLintCommand(stack, "pnpm run --recursive lint"),
|
|
193
|
-
test: "pnpm run --recursive test",
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
if (stack.monorepo === "bun-workspaces") {
|
|
197
|
-
return {
|
|
198
|
-
lint: resolveLintCommand(stack, "bun run lint"),
|
|
199
|
-
test: "bun run --filter '*' test",
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Build quality.commands from a detected project stack.
|
|
207
|
-
*/
|
|
208
|
-
export function buildQualityCommands(stack: ProjectStack): QualityCommands {
|
|
209
|
-
// Monorepo orchestrators: delegate to the tool's own scoping
|
|
210
|
-
const monorepoCommands = buildMonorepoQualityCommands(stack);
|
|
211
|
-
if (monorepoCommands) return monorepoCommands;
|
|
212
|
-
|
|
213
|
-
if (stack.runtime === "bun" && stack.language === "typescript") {
|
|
214
|
-
return {
|
|
215
|
-
typecheck: "bun run tsc --noEmit",
|
|
216
|
-
lint: resolveLintCommand(stack, "bun run lint"),
|
|
217
|
-
test: "bun test",
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (stack.runtime === "node" && stack.language === "typescript") {
|
|
222
|
-
return {
|
|
223
|
-
typecheck: "npx tsc --noEmit",
|
|
224
|
-
lint: resolveLintCommand(stack, "npm run lint"),
|
|
225
|
-
test: "npm test",
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (stack.language === "python") {
|
|
230
|
-
return {
|
|
231
|
-
lint: "ruff check .",
|
|
232
|
-
test: "pytest",
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (stack.language === "rust") {
|
|
237
|
-
return {
|
|
238
|
-
typecheck: "cargo check",
|
|
239
|
-
lint: "cargo clippy",
|
|
240
|
-
test: "cargo test",
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (stack.language === "go") {
|
|
245
|
-
return {
|
|
246
|
-
typecheck: "go vet ./...",
|
|
247
|
-
lint: "golangci-lint run",
|
|
248
|
-
test: "go test ./...",
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return {};
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function isStackDetected(stack: ProjectStack): boolean {
|
|
256
|
-
return stack.runtime !== "unknown" || stack.language !== "unknown";
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/** Build the acceptance config section from StackInfo, or undefined if not applicable. */
|
|
260
|
-
function buildAcceptanceConfig(stack: StackInfo): { testStrategy: string; testFramework?: string } | undefined {
|
|
261
|
-
if (stack.uiFramework === "ink") {
|
|
262
|
-
return { testStrategy: "component", testFramework: "ink-testing-library" };
|
|
263
|
-
}
|
|
264
|
-
if (stack.uiFramework === "react") {
|
|
265
|
-
return { testStrategy: "component", testFramework: "@testing-library/react" };
|
|
266
|
-
}
|
|
267
|
-
if (stack.uiFramework === "vue") {
|
|
268
|
-
return { testStrategy: "component", testFramework: "@testing-library/vue" };
|
|
269
|
-
}
|
|
270
|
-
if (stack.uiFramework === "svelte") {
|
|
271
|
-
return { testStrategy: "component", testFramework: "@testing-library/svelte" };
|
|
272
|
-
}
|
|
273
|
-
if (stack.hasBin) {
|
|
274
|
-
const testFramework = stack.runtime === "bun" ? "bun:test" : "jest";
|
|
275
|
-
return { testStrategy: "cli", testFramework };
|
|
276
|
-
}
|
|
277
|
-
return undefined;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Build the full init config object from a detected project stack.
|
|
282
|
-
* Falls back to minimal config when stack is undetected.
|
|
283
|
-
*/
|
|
284
|
-
export function buildInitConfig(stack: ProjectStack | StackInfo): object {
|
|
285
|
-
const stackInfo = stack as StackInfo;
|
|
286
|
-
const acceptance = buildAcceptanceConfig(stackInfo);
|
|
287
|
-
|
|
288
|
-
if (!isStackDetected(stack)) {
|
|
289
|
-
return acceptance ? { version: 1, acceptance } : { version: 1 };
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const commands = buildQualityCommands(stack);
|
|
293
|
-
const hasCommands = Object.keys(commands).length > 0;
|
|
294
|
-
|
|
295
|
-
if (!hasCommands && !acceptance) {
|
|
296
|
-
return { version: 1 };
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const config: Record<string, unknown> = { version: 1 };
|
|
300
|
-
if (hasCommands) config.quality = { commands };
|
|
301
|
-
if (acceptance) config.acceptance = acceptance;
|
|
302
|
-
return config;
|
|
303
|
-
}
|