@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.ts
DELETED
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Init Command
|
|
3
|
-
*
|
|
4
|
-
* Initializes nax configuration directories and files.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { existsSync } from "node:fs";
|
|
8
|
-
import { mkdir } from "node:fs/promises";
|
|
9
|
-
import { join } from "node:path";
|
|
10
|
-
import { globalConfigDir, projectConfigDir } from "../config/paths";
|
|
11
|
-
import { getLogger } from "../logger";
|
|
12
|
-
import { initContext, initPackage } from "./init-context";
|
|
13
|
-
import { buildInitConfig, detectStack } from "./init-detect";
|
|
14
|
-
import type { ProjectStack } from "./init-detect";
|
|
15
|
-
import { promptsInitCommand } from "./prompts";
|
|
16
|
-
|
|
17
|
-
/** Init command options */
|
|
18
|
-
export interface InitOptions {
|
|
19
|
-
/** Initialize global config (~/.nax) */
|
|
20
|
-
global?: boolean;
|
|
21
|
-
/** Project root (default: cwd) */
|
|
22
|
-
projectRoot?: string;
|
|
23
|
-
/**
|
|
24
|
-
* Initialize a per-package nax/context.md scaffold.
|
|
25
|
-
* Relative path from repo root, e.g. "packages/api".
|
|
26
|
-
*/
|
|
27
|
-
package?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Options for initProject */
|
|
31
|
-
export interface InitProjectOptions {
|
|
32
|
-
/** Use LLM to generate context.md (--ai flag) */
|
|
33
|
-
ai?: boolean;
|
|
34
|
-
/** Force overwrite of existing files */
|
|
35
|
-
force?: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Gitignore entries added by nax init
|
|
40
|
-
*/
|
|
41
|
-
const NAX_GITIGNORE_ENTRIES = [
|
|
42
|
-
".nax-verifier-verdict.json",
|
|
43
|
-
"nax.lock",
|
|
44
|
-
"nax/**/runs/",
|
|
45
|
-
"nax/metrics.json",
|
|
46
|
-
"nax/features/*/status.json",
|
|
47
|
-
"nax/features/*/plan/",
|
|
48
|
-
"nax/features/*/acp-sessions.json",
|
|
49
|
-
"nax/features/*/interactions/",
|
|
50
|
-
"nax/features/*/progress.txt",
|
|
51
|
-
"nax/features/*/acceptance-refined.json",
|
|
52
|
-
".nax-pids",
|
|
53
|
-
".nax-wt/",
|
|
54
|
-
];
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Add nax-specific entries to .gitignore if not already present.
|
|
58
|
-
*
|
|
59
|
-
* Appends a clearly marked nax section to the project .gitignore.
|
|
60
|
-
*/
|
|
61
|
-
async function updateGitignore(projectRoot: string): Promise<void> {
|
|
62
|
-
const logger = getLogger();
|
|
63
|
-
const gitignorePath = join(projectRoot, ".gitignore");
|
|
64
|
-
|
|
65
|
-
let existing = "";
|
|
66
|
-
if (existsSync(gitignorePath)) {
|
|
67
|
-
existing = await Bun.file(gitignorePath).text();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const missingEntries = NAX_GITIGNORE_ENTRIES.filter((entry) => !existing.includes(entry));
|
|
71
|
-
|
|
72
|
-
if (missingEntries.length === 0) {
|
|
73
|
-
logger.info("init", ".gitignore already has nax entries", { path: gitignorePath });
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const naxSection = `\n# nax — generated files\n${missingEntries.join("\n")}\n`;
|
|
78
|
-
await Bun.write(gitignorePath, existing + naxSection);
|
|
79
|
-
logger.info("init", "Updated .gitignore with nax entries", {
|
|
80
|
-
path: gitignorePath,
|
|
81
|
-
added: missingEntries,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Build a stack-aware constitution.md from the detected project stack.
|
|
87
|
-
*/
|
|
88
|
-
function buildConstitution(stack: ProjectStack): string {
|
|
89
|
-
const sections: string[] = [];
|
|
90
|
-
|
|
91
|
-
sections.push("# Project Constitution\n");
|
|
92
|
-
|
|
93
|
-
sections.push("## Goals");
|
|
94
|
-
sections.push("- Deliver high-quality, maintainable code");
|
|
95
|
-
sections.push("- Follow project conventions and best practices");
|
|
96
|
-
sections.push("- Maintain comprehensive test coverage\n");
|
|
97
|
-
|
|
98
|
-
sections.push("## Constraints");
|
|
99
|
-
sections.push("- Follow functional style for pure logic");
|
|
100
|
-
sections.push("- Keep files focused and under 400 lines\n");
|
|
101
|
-
|
|
102
|
-
if (stack.runtime === "bun") {
|
|
103
|
-
sections.push("## Bun-Native APIs");
|
|
104
|
-
sections.push("- Use `Bun.file()` for file reads, `Bun.write()` for file writes");
|
|
105
|
-
sections.push("- Use `Bun.spawn()` for subprocesses (never `child_process`)");
|
|
106
|
-
sections.push("- Use `Bun.sleep()` for delays");
|
|
107
|
-
sections.push("- Use `bun test` for running tests\n");
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (stack.language === "typescript") {
|
|
111
|
-
sections.push("## strict TypeScript");
|
|
112
|
-
sections.push("- Enable strict mode in tsconfig.json");
|
|
113
|
-
sections.push("- No `any` in public APIs — use `unknown` + type guards");
|
|
114
|
-
sections.push("- Explicit return types on all exported functions\n");
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (stack.language === "python") {
|
|
118
|
-
sections.push("## Python Standards");
|
|
119
|
-
sections.push("- Follow PEP 8 style guide for formatting and naming");
|
|
120
|
-
sections.push("- Add type hints to all function signatures");
|
|
121
|
-
sections.push("- Use type annotations for variables where non-obvious\n");
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (stack.monorepo !== "none") {
|
|
125
|
-
sections.push("## Monorepo Conventions");
|
|
126
|
-
sections.push("- Respect package boundaries — do not import across packages without explicit dependency");
|
|
127
|
-
sections.push("- Each package should be independently buildable and testable");
|
|
128
|
-
sections.push("- Shared utilities go in a dedicated `packages/shared` (or equivalent) package");
|
|
129
|
-
if (stack.monorepo === "turborepo") {
|
|
130
|
-
sections.push("- Use `turbo run <task> --filter=<package>` to run tasks scoped to a single package");
|
|
131
|
-
} else if (stack.monorepo === "nx") {
|
|
132
|
-
sections.push("- Use `nx run <package>:<task>` to run tasks scoped to a single package");
|
|
133
|
-
} else if (stack.monorepo === "pnpm-workspaces") {
|
|
134
|
-
sections.push("- Use `pnpm --filter <package> run <task>` to run tasks scoped to a single package");
|
|
135
|
-
} else if (stack.monorepo === "bun-workspaces") {
|
|
136
|
-
sections.push("- Use `bun run --filter <package> <task>` to run tasks scoped to a single package");
|
|
137
|
-
}
|
|
138
|
-
sections.push("");
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
sections.push("## Preferences");
|
|
142
|
-
sections.push("- Prefer immutability over mutation");
|
|
143
|
-
sections.push("- Write tests first (TDD approach)");
|
|
144
|
-
sections.push("- Clear, descriptive naming");
|
|
145
|
-
|
|
146
|
-
return `${sections.join("\n")}\n`;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const MINIMAL_GLOBAL_CONFIG = {
|
|
150
|
-
version: 1,
|
|
151
|
-
// Add global preferences here (e.g., model tiers, execution limits)
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Initialize global nax config directory (~/.nax)
|
|
156
|
-
*/
|
|
157
|
-
async function initGlobal(): Promise<void> {
|
|
158
|
-
const logger = getLogger();
|
|
159
|
-
const globalDir = globalConfigDir();
|
|
160
|
-
|
|
161
|
-
// Create ~/.nax if it doesn't exist
|
|
162
|
-
if (!existsSync(globalDir)) {
|
|
163
|
-
await mkdir(globalDir, { recursive: true });
|
|
164
|
-
logger.info("init", "Created global config directory", { path: globalDir });
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Create ~/.nax/config.json if it doesn't exist
|
|
168
|
-
const configPath = join(globalDir, "config.json");
|
|
169
|
-
if (!existsSync(configPath)) {
|
|
170
|
-
await Bun.write(configPath, `${JSON.stringify(MINIMAL_GLOBAL_CONFIG, null, 2)}\n`);
|
|
171
|
-
logger.info("init", "Created global config", { path: configPath });
|
|
172
|
-
} else {
|
|
173
|
-
logger.info("init", "Global config already exists", { path: configPath });
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Create ~/.nax/constitution.md if it doesn't exist
|
|
177
|
-
const constitutionPath = join(globalDir, "constitution.md");
|
|
178
|
-
if (!existsSync(constitutionPath)) {
|
|
179
|
-
await Bun.write(
|
|
180
|
-
constitutionPath,
|
|
181
|
-
buildConstitution({ runtime: "unknown", language: "unknown", linter: "unknown", monorepo: "none" }),
|
|
182
|
-
);
|
|
183
|
-
logger.info("init", "Created global constitution", { path: constitutionPath });
|
|
184
|
-
} else {
|
|
185
|
-
logger.info("init", "Global constitution already exists", { path: constitutionPath });
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Create ~/.nax/hooks/ directory if it doesn't exist
|
|
189
|
-
const hooksDir = join(globalDir, "hooks");
|
|
190
|
-
if (!existsSync(hooksDir)) {
|
|
191
|
-
await mkdir(hooksDir, { recursive: true });
|
|
192
|
-
logger.info("init", "Created global hooks directory", { path: hooksDir });
|
|
193
|
-
} else {
|
|
194
|
-
logger.info("init", "Global hooks directory already exists", { path: hooksDir });
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
logger.info("init", "Global config initialized successfully", { path: globalDir });
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Initialize project nax directory (nax/)
|
|
202
|
-
*/
|
|
203
|
-
export async function initProject(projectRoot: string, options?: InitProjectOptions): Promise<void> {
|
|
204
|
-
const logger = getLogger();
|
|
205
|
-
const projectDir = projectConfigDir(projectRoot);
|
|
206
|
-
|
|
207
|
-
// Create nax/ directory if it doesn't exist
|
|
208
|
-
if (!existsSync(projectDir)) {
|
|
209
|
-
await mkdir(projectDir, { recursive: true });
|
|
210
|
-
logger.info("init", "Created project config directory", { path: projectDir });
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Detect project stack and build config
|
|
214
|
-
const stack = detectStack(projectRoot);
|
|
215
|
-
const projectConfig = buildInitConfig(stack);
|
|
216
|
-
logger.info("init", "Detected project stack", {
|
|
217
|
-
runtime: stack.runtime,
|
|
218
|
-
language: stack.language,
|
|
219
|
-
linter: stack.linter,
|
|
220
|
-
monorepo: stack.monorepo,
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// Create nax/config.json if it doesn't exist
|
|
224
|
-
const configPath = join(projectDir, "config.json");
|
|
225
|
-
if (!existsSync(configPath)) {
|
|
226
|
-
await Bun.write(configPath, `${JSON.stringify(projectConfig, null, 2)}\n`);
|
|
227
|
-
logger.info("init", "Created project config", { path: configPath });
|
|
228
|
-
} else {
|
|
229
|
-
logger.info("init", "Project config already exists", { path: configPath });
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Generate context.md (template or LLM-enhanced with --ai flag)
|
|
233
|
-
await initContext(projectRoot, { ai: options?.ai, force: options?.force });
|
|
234
|
-
|
|
235
|
-
// Create nax/constitution.md with stack-aware content
|
|
236
|
-
const constitutionPath = join(projectDir, "constitution.md");
|
|
237
|
-
if (!existsSync(constitutionPath) || options?.force) {
|
|
238
|
-
await Bun.write(constitutionPath, buildConstitution(stack));
|
|
239
|
-
logger.info("init", "Created project constitution", { path: constitutionPath });
|
|
240
|
-
} else {
|
|
241
|
-
logger.info("init", "Project constitution already exists", { path: constitutionPath });
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Create nax/hooks/ directory if it doesn't exist
|
|
245
|
-
const hooksDir = join(projectDir, "hooks");
|
|
246
|
-
if (!existsSync(hooksDir)) {
|
|
247
|
-
await mkdir(hooksDir, { recursive: true });
|
|
248
|
-
logger.info("init", "Created project hooks directory", { path: hooksDir });
|
|
249
|
-
} else {
|
|
250
|
-
logger.info("init", "Project hooks directory already exists", { path: hooksDir });
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Update .gitignore to include nax-specific entries
|
|
254
|
-
await updateGitignore(projectRoot);
|
|
255
|
-
|
|
256
|
-
// Create prompt templates
|
|
257
|
-
// Pass autoWireConfig: false to prevent auto-wiring prompts.overrides
|
|
258
|
-
// Templates are created but not activated until user explicitly configures them
|
|
259
|
-
await promptsInitCommand({ workdir: projectRoot, force: false, autoWireConfig: false });
|
|
260
|
-
|
|
261
|
-
// Print summary
|
|
262
|
-
console.log("\n[OK] nax init complete. Created files:");
|
|
263
|
-
console.log(" - nax/config.json");
|
|
264
|
-
console.log(" - nax/context.md");
|
|
265
|
-
console.log(" - nax/constitution.md");
|
|
266
|
-
console.log(" - nax/hooks/");
|
|
267
|
-
console.log(" - nax/templates/");
|
|
268
|
-
console.log("\nNext steps:");
|
|
269
|
-
console.log(" 1. Review nax/context.md and fill in TODOs");
|
|
270
|
-
console.log(" 2. Review nax/config.json and adjust quality commands");
|
|
271
|
-
console.log(" 3. Run: nax generate");
|
|
272
|
-
console.log(" 4. Run: nax plan");
|
|
273
|
-
console.log(" 5. Run: nax run");
|
|
274
|
-
|
|
275
|
-
logger.info("init", "Project config initialized successfully", { path: projectDir });
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Run init command
|
|
280
|
-
*/
|
|
281
|
-
export async function initCommand(options: InitOptions = {}): Promise<void> {
|
|
282
|
-
if (options.global) {
|
|
283
|
-
await initGlobal();
|
|
284
|
-
} else if (options.package) {
|
|
285
|
-
const projectRoot = options.projectRoot ?? process.cwd();
|
|
286
|
-
await initPackage(projectRoot, options.package);
|
|
287
|
-
console.log("\n[OK] Package scaffold created.");
|
|
288
|
-
console.log(` Created: ${options.package}/nax/context.md`);
|
|
289
|
-
console.log("\nNext steps:");
|
|
290
|
-
console.log(` 1. Review ${options.package}/nax/context.md and fill in TODOs`);
|
|
291
|
-
console.log(` 2. Run: nax generate --package ${options.package}`);
|
|
292
|
-
} else {
|
|
293
|
-
const projectRoot = options.projectRoot ?? process.cwd();
|
|
294
|
-
await initProject(projectRoot);
|
|
295
|
-
}
|
|
296
|
-
}
|
package/src/cli/interact.ts
DELETED
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Interact CLI Command (v0.15.0 US-006)
|
|
3
|
-
*
|
|
4
|
-
* Manage pending interactions from CLI:
|
|
5
|
-
* - nax interact list -f <feature>
|
|
6
|
-
* - nax interact respond <id> --action approve|reject|choose|input --value <val>
|
|
7
|
-
* - nax interact cancel <id>
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { existsSync } from "node:fs";
|
|
11
|
-
import { join } from "node:path";
|
|
12
|
-
import chalk from "chalk";
|
|
13
|
-
import { resolveProject } from "../commands/common";
|
|
14
|
-
import type { InteractionRequest, InteractionResponse } from "../interaction";
|
|
15
|
-
import {
|
|
16
|
-
deletePendingInteraction,
|
|
17
|
-
listPendingInteractions,
|
|
18
|
-
loadPendingInteraction,
|
|
19
|
-
savePendingInteraction,
|
|
20
|
-
} from "../interaction";
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Options for interact list command
|
|
24
|
-
*/
|
|
25
|
-
export interface InteractListOptions {
|
|
26
|
-
/** Feature name (required) */
|
|
27
|
-
feature: string;
|
|
28
|
-
/** Explicit project directory */
|
|
29
|
-
dir?: string;
|
|
30
|
-
/** JSON output mode */
|
|
31
|
-
json?: boolean;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Options for interact respond command
|
|
36
|
-
*/
|
|
37
|
-
export interface InteractRespondOptions {
|
|
38
|
-
/** Feature name */
|
|
39
|
-
feature?: string;
|
|
40
|
-
/** Explicit project directory */
|
|
41
|
-
dir?: string;
|
|
42
|
-
/** Action to take */
|
|
43
|
-
action: "approve" | "reject" | "choose" | "input" | "skip" | "abort";
|
|
44
|
-
/** Value (for choose/input) */
|
|
45
|
-
value?: string;
|
|
46
|
-
/** JSON output mode */
|
|
47
|
-
json?: boolean;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Options for interact cancel command
|
|
52
|
-
*/
|
|
53
|
-
export interface InteractCancelOptions {
|
|
54
|
-
/** Feature name */
|
|
55
|
-
feature?: string;
|
|
56
|
-
/** Explicit project directory */
|
|
57
|
-
dir?: string;
|
|
58
|
-
/** JSON output mode */
|
|
59
|
-
json?: boolean;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* List pending interactions for a feature
|
|
64
|
-
*/
|
|
65
|
-
export async function interactListCommand(options: InteractListOptions): Promise<void> {
|
|
66
|
-
const resolved = resolveProject({
|
|
67
|
-
dir: options.dir,
|
|
68
|
-
feature: options.feature,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
if (!resolved.featureDir) {
|
|
72
|
-
throw new Error("Feature directory not resolved");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const interactionsDir = join(resolved.featureDir, "interactions");
|
|
76
|
-
if (!existsSync(interactionsDir)) {
|
|
77
|
-
if (options.json) {
|
|
78
|
-
console.log(JSON.stringify({ interactions: [] }));
|
|
79
|
-
} else {
|
|
80
|
-
console.log(chalk.dim("No pending interactions."));
|
|
81
|
-
}
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const ids = await listPendingInteractions(resolved.featureDir);
|
|
86
|
-
|
|
87
|
-
if (ids.length === 0) {
|
|
88
|
-
if (options.json) {
|
|
89
|
-
console.log(JSON.stringify({ interactions: [] }));
|
|
90
|
-
} else {
|
|
91
|
-
console.log(chalk.dim("No pending interactions."));
|
|
92
|
-
}
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Load full requests
|
|
97
|
-
const requests: InteractionRequest[] = [];
|
|
98
|
-
for (const id of ids) {
|
|
99
|
-
const req = await loadPendingInteraction(id, resolved.featureDir);
|
|
100
|
-
if (req) {
|
|
101
|
-
requests.push(req);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (options.json) {
|
|
106
|
-
console.log(JSON.stringify({ interactions: requests }, null, 2));
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Display table
|
|
111
|
-
console.log(chalk.bold(`\n📬 Pending Interactions (${options.feature})\n`));
|
|
112
|
-
|
|
113
|
-
for (const req of requests) {
|
|
114
|
-
const safety = req.metadata?.safety ?? "unknown";
|
|
115
|
-
const safetyIcon = safety === "red" ? "🔴" : safety === "yellow" ? "🟡" : "🟢";
|
|
116
|
-
const timeRemaining = req.timeout ? Math.max(0, req.createdAt + req.timeout - Date.now()) : null;
|
|
117
|
-
|
|
118
|
-
console.log(`${safetyIcon} ${chalk.bold(req.id)}`);
|
|
119
|
-
console.log(chalk.dim(` Type: ${req.type}`));
|
|
120
|
-
console.log(chalk.dim(` Stage: ${req.stage}`));
|
|
121
|
-
console.log(chalk.dim(` Summary: ${req.summary}`));
|
|
122
|
-
if (req.storyId) {
|
|
123
|
-
console.log(chalk.dim(` Story: ${req.storyId}`));
|
|
124
|
-
}
|
|
125
|
-
console.log(chalk.dim(` Fallback: ${req.fallback}`));
|
|
126
|
-
if (timeRemaining !== null) {
|
|
127
|
-
const timeoutSec = Math.floor(timeRemaining / 1000);
|
|
128
|
-
console.log(chalk.dim(` Timeout: ${timeoutSec}s remaining`));
|
|
129
|
-
}
|
|
130
|
-
if (req.options && req.options.length > 0) {
|
|
131
|
-
console.log(chalk.dim(" Options:"));
|
|
132
|
-
for (const opt of req.options) {
|
|
133
|
-
console.log(chalk.dim(` [${opt.key}] ${opt.label}`));
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
console.log();
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Respond to a pending interaction
|
|
142
|
-
*/
|
|
143
|
-
export async function interactRespondCommand(requestId: string, options: InteractRespondOptions): Promise<void> {
|
|
144
|
-
// Find the feature by searching all features for the request
|
|
145
|
-
let featureDir: string | null = null;
|
|
146
|
-
let request: InteractionRequest | null = null;
|
|
147
|
-
|
|
148
|
-
if (options.feature) {
|
|
149
|
-
const resolved = resolveProject({
|
|
150
|
-
dir: options.dir,
|
|
151
|
-
feature: options.feature,
|
|
152
|
-
});
|
|
153
|
-
featureDir = resolved.featureDir ?? null;
|
|
154
|
-
if (featureDir) {
|
|
155
|
-
request = await loadPendingInteraction(requestId, featureDir);
|
|
156
|
-
}
|
|
157
|
-
} else {
|
|
158
|
-
// Search all features
|
|
159
|
-
const resolved = resolveProject({ dir: options.dir });
|
|
160
|
-
const featuresDir = join(resolved.projectDir, "nax", "features");
|
|
161
|
-
if (existsSync(featuresDir)) {
|
|
162
|
-
const { readdirSync } = await import("node:fs");
|
|
163
|
-
const features = readdirSync(featuresDir, { withFileTypes: true })
|
|
164
|
-
.filter((e) => e.isDirectory())
|
|
165
|
-
.map((e) => e.name);
|
|
166
|
-
|
|
167
|
-
for (const feature of features) {
|
|
168
|
-
const dir = join(featuresDir, feature);
|
|
169
|
-
const req = await loadPendingInteraction(requestId, dir);
|
|
170
|
-
if (req) {
|
|
171
|
-
request = req;
|
|
172
|
-
featureDir = dir;
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (!request || !featureDir) {
|
|
180
|
-
throw new Error(`Interaction request not found: ${requestId}`);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Validate action matches request type
|
|
184
|
-
if (options.action === "choose" && request.type !== "choose") {
|
|
185
|
-
throw new Error(`Action "choose" only valid for type "choose" (request is ${request.type})`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (options.action === "input" && request.type !== "input") {
|
|
189
|
-
throw new Error(`Action "input" only valid for type "input" (request is ${request.type})`);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (options.action === "choose" && !options.value) {
|
|
193
|
-
throw new Error("--value required for action choose");
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (options.action === "input" && !options.value) {
|
|
197
|
-
throw new Error("--value required for action input");
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Create response
|
|
201
|
-
const response: InteractionResponse = {
|
|
202
|
-
requestId,
|
|
203
|
-
action: options.action,
|
|
204
|
-
value: options.value,
|
|
205
|
-
respondedBy: "cli",
|
|
206
|
-
respondedAt: Date.now(),
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
// Save response (write to responses/ directory)
|
|
210
|
-
const responsesDir = join(featureDir, "responses");
|
|
211
|
-
await Bun.write(join(responsesDir, ".gitkeep"), "");
|
|
212
|
-
const responseFile = join(responsesDir, `${requestId}.json`);
|
|
213
|
-
await Bun.write(responseFile, JSON.stringify(response, null, 2));
|
|
214
|
-
|
|
215
|
-
// Delete pending interaction
|
|
216
|
-
await deletePendingInteraction(requestId, featureDir);
|
|
217
|
-
|
|
218
|
-
if (options.json) {
|
|
219
|
-
console.log(JSON.stringify({ success: true, response }));
|
|
220
|
-
} else {
|
|
221
|
-
console.log(chalk.green(`✅ Response recorded: ${options.action}`));
|
|
222
|
-
if (options.value) {
|
|
223
|
-
console.log(chalk.dim(` Value: ${options.value}`));
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Cancel a pending interaction (applies fallback)
|
|
230
|
-
*/
|
|
231
|
-
export async function interactCancelCommand(requestId: string, options: InteractCancelOptions): Promise<void> {
|
|
232
|
-
// Find the feature by searching all features for the request
|
|
233
|
-
let featureDir: string | null = null;
|
|
234
|
-
let request: InteractionRequest | null = null;
|
|
235
|
-
|
|
236
|
-
if (options.feature) {
|
|
237
|
-
const resolved = resolveProject({
|
|
238
|
-
dir: options.dir,
|
|
239
|
-
feature: options.feature,
|
|
240
|
-
});
|
|
241
|
-
featureDir = resolved.featureDir ?? null;
|
|
242
|
-
if (featureDir) {
|
|
243
|
-
request = await loadPendingInteraction(requestId, featureDir);
|
|
244
|
-
}
|
|
245
|
-
} else {
|
|
246
|
-
// Search all features
|
|
247
|
-
const resolved = resolveProject({ dir: options.dir });
|
|
248
|
-
const featuresDir = join(resolved.projectDir, "nax", "features");
|
|
249
|
-
if (existsSync(featuresDir)) {
|
|
250
|
-
const { readdirSync } = await import("node:fs");
|
|
251
|
-
const features = readdirSync(featuresDir, { withFileTypes: true })
|
|
252
|
-
.filter((e) => e.isDirectory())
|
|
253
|
-
.map((e) => e.name);
|
|
254
|
-
|
|
255
|
-
for (const feature of features) {
|
|
256
|
-
const dir = join(featuresDir, feature);
|
|
257
|
-
const req = await loadPendingInteraction(requestId, dir);
|
|
258
|
-
if (req) {
|
|
259
|
-
request = req;
|
|
260
|
-
featureDir = dir;
|
|
261
|
-
break;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (!request || !featureDir) {
|
|
268
|
-
throw new Error(`Interaction request not found: ${requestId}`);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Create response with fallback action
|
|
272
|
-
const fallbackAction = request.fallback === "continue" ? "approve" : request.fallback === "skip" ? "skip" : "abort";
|
|
273
|
-
|
|
274
|
-
const response: InteractionResponse = {
|
|
275
|
-
requestId,
|
|
276
|
-
action: fallbackAction,
|
|
277
|
-
respondedBy: "cli-cancel",
|
|
278
|
-
respondedAt: Date.now(),
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
// Save response
|
|
282
|
-
const responsesDir = join(featureDir, "responses");
|
|
283
|
-
await Bun.write(join(responsesDir, ".gitkeep"), "");
|
|
284
|
-
const responseFile = join(responsesDir, `${requestId}.json`);
|
|
285
|
-
await Bun.write(responseFile, JSON.stringify(response, null, 2));
|
|
286
|
-
|
|
287
|
-
// Delete pending interaction
|
|
288
|
-
await deletePendingInteraction(requestId, featureDir);
|
|
289
|
-
|
|
290
|
-
if (options.json) {
|
|
291
|
-
console.log(JSON.stringify({ success: true, response }));
|
|
292
|
-
} else {
|
|
293
|
-
console.log(chalk.yellow(`⏭ Interaction cancelled (fallback: ${request.fallback})`));
|
|
294
|
-
}
|
|
295
|
-
}
|