@nathapp/nax 0.50.2 → 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 +579 -373
- 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 -423
- 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 -135
- 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 -218
- 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 -217
- 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 -520
- package/src/config/schema-types.ts +0 -53
- package/src/config/schema.ts +0 -60
- package/src/config/schemas.ts +0 -425
- 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 -280
- 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 -140
- 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
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code Agent - Interactive (TUI) Mode
|
|
3
|
-
*
|
|
4
|
-
* Handles terminal UI interactions with the Claude agent.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { PidRegistry } from "../../execution/pid-registry";
|
|
8
|
-
import { getLogger } from "../../logger";
|
|
9
|
-
import type { AgentRunOptions, InteractiveRunOptions, PtyHandle } from "../types";
|
|
10
|
-
import { buildAllowedEnv } from "./execution";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Run Claude agent in interactive (TTY) mode for TUI output.
|
|
14
|
-
*
|
|
15
|
-
* @param binary - Path to claude binary
|
|
16
|
-
* @param options - Interactive run options
|
|
17
|
-
* @param pidRegistry - PID registry for cleanup
|
|
18
|
-
* @returns PTY handle for stdin/stdout/kill control
|
|
19
|
-
*/
|
|
20
|
-
export function runInteractiveMode(
|
|
21
|
-
binary: string,
|
|
22
|
-
options: InteractiveRunOptions,
|
|
23
|
-
pidRegistry: PidRegistry,
|
|
24
|
-
): PtyHandle {
|
|
25
|
-
const model = options.modelDef.model;
|
|
26
|
-
const cmd = [binary, "--model", model, options.prompt];
|
|
27
|
-
|
|
28
|
-
// BUN-001: Replaced node-pty with Bun.spawn (piped stdio).
|
|
29
|
-
// runInteractive() is TUI-only and currently dormant in headless nax runs.
|
|
30
|
-
// TERM + FORCE_COLOR preserve formatting output from Claude Code.
|
|
31
|
-
const allowedEnv = buildAllowedEnv(options as unknown as AgentRunOptions);
|
|
32
|
-
const proc = Bun.spawn(cmd, {
|
|
33
|
-
cwd: options.workdir,
|
|
34
|
-
env: { ...allowedEnv, TERM: "xterm-256color", FORCE_COLOR: "1" },
|
|
35
|
-
stdin: "pipe",
|
|
36
|
-
stdout: "pipe",
|
|
37
|
-
stderr: "inherit",
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
pidRegistry.register(proc.pid).catch(() => {});
|
|
41
|
-
|
|
42
|
-
// Stream stdout to onOutput callback
|
|
43
|
-
(async () => {
|
|
44
|
-
try {
|
|
45
|
-
for await (const chunk of proc.stdout) {
|
|
46
|
-
options.onOutput(Buffer.from(chunk));
|
|
47
|
-
}
|
|
48
|
-
} catch (err) {
|
|
49
|
-
// BUG-21: Handle stream errors to avoid unhandled rejections
|
|
50
|
-
getLogger()?.error("agent", "runInteractive stdout error", { err });
|
|
51
|
-
}
|
|
52
|
-
})();
|
|
53
|
-
|
|
54
|
-
// Fire onExit when process completes
|
|
55
|
-
proc.exited
|
|
56
|
-
.then((code) => {
|
|
57
|
-
pidRegistry.unregister(proc.pid).catch(() => {});
|
|
58
|
-
options.onExit(code ?? 1);
|
|
59
|
-
})
|
|
60
|
-
.catch((err) => {
|
|
61
|
-
// BUG-22: Guard against onExit or unregister throws
|
|
62
|
-
getLogger()?.error("agent", "runInteractive exit error", { err });
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
write: (data: string) => {
|
|
67
|
-
proc.stdin.write(data);
|
|
68
|
-
},
|
|
69
|
-
resize: (_cols: number, _rows: number) => {
|
|
70
|
-
/* no-op: Bun.spawn has no PTY resize */
|
|
71
|
-
},
|
|
72
|
-
kill: () => {
|
|
73
|
-
proc.kill();
|
|
74
|
-
},
|
|
75
|
-
pid: proc.pid,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
/**
|
|
5
|
-
* Claude Code Plan Logic
|
|
6
|
-
*
|
|
7
|
-
* Extracted from claude.ts: plan(), buildPlanCommand()
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { resolvePermissions } from "../../config/permissions";
|
|
11
|
-
import type { PidRegistry } from "../../execution/pid-registry";
|
|
12
|
-
import { withProcessTimeout } from "../../execution/timeout-handler";
|
|
13
|
-
import { getLogger } from "../../logger";
|
|
14
|
-
import { resolveBalancedModelDef } from "../shared/model-resolution";
|
|
15
|
-
import type { PlanOptions, PlanResult } from "../shared/types-extended";
|
|
16
|
-
import type { AgentRunOptions } from "../types";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Build the CLI command for plan mode.
|
|
20
|
-
*/
|
|
21
|
-
export function buildPlanCommand(binary: string, options: PlanOptions): string[] {
|
|
22
|
-
const cmd = [binary, "--permission-mode", "plan"];
|
|
23
|
-
|
|
24
|
-
// Add model if specified (explicit or resolved from config)
|
|
25
|
-
let modelDef = options.modelDef;
|
|
26
|
-
if (!modelDef && options.config) {
|
|
27
|
-
modelDef = resolveBalancedModelDef(options.config);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (modelDef) {
|
|
31
|
-
cmd.push("--model", modelDef.model);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Resolve permission mode from config
|
|
35
|
-
const { skipPermissions } = resolvePermissions(
|
|
36
|
-
options.config as import("../../config").NaxConfig | undefined,
|
|
37
|
-
"plan",
|
|
38
|
-
);
|
|
39
|
-
if (skipPermissions) {
|
|
40
|
-
cmd.push("--dangerously-skip-permissions");
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Add prompt with codebase context and input file if available
|
|
44
|
-
let fullPrompt = options.prompt;
|
|
45
|
-
if (options.codebaseContext) {
|
|
46
|
-
fullPrompt = `${options.codebaseContext}\n\n${options.prompt}`;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// For non-interactive mode, include input file content in the prompt
|
|
50
|
-
if (options.inputFile) {
|
|
51
|
-
try {
|
|
52
|
-
const inputContent = require("node:fs").readFileSync(
|
|
53
|
-
require("node:path").resolve(options.workdir, options.inputFile),
|
|
54
|
-
"utf-8",
|
|
55
|
-
);
|
|
56
|
-
fullPrompt = `${fullPrompt}\n\n## Input Requirements\n\n${inputContent}`;
|
|
57
|
-
} catch (error) {
|
|
58
|
-
throw new Error(`Failed to read input file ${options.inputFile}: ${(error as Error).message}`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (!options.interactive) {
|
|
63
|
-
cmd.push("-p", fullPrompt);
|
|
64
|
-
} else {
|
|
65
|
-
// Interactive mode: pass prompt as initial message, agent will ask follow-ups
|
|
66
|
-
cmd.push("-p", fullPrompt);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return cmd;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Run Claude Code in plan mode to generate a feature specification.
|
|
74
|
-
*/
|
|
75
|
-
export async function runPlan(
|
|
76
|
-
binary: string,
|
|
77
|
-
options: PlanOptions,
|
|
78
|
-
pidRegistry: PidRegistry,
|
|
79
|
-
buildAllowedEnv: (options: AgentRunOptions) => Record<string, string | undefined>,
|
|
80
|
-
): Promise<PlanResult> {
|
|
81
|
-
const { resolveBalancedModelDef } = await import("../shared/model-resolution");
|
|
82
|
-
|
|
83
|
-
const cmd = buildPlanCommand(binary, options);
|
|
84
|
-
|
|
85
|
-
// Resolve model: explicit modelDef > config.models.balanced > throw
|
|
86
|
-
let modelDef = options.modelDef;
|
|
87
|
-
if (!modelDef) {
|
|
88
|
-
if (!options.config) {
|
|
89
|
-
throw new Error("runPlan() requires either modelDef or config with models.balanced configured");
|
|
90
|
-
}
|
|
91
|
-
modelDef = resolveBalancedModelDef(options.config);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const envOptions: AgentRunOptions = {
|
|
95
|
-
workdir: options.workdir,
|
|
96
|
-
modelDef,
|
|
97
|
-
prompt: "",
|
|
98
|
-
modelTier: options.modelTier || "balanced",
|
|
99
|
-
timeoutSeconds: 600,
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const PLAN_TIMEOUT_MS = 600_000; // 10 minutes
|
|
103
|
-
|
|
104
|
-
if (options.interactive) {
|
|
105
|
-
// Interactive mode: inherit stdio
|
|
106
|
-
const proc = Bun.spawn(cmd, {
|
|
107
|
-
cwd: options.workdir,
|
|
108
|
-
stdin: "inherit",
|
|
109
|
-
stdout: "inherit",
|
|
110
|
-
stderr: "inherit",
|
|
111
|
-
env: buildAllowedEnv(envOptions),
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// Register PID
|
|
115
|
-
await pidRegistry.register(proc.pid);
|
|
116
|
-
|
|
117
|
-
let exitCode: number;
|
|
118
|
-
try {
|
|
119
|
-
const timeoutResult = await withProcessTimeout(proc, PLAN_TIMEOUT_MS, {
|
|
120
|
-
graceMs: 5000,
|
|
121
|
-
});
|
|
122
|
-
exitCode = timeoutResult.exitCode;
|
|
123
|
-
} finally {
|
|
124
|
-
// Unregister PID after exit
|
|
125
|
-
await pidRegistry.unregister(proc.pid);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (exitCode !== 0) {
|
|
129
|
-
throw new Error(`Plan mode failed with exit code ${exitCode}`);
|
|
130
|
-
}
|
|
131
|
-
return { specContent: "", conversationLog: "" };
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Non-interactive: redirect stdout to temp file via Bun.file()
|
|
135
|
-
|
|
136
|
-
const tempDir = mkdtempSync(join(tmpdir(), "nax-plan-"));
|
|
137
|
-
const outFile = join(tempDir, "stdout.txt");
|
|
138
|
-
const errFile = join(tempDir, "stderr.txt");
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
const proc = Bun.spawn(cmd, {
|
|
142
|
-
cwd: options.workdir,
|
|
143
|
-
stdin: "ignore",
|
|
144
|
-
stdout: Bun.file(outFile),
|
|
145
|
-
stderr: Bun.file(errFile),
|
|
146
|
-
env: buildAllowedEnv(envOptions),
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// Register PID
|
|
150
|
-
await pidRegistry.register(proc.pid);
|
|
151
|
-
|
|
152
|
-
let exitCode: number;
|
|
153
|
-
try {
|
|
154
|
-
const timeoutResult = await withProcessTimeout(proc, PLAN_TIMEOUT_MS, {
|
|
155
|
-
graceMs: 5000,
|
|
156
|
-
});
|
|
157
|
-
exitCode = timeoutResult.exitCode;
|
|
158
|
-
} finally {
|
|
159
|
-
// Unregister PID after exit
|
|
160
|
-
await pidRegistry.unregister(proc.pid);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const specContent = await Bun.file(outFile).text();
|
|
164
|
-
const conversationLog = await Bun.file(errFile).text();
|
|
165
|
-
|
|
166
|
-
if (exitCode !== 0) {
|
|
167
|
-
throw new Error(`Plan mode failed with exit code ${exitCode}: ${conversationLog || "unknown error"}`);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return { specContent, conversationLog };
|
|
171
|
-
} finally {
|
|
172
|
-
try {
|
|
173
|
-
rmSync(tempDir, { recursive: true });
|
|
174
|
-
} catch (error) {
|
|
175
|
-
const logger = getLogger();
|
|
176
|
-
logger?.debug("agent", "Failed to clean up temp directory", { error, tempDir });
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Codex Agent Adapter — implements AgentAdapter interface
|
|
3
|
-
*
|
|
4
|
-
* Provides uniform interface for spawning Codex agent processes,
|
|
5
|
-
* supporting one-shot completions and headless execution.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type {
|
|
9
|
-
AgentAdapter,
|
|
10
|
-
AgentCapabilities,
|
|
11
|
-
AgentResult,
|
|
12
|
-
AgentRunOptions,
|
|
13
|
-
CompleteOptions,
|
|
14
|
-
DecomposeOptions,
|
|
15
|
-
DecomposeResult,
|
|
16
|
-
PlanOptions,
|
|
17
|
-
PlanResult,
|
|
18
|
-
} from "../types";
|
|
19
|
-
import { CompleteError } from "../types";
|
|
20
|
-
|
|
21
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
22
|
-
// Injectable dependencies — matches the _deps pattern used in claude.ts
|
|
23
|
-
// These are replaced in unit tests to intercept Bun.spawn calls.
|
|
24
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
export const _codexRunDeps = {
|
|
27
|
-
which(name: string): string | null {
|
|
28
|
-
return Bun.which(name);
|
|
29
|
-
},
|
|
30
|
-
spawn(
|
|
31
|
-
cmd: string[],
|
|
32
|
-
opts: { cwd?: string; stdout: "pipe"; stderr: "pipe" | "inherit"; env?: Record<string, string | undefined> },
|
|
33
|
-
): {
|
|
34
|
-
stdout: ReadableStream<Uint8Array>;
|
|
35
|
-
stderr: ReadableStream<Uint8Array>;
|
|
36
|
-
exited: Promise<number>;
|
|
37
|
-
pid: number;
|
|
38
|
-
kill(signal?: number | NodeJS.Signals): void;
|
|
39
|
-
} {
|
|
40
|
-
return Bun.spawn(cmd, opts) as unknown as {
|
|
41
|
-
stdout: ReadableStream<Uint8Array>;
|
|
42
|
-
stderr: ReadableStream<Uint8Array>;
|
|
43
|
-
exited: Promise<number>;
|
|
44
|
-
pid: number;
|
|
45
|
-
kill(signal?: number | NodeJS.Signals): void;
|
|
46
|
-
};
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export const _codexCompleteDeps = {
|
|
51
|
-
spawn(
|
|
52
|
-
cmd: string[],
|
|
53
|
-
opts: { stdout: "pipe"; stderr: "pipe" | "inherit" },
|
|
54
|
-
): {
|
|
55
|
-
stdout: ReadableStream<Uint8Array>;
|
|
56
|
-
stderr: ReadableStream<Uint8Array>;
|
|
57
|
-
exited: Promise<number>;
|
|
58
|
-
pid: number;
|
|
59
|
-
} {
|
|
60
|
-
return Bun.spawn(cmd, opts) as unknown as {
|
|
61
|
-
stdout: ReadableStream<Uint8Array>;
|
|
62
|
-
stderr: ReadableStream<Uint8Array>;
|
|
63
|
-
exited: Promise<number>;
|
|
64
|
-
pid: number;
|
|
65
|
-
};
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
70
|
-
// CodexAdapter implementation
|
|
71
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Maximum characters to capture from agent stdout.
|
|
75
|
-
*/
|
|
76
|
-
const MAX_AGENT_OUTPUT_CHARS = 5000;
|
|
77
|
-
|
|
78
|
-
export class CodexAdapter implements AgentAdapter {
|
|
79
|
-
readonly name = "codex";
|
|
80
|
-
readonly displayName = "Codex";
|
|
81
|
-
readonly binary = "codex";
|
|
82
|
-
|
|
83
|
-
readonly capabilities: AgentCapabilities = {
|
|
84
|
-
supportedTiers: ["fast", "balanced"],
|
|
85
|
-
maxContextTokens: 8_000,
|
|
86
|
-
features: new Set<"tdd" | "review" | "refactor" | "batch">(["tdd", "refactor"]),
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
async isInstalled(): Promise<boolean> {
|
|
90
|
-
const path = _codexRunDeps.which("codex");
|
|
91
|
-
return path !== null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
buildCommand(options: AgentRunOptions): string[] {
|
|
95
|
-
return ["codex", "-q", "--prompt", options.prompt];
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async run(options: AgentRunOptions): Promise<AgentResult> {
|
|
99
|
-
const cmd = this.buildCommand(options);
|
|
100
|
-
const startTime = Date.now();
|
|
101
|
-
|
|
102
|
-
const proc = _codexRunDeps.spawn(cmd, {
|
|
103
|
-
cwd: options.workdir,
|
|
104
|
-
stdout: "pipe",
|
|
105
|
-
stderr: "inherit",
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
const exitCode = await proc.exited;
|
|
109
|
-
const stdout = await new Response(proc.stdout).text();
|
|
110
|
-
const durationMs = Date.now() - startTime;
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
success: exitCode === 0,
|
|
114
|
-
exitCode,
|
|
115
|
-
output: stdout.slice(-MAX_AGENT_OUTPUT_CHARS),
|
|
116
|
-
rateLimited: false,
|
|
117
|
-
durationMs,
|
|
118
|
-
estimatedCost: 0,
|
|
119
|
-
pid: proc.pid,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async complete(prompt: string, _options?: CompleteOptions): Promise<string> {
|
|
124
|
-
const cmd = ["codex", "-q", "--prompt", prompt];
|
|
125
|
-
|
|
126
|
-
const proc = _codexCompleteDeps.spawn(cmd, { stdout: "pipe", stderr: "pipe" });
|
|
127
|
-
const exitCode = await proc.exited;
|
|
128
|
-
|
|
129
|
-
const stdout = await new Response(proc.stdout).text();
|
|
130
|
-
const stderr = await new Response(proc.stderr).text();
|
|
131
|
-
const trimmed = stdout.trim();
|
|
132
|
-
|
|
133
|
-
if (exitCode !== 0) {
|
|
134
|
-
const errorDetails = stderr.trim() || trimmed;
|
|
135
|
-
const errorMessage = errorDetails || `complete() failed with exit code ${exitCode}`;
|
|
136
|
-
throw new CompleteError(errorMessage, exitCode);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (!trimmed) {
|
|
140
|
-
throw new CompleteError("complete() returned empty output");
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return trimmed;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async plan(_options: PlanOptions): Promise<PlanResult> {
|
|
147
|
-
throw new Error("CodexAdapter.plan() not implemented");
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
async decompose(_options: DecomposeOptions): Promise<DecomposeResult> {
|
|
151
|
-
throw new Error("CodexAdapter.decompose() not implemented");
|
|
152
|
-
}
|
|
153
|
-
}
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cost calculation functions for all agent adapters.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { ModelTier } from "../../config/schema";
|
|
6
|
-
import { parseTokenUsage } from "./parse";
|
|
7
|
-
import { COST_RATES, MODEL_PRICING } from "./pricing";
|
|
8
|
-
import type { CostEstimate, ModelCostRates, SessionTokenUsage } from "./types";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Estimate cost in USD based on token usage and model tier.
|
|
12
|
-
*
|
|
13
|
-
* @param modelTier - Model tier (fast/balanced/powerful)
|
|
14
|
-
* @param inputTokens - Number of input tokens consumed
|
|
15
|
-
* @param outputTokens - Number of output tokens generated
|
|
16
|
-
* @param customRates - Optional custom rates (overrides tier defaults)
|
|
17
|
-
* @returns Total cost in USD
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```ts
|
|
21
|
-
* const cost = estimateCost("balanced", 10000, 5000);
|
|
22
|
-
* // Sonnet 4.5: (10000/1M * $3.00) + (5000/1M * $15.00) = $0.105
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
export function estimateCost(
|
|
26
|
-
modelTier: ModelTier,
|
|
27
|
-
inputTokens: number,
|
|
28
|
-
outputTokens: number,
|
|
29
|
-
customRates?: ModelCostRates,
|
|
30
|
-
): number {
|
|
31
|
-
const rates = customRates ?? COST_RATES[modelTier];
|
|
32
|
-
const inputCost = (inputTokens / 1_000_000) * rates.inputPer1M;
|
|
33
|
-
const outputCost = (outputTokens / 1_000_000) * rates.outputPer1M;
|
|
34
|
-
return inputCost + outputCost;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Estimate cost from agent output by parsing token usage.
|
|
39
|
-
*
|
|
40
|
-
* Attempts to extract token counts from stdout/stderr, then calculates cost.
|
|
41
|
-
* Returns null if tokens cannot be parsed.
|
|
42
|
-
*
|
|
43
|
-
* @param modelTier - Model tier for cost calculation
|
|
44
|
-
* @param output - Agent stdout + stderr combined
|
|
45
|
-
* @returns Cost estimate with confidence indicator, or null if unparseable
|
|
46
|
-
*/
|
|
47
|
-
export function estimateCostFromOutput(modelTier: ModelTier, output: string): CostEstimate | null {
|
|
48
|
-
const usage = parseTokenUsage(output);
|
|
49
|
-
if (!usage) {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
const cost = estimateCost(modelTier, usage.inputTokens, usage.outputTokens);
|
|
53
|
-
return {
|
|
54
|
-
cost,
|
|
55
|
-
confidence: usage.confidence,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Fallback cost estimation based on runtime duration.
|
|
61
|
-
*
|
|
62
|
-
* Used when token usage cannot be parsed from agent output.
|
|
63
|
-
* Provides conservative estimates using per-minute rates.
|
|
64
|
-
*
|
|
65
|
-
* @param modelTier - Model tier for cost calculation
|
|
66
|
-
* @param durationMs - Agent runtime in milliseconds
|
|
67
|
-
* @returns Cost estimate with 'fallback' confidence
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* ```ts
|
|
71
|
-
* const estimate = estimateCostByDuration("balanced", 120000); // 2 minutes
|
|
72
|
-
* // { cost: 0.10, confidence: 'fallback' }
|
|
73
|
-
* // Sonnet: 2 min * $0.05/min = $0.10
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
76
|
-
export function estimateCostByDuration(modelTier: ModelTier, durationMs: number): CostEstimate {
|
|
77
|
-
const costPerMinute: Record<ModelTier, number> = {
|
|
78
|
-
fast: 0.01,
|
|
79
|
-
balanced: 0.05,
|
|
80
|
-
powerful: 0.15,
|
|
81
|
-
};
|
|
82
|
-
const minutes = durationMs / 60000;
|
|
83
|
-
const cost = minutes * costPerMinute[modelTier];
|
|
84
|
-
return {
|
|
85
|
-
cost,
|
|
86
|
-
confidence: "fallback",
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Format cost estimate with confidence indicator for display.
|
|
92
|
-
*
|
|
93
|
-
* @param estimate - Cost estimate with confidence level
|
|
94
|
-
* @returns Formatted cost string with confidence indicator
|
|
95
|
-
*
|
|
96
|
-
* @example
|
|
97
|
-
* ```ts
|
|
98
|
-
* formatCostWithConfidence({ cost: 0.12, confidence: 'exact' });
|
|
99
|
-
* // "$0.12"
|
|
100
|
-
*
|
|
101
|
-
* formatCostWithConfidence({ cost: 0.15, confidence: 'estimated' });
|
|
102
|
-
* // "~$0.15"
|
|
103
|
-
*
|
|
104
|
-
* formatCostWithConfidence({ cost: 0.05, confidence: 'fallback' });
|
|
105
|
-
* // "~$0.05 (duration-based)"
|
|
106
|
-
* ```
|
|
107
|
-
*/
|
|
108
|
-
export function formatCostWithConfidence(estimate: CostEstimate): string {
|
|
109
|
-
const formattedCost = `$${estimate.cost.toFixed(2)}`;
|
|
110
|
-
|
|
111
|
-
switch (estimate.confidence) {
|
|
112
|
-
case "exact":
|
|
113
|
-
return formattedCost;
|
|
114
|
-
case "estimated":
|
|
115
|
-
return `~${formattedCost}`;
|
|
116
|
-
case "fallback":
|
|
117
|
-
return `~${formattedCost} (duration-based)`;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Calculate USD cost from ACP session token counts using per-model pricing.
|
|
123
|
-
*
|
|
124
|
-
* @param usage - Token counts from cumulative_token_usage
|
|
125
|
-
* @param model - Model identifier (e.g., 'claude-sonnet-4', 'claude-haiku-4-5')
|
|
126
|
-
* @returns Estimated cost in USD
|
|
127
|
-
*/
|
|
128
|
-
export function estimateCostFromTokenUsage(usage: SessionTokenUsage, model: string): number {
|
|
129
|
-
const pricing = MODEL_PRICING[model];
|
|
130
|
-
|
|
131
|
-
if (!pricing) {
|
|
132
|
-
// Fallback: use average rate for unknown models
|
|
133
|
-
const fallbackInputRate = 3 / 1_000_000;
|
|
134
|
-
const fallbackOutputRate = 15 / 1_000_000;
|
|
135
|
-
const inputCost = (usage.input_tokens ?? 0) * fallbackInputRate;
|
|
136
|
-
const outputCost = (usage.output_tokens ?? 0) * fallbackOutputRate;
|
|
137
|
-
const cacheReadCost = (usage.cache_read_input_tokens ?? 0) * (0.5 / 1_000_000);
|
|
138
|
-
const cacheCreationCost = (usage.cache_creation_input_tokens ?? 0) * (2 / 1_000_000);
|
|
139
|
-
return inputCost + outputCost + cacheReadCost + cacheCreationCost;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Convert $/1M rates to $/token
|
|
143
|
-
const inputRate = pricing.input / 1_000_000;
|
|
144
|
-
const outputRate = pricing.output / 1_000_000;
|
|
145
|
-
const cacheReadRate = (pricing.cacheRead ?? pricing.input * 0.1) / 1_000_000;
|
|
146
|
-
const cacheCreationRate = (pricing.cacheCreation ?? pricing.input * 0.33) / 1_000_000;
|
|
147
|
-
|
|
148
|
-
const inputCost = (usage.input_tokens ?? 0) * inputRate;
|
|
149
|
-
const outputCost = (usage.output_tokens ?? 0) * outputRate;
|
|
150
|
-
const cacheReadCost = (usage.cache_read_input_tokens ?? 0) * cacheReadRate;
|
|
151
|
-
const cacheCreationCost = (usage.cache_creation_input_tokens ?? 0) * cacheCreationRate;
|
|
152
|
-
|
|
153
|
-
return inputCost + outputCost + cacheReadCost + cacheCreationCost;
|
|
154
|
-
}
|
package/src/agents/cost/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export type { ModelCostRates, TokenUsage, CostEstimate, TokenUsageWithConfidence, SessionTokenUsage } from "./types";
|
|
2
|
-
export { COST_RATES, MODEL_PRICING } from "./pricing";
|
|
3
|
-
export { parseTokenUsage } from "./parse";
|
|
4
|
-
export {
|
|
5
|
-
estimateCost,
|
|
6
|
-
estimateCostFromOutput,
|
|
7
|
-
estimateCostByDuration,
|
|
8
|
-
formatCostWithConfidence,
|
|
9
|
-
estimateCostFromTokenUsage,
|
|
10
|
-
} from "./calculate";
|
package/src/agents/cost/parse.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token usage parsing from raw agent output strings.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { TokenUsageWithConfidence } from "./types";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Parse Claude Code output for token usage.
|
|
9
|
-
*
|
|
10
|
-
* Supports multiple formats with varying confidence levels:
|
|
11
|
-
* - JSON structured output → "exact" confidence
|
|
12
|
-
* - Markdown/plain text patterns → "estimated" confidence
|
|
13
|
-
*
|
|
14
|
-
* Uses specific regex patterns to reduce false positives.
|
|
15
|
-
*
|
|
16
|
-
* @param output - Agent stdout + stderr combined
|
|
17
|
-
* @returns Token usage with confidence indicator, or null if tokens cannot be parsed
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```ts
|
|
21
|
-
* // JSON format (exact)
|
|
22
|
-
* const usage1 = parseTokenUsage('{"usage": {"input_tokens": 1234, "output_tokens": 5678}}');
|
|
23
|
-
* // { inputTokens: 1234, outputTokens: 5678, confidence: 'exact' }
|
|
24
|
-
*
|
|
25
|
-
* // Markdown format (estimated)
|
|
26
|
-
* const usage2 = parseTokenUsage('Input tokens: 1234\nOutput tokens: 5678');
|
|
27
|
-
* // { inputTokens: 1234, outputTokens: 5678, confidence: 'estimated' }
|
|
28
|
-
*
|
|
29
|
-
* // Unparseable
|
|
30
|
-
* const usage3 = parseTokenUsage('No token data here');
|
|
31
|
-
* // null
|
|
32
|
-
* ```
|
|
33
|
-
*/
|
|
34
|
-
export function parseTokenUsage(output: string): TokenUsageWithConfidence | null {
|
|
35
|
-
// Try JSON format first (most reliable) - confidence: exact
|
|
36
|
-
try {
|
|
37
|
-
const jsonMatch = output.match(
|
|
38
|
-
/\{[^}]*"usage"\s*:\s*\{[^}]*"input_tokens"\s*:\s*(\d+)[^}]*"output_tokens"\s*:\s*(\d+)[^}]*\}[^}]*\}/,
|
|
39
|
-
);
|
|
40
|
-
if (jsonMatch) {
|
|
41
|
-
return {
|
|
42
|
-
inputTokens: Number.parseInt(jsonMatch[1], 10),
|
|
43
|
-
outputTokens: Number.parseInt(jsonMatch[2], 10),
|
|
44
|
-
confidence: "exact",
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Try parsing as full JSON object
|
|
49
|
-
const lines = output.split("\n");
|
|
50
|
-
for (const line of lines) {
|
|
51
|
-
if (line.trim().startsWith("{")) {
|
|
52
|
-
try {
|
|
53
|
-
const parsed = JSON.parse(line);
|
|
54
|
-
if (parsed.usage?.input_tokens && parsed.usage?.output_tokens) {
|
|
55
|
-
return {
|
|
56
|
-
inputTokens: parsed.usage.input_tokens,
|
|
57
|
-
outputTokens: parsed.usage.output_tokens,
|
|
58
|
-
confidence: "exact",
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
} catch {
|
|
62
|
-
// Not valid JSON, continue
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
} catch {
|
|
67
|
-
// JSON parsing failed, try regex patterns
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Try specific markdown-style patterns (more specific to reduce false positives)
|
|
71
|
-
// Match "Input tokens: 1234" or "input_tokens: 1234" or "INPUT TOKENS: 1234"
|
|
72
|
-
// Use word boundary at start, require colon or space after keyword, then digits
|
|
73
|
-
// confidence: estimated (regex-based)
|
|
74
|
-
const inputMatch = output.match(/\b(?:input|input_tokens)\s*:\s*(\d{2,})|(?:input)\s+(?:tokens?)\s*:\s*(\d{2,})/i);
|
|
75
|
-
const outputMatch = output.match(
|
|
76
|
-
/\b(?:output|output_tokens)\s*:\s*(\d{2,})|(?:output)\s+(?:tokens?)\s*:\s*(\d{2,})/i,
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
if (inputMatch && outputMatch) {
|
|
80
|
-
// Extract token counts (may be in capture group 1 or 2)
|
|
81
|
-
const inputTokens = Number.parseInt(inputMatch[1] || inputMatch[2], 10);
|
|
82
|
-
const outputTokens = Number.parseInt(outputMatch[1] || outputMatch[2], 10);
|
|
83
|
-
|
|
84
|
-
// Sanity check: reject if tokens seem unreasonably large (> 1M each)
|
|
85
|
-
if (inputTokens > 1_000_000 || outputTokens > 1_000_000) {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
inputTokens,
|
|
91
|
-
outputTokens,
|
|
92
|
-
confidence: "estimated",
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return null;
|
|
97
|
-
}
|