@curdx/cli 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +50 -8
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -101,7 +101,7 @@ var init_wezterm = __esm({
|
|
|
101
101
|
if (opts.cwd) {
|
|
102
102
|
args.push("--cwd", opts.cwd);
|
|
103
103
|
}
|
|
104
|
-
args.push("--", cmd);
|
|
104
|
+
args.push("--", cmd, ...opts.cmdArgs ?? []);
|
|
105
105
|
const result = await execa2("wezterm", args);
|
|
106
106
|
const paneId = result.stdout.trim();
|
|
107
107
|
if (!paneId) {
|
|
@@ -253,9 +253,41 @@ var init_types = __esm({
|
|
|
253
253
|
// src/runtime/launcher.ts
|
|
254
254
|
var launcher_exports = {};
|
|
255
255
|
__export(launcher_exports, {
|
|
256
|
+
buildProviderCommand: () => buildProviderCommand,
|
|
256
257
|
launch: () => launch
|
|
257
258
|
});
|
|
258
259
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
260
|
+
import { execa as execa3 } from "execa";
|
|
261
|
+
function buildProviderCommand(provider, allowAll) {
|
|
262
|
+
switch (provider) {
|
|
263
|
+
case "claude":
|
|
264
|
+
return {
|
|
265
|
+
cmd: "claude",
|
|
266
|
+
args: allowAll ? ["--dangerously-skip-permissions"] : []
|
|
267
|
+
};
|
|
268
|
+
case "codex":
|
|
269
|
+
return {
|
|
270
|
+
cmd: "codex",
|
|
271
|
+
args: allowAll ? [
|
|
272
|
+
"-c",
|
|
273
|
+
"disable_paste_burst=true",
|
|
274
|
+
"-c",
|
|
275
|
+
'trust_level="trusted"',
|
|
276
|
+
"-c",
|
|
277
|
+
'approval_policy="never"',
|
|
278
|
+
"-c",
|
|
279
|
+
'sandbox_mode="danger-full-access"'
|
|
280
|
+
] : []
|
|
281
|
+
};
|
|
282
|
+
case "gemini":
|
|
283
|
+
return {
|
|
284
|
+
cmd: "gemini",
|
|
285
|
+
args: allowAll ? ["--yolo"] : []
|
|
286
|
+
};
|
|
287
|
+
default:
|
|
288
|
+
return { cmd: provider, args: [] };
|
|
289
|
+
}
|
|
290
|
+
}
|
|
259
291
|
async function launch(options) {
|
|
260
292
|
const projectRoot = process.cwd();
|
|
261
293
|
if (options.resume) {
|
|
@@ -288,9 +320,11 @@ async function freshLaunch(options, projectRoot) {
|
|
|
288
320
|
for (let i = 0; i < additionalProviders.length; i++) {
|
|
289
321
|
const provider = additionalProviders[i];
|
|
290
322
|
try {
|
|
323
|
+
const { args: providerArgs } = buildProviderCommand(provider, options.allowAll);
|
|
291
324
|
const paneId = await terminal.createPane(provider, {
|
|
292
325
|
direction: "right",
|
|
293
|
-
percent: Math.floor(100 / (additionalProviders.length - i + 1))
|
|
326
|
+
percent: Math.floor(100 / (additionalProviders.length - i + 1)),
|
|
327
|
+
cmdArgs: providerArgs
|
|
294
328
|
});
|
|
295
329
|
paneIds[provider] = paneId;
|
|
296
330
|
} catch {
|
|
@@ -326,6 +360,13 @@ async function freshLaunch(options, projectRoot) {
|
|
|
326
360
|
}
|
|
327
361
|
await saveSession(registry, projectRoot).catch(() => {
|
|
328
362
|
});
|
|
363
|
+
const primary = buildProviderCommand(valid[0], options.allowAll);
|
|
364
|
+
const child = execa3(primary.cmd, primary.args, {
|
|
365
|
+
stdio: "inherit",
|
|
366
|
+
cwd: projectRoot,
|
|
367
|
+
reject: false
|
|
368
|
+
});
|
|
369
|
+
await child;
|
|
329
370
|
return {
|
|
330
371
|
providers: valid,
|
|
331
372
|
missing,
|
|
@@ -471,7 +512,7 @@ __export(init_exports, {
|
|
|
471
512
|
import { existsSync as existsSync2 } from "fs";
|
|
472
513
|
import { join as join3, basename } from "path";
|
|
473
514
|
import { homedir } from "os";
|
|
474
|
-
import { execa as
|
|
515
|
+
import { execa as execa4 } from "execa";
|
|
475
516
|
async function detectEnvironment(projectRoot) {
|
|
476
517
|
const [clis, terminal] = await Promise.all([
|
|
477
518
|
detectAvailableClis(),
|
|
@@ -511,7 +552,7 @@ async function installClaudeMem(installPath) {
|
|
|
511
552
|
return "already-installed";
|
|
512
553
|
}
|
|
513
554
|
try {
|
|
514
|
-
await
|
|
555
|
+
await execa4("git", [
|
|
515
556
|
"clone",
|
|
516
557
|
"https://github.com/thedotmack/claude-mem.git",
|
|
517
558
|
targetPath
|
|
@@ -603,7 +644,7 @@ var version = loadVersion();
|
|
|
603
644
|
var KNOWN_PROVIDERS = ["claude", "codex", "gemini"];
|
|
604
645
|
function parseArgs(argv) {
|
|
605
646
|
const program = new Command();
|
|
606
|
-
program.name("curdx").description("AI \u4EE3\u7801\u538B\u69A8\u673A \u2014 \u591A\u6A21\u578B\u5BF9\u6297\u3001\u4E94\u7EA7\u9A8C\u8BC1\u3001PUA \u97AD\u7B56").version(version).argument("[providers...]", "\u989D\u5916\u7684 AI \u6A21\u578B (codex, gemini)").option("-r, --resume", "\u6062\u590D\u4E0A\u6B21\u7EC8\u7AEF\u4F1A\u8BDD", false).exitOverride().configureOutput({
|
|
647
|
+
program.name("curdx").description("AI \u4EE3\u7801\u538B\u69A8\u673A \u2014 \u591A\u6A21\u578B\u5BF9\u6297\u3001\u4E94\u7EA7\u9A8C\u8BC1\u3001PUA \u97AD\u7B56").version(version).argument("[providers...]", "\u989D\u5916\u7684 AI \u6A21\u578B (codex, gemini)").option("-r, --resume", "\u6062\u590D\u4E0A\u6B21\u7EC8\u7AEF\u4F1A\u8BDD", false).option("-a, --allow-all", "\u8DF3\u8FC7\u6240\u6709\u6743\u9650\u786E\u8BA4\uFF08claude: --dangerously-skip-permissions, codex: --full-auto\uFF09", false).exitOverride().configureOutput({
|
|
607
648
|
writeOut: () => {
|
|
608
649
|
},
|
|
609
650
|
writeErr: () => {
|
|
@@ -623,14 +664,15 @@ function parseArgs(argv) {
|
|
|
623
664
|
}
|
|
624
665
|
return {
|
|
625
666
|
providers,
|
|
626
|
-
resume: opts.resume
|
|
667
|
+
resume: opts.resume,
|
|
668
|
+
allowAll: opts.allowAll
|
|
627
669
|
};
|
|
628
670
|
}
|
|
629
671
|
function createCli() {
|
|
630
672
|
const program = new Command();
|
|
631
|
-
program.name("curdx").description("AI \u4EE3\u7801\u538B\u69A8\u673A \u2014 \u591A\u6A21\u578B\u5BF9\u6297\u3001\u4E94\u7EA7\u9A8C\u8BC1\u3001PUA \u97AD\u7B56").version(version).argument("[providers...]", "\u989D\u5916\u7684 AI \u6A21\u578B (codex, gemini)").option("-r, --resume", "\u6062\u590D\u4E0A\u6B21\u7EC8\u7AEF\u4F1A\u8BDD", false).action(async (providers, opts) => {
|
|
673
|
+
program.name("curdx").description("AI \u4EE3\u7801\u538B\u69A8\u673A \u2014 \u591A\u6A21\u578B\u5BF9\u6297\u3001\u4E94\u7EA7\u9A8C\u8BC1\u3001PUA \u97AD\u7B56").version(version).argument("[providers...]", "\u989D\u5916\u7684 AI \u6A21\u578B (codex, gemini)").option("-r, --resume", "\u6062\u590D\u4E0A\u6B21\u7EC8\u7AEF\u4F1A\u8BDD", false).option("-a, --allow-all", "\u8DF3\u8FC7\u6240\u6709\u6743\u9650\u786E\u8BA4", false).action(async (providers, opts) => {
|
|
632
674
|
const { launch: launch2 } = await Promise.resolve().then(() => (init_launcher(), launcher_exports));
|
|
633
|
-
const parsed = parseArgs(["node", "curdx", ...opts.resume ? ["-r"] : [], ...providers]);
|
|
675
|
+
const parsed = parseArgs(["node", "curdx", ...opts.resume ? ["-r"] : [], ...opts.allowAll ? ["-a"] : [], ...providers]);
|
|
634
676
|
await launch2(parsed);
|
|
635
677
|
});
|
|
636
678
|
program.command("init").description("\u521D\u59CB\u5316 curdx \u9879\u76EE\uFF08\u68C0\u6D4B\u73AF\u5883\u3001\u751F\u6210\u914D\u7F6E\u3001\u5B89\u88C5\u63D2\u4EF6\uFF09").action(async () => {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime/detect.ts","../src/runtime/terminal.ts","../src/runtime/wezterm.ts","../src/shared/fs-atomic.ts","../src/runtime/registry.ts","../src/shared/types.ts","../src/runtime/launcher.ts","../src/runtime/completion.ts","../src/runtime/init.ts","../src/runtime/cli.ts"],"sourcesContent":["import { execa } from 'execa'\nimport type { Provider } from './cli.js'\n\nexport interface CliAvailability {\n claude: boolean\n codex: boolean\n gemini: boolean\n}\n\nexport interface ValidationResult {\n valid: string[]\n missing: string[]\n}\n\n/**\n * Detect which AI CLI tools are installed on the system.\n * Uses `which` command for silent detection — never throws.\n */\nexport async function detectAvailableClis(): Promise<CliAvailability> {\n const check = async (cmd: string): Promise<boolean> => {\n try {\n const result = await execa('which', [cmd], { reject: false })\n return result.exitCode === 0\n } catch {\n return false\n }\n }\n\n const [claude, codex, gemini] = await Promise.all([\n check('claude'),\n check('codex'),\n check('gemini'),\n ])\n\n return { claude, codex, gemini }\n}\n\n/**\n * Validate requested providers against detected availability.\n * Returns which providers are valid and which are missing.\n */\nexport function validateProviders(\n requested: string[],\n available: CliAvailability,\n): ValidationResult {\n const valid: string[] = []\n const missing: string[] = []\n\n for (const provider of requested) {\n if (provider in available && available[provider as keyof CliAvailability]) {\n valid.push(provider)\n } else {\n missing.push(provider)\n }\n }\n\n return { valid, missing }\n}\n","import { execaCommand } from 'execa'\n\n/** Information about a terminal pane */\nexport interface PaneInfo {\n paneId: string\n title: string\n isActive: boolean\n}\n\n/** Options for creating a new pane */\nexport interface CreatePaneOptions {\n direction: 'right' | 'bottom'\n percent?: number\n cwd?: string\n title?: string\n}\n\n/** Supported terminal backends */\nexport type TerminalBackend = 'wezterm' | 'tmux'\n\n/** Abstract terminal interface — all backends must implement this */\nexport interface Terminal {\n readonly backend: TerminalBackend\n\n /** Send text to a specific pane */\n sendText(paneId: string, text: string): Promise<void>\n\n /** Create a new split pane running a command */\n createPane(cmd: string, opts: CreatePaneOptions): Promise<string>\n\n /** Check if a pane is still alive */\n isAlive(paneId: string): Promise<boolean>\n\n /** Kill/close a pane */\n killPane(paneId: string): Promise<void>\n\n /** Activate/focus a pane */\n activatePane(paneId: string): Promise<void>\n\n /** List all panes in current window */\n listPanes(): Promise<PaneInfo[]>\n}\n\n/**\n * Detect which terminal backend is available.\n * Prefers WezTerm over tmux.\n */\nexport async function detectTerminalBackend(): Promise<TerminalBackend | null> {\n try {\n const result = await execaCommand('which wezterm', { reject: false })\n if (result.exitCode === 0) return 'wezterm'\n } catch { /* not available */ }\n\n try {\n const result = await execaCommand('which tmux', { reject: false })\n if (result.exitCode === 0) return 'tmux'\n } catch { /* not available */ }\n\n return null\n}\n","import { execa } from 'execa'\nimport type { Terminal, PaneInfo, CreatePaneOptions, TerminalBackend } from './terminal.js'\n\nconst MAX_ARGV_TEXT_LENGTH = 4000\n\n/** WezTerm terminal backend — operates via `wezterm cli` API */\nexport class WeztermTerminal implements Terminal {\n readonly backend: TerminalBackend = 'wezterm'\n\n async sendText(paneId: string, text: string): Promise<void> {\n if (text.length > MAX_ARGV_TEXT_LENGTH) {\n await execa('wezterm', ['cli', 'send-text', '--pane-id', paneId, '--no-paste'], {\n input: text,\n })\n } else {\n await execa('wezterm', [\n 'cli', 'send-text', '--pane-id', paneId, '--no-paste', '--', text,\n ])\n }\n }\n\n async createPane(cmd: string, opts: CreatePaneOptions): Promise<string> {\n // 校验 cmd 防止命令注入\n if (!cmd || /[;&|`$]/.test(cmd)) {\n throw new Error(`Invalid pane command: ${cmd}`)\n }\n\n const percent = opts.percent ?? 50\n const dirFlag = opts.direction === 'right' ? '--right' : '--bottom'\n\n const args = ['cli', 'split-pane', dirFlag, '--percent', String(percent)]\n\n if (opts.cwd) {\n args.push('--cwd', opts.cwd)\n }\n\n args.push('--', cmd)\n\n const result = await execa('wezterm', args)\n const paneId = result.stdout.trim()\n if (!paneId) {\n throw new Error('wezterm split-pane returned empty pane ID')\n }\n return paneId\n }\n\n async isAlive(paneId: string): Promise<boolean> {\n try {\n const panes = await this.listPanes()\n return panes.some((p) => p.paneId === paneId)\n } catch {\n return false\n }\n }\n\n async killPane(paneId: string): Promise<void> {\n await execa('wezterm', ['cli', 'kill-pane', '--pane-id', paneId])\n }\n\n async activatePane(paneId: string): Promise<void> {\n await execa('wezterm', ['cli', 'activate-pane', '--pane-id', paneId])\n }\n\n async listPanes(): Promise<PaneInfo[]> {\n try {\n const result = await execa('wezterm', ['cli', 'list', '--format', 'json'])\n const raw = JSON.parse(result.stdout) as Array<{\n pane_id: number\n title: string\n is_active: boolean\n }>\n return raw.map((p) => ({\n paneId: String(p.pane_id),\n title: p.title,\n isActive: p.is_active,\n }))\n } catch {\n return []\n }\n }\n}\n","import { writeFileSync, renameSync, unlinkSync, mkdirSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { randomBytes } from 'node:crypto'\nimport { stringify as yamlStringify } from 'yaml'\n\nfunction ensureDir(filePath: string): void {\n mkdirSync(dirname(filePath), { recursive: true })\n}\n\nfunction tempPath(filePath: string): string {\n const rand = randomBytes(6).toString('hex')\n // tmp 文件放同目录,避免跨设备 EXDEV 错误\n return join(dirname(filePath), `.${rand}.tmp`)\n}\n\nfunction atomicWriteImpl(filePath: string, content: string): void {\n ensureDir(filePath)\n const tmp = tempPath(filePath)\n try {\n writeFileSync(tmp, content, 'utf-8')\n renameSync(tmp, filePath)\n } catch (err) {\n try { unlinkSync(tmp) } catch { /* 清理失败忽略 */ }\n throw err\n }\n}\n\n/** Atomically write text to file (synchronous) */\nexport function atomicWriteSync(filePath: string, content: string): void {\n atomicWriteImpl(filePath, content)\n}\n\n/** Atomically write JSON data to file */\nexport function atomicWriteJson(filePath: string, data: unknown): void {\n const content = JSON.stringify(data, null, 2)\n atomicWriteImpl(filePath, content)\n}\n\n/** Atomically write YAML data to file */\nexport function atomicWriteYaml(filePath: string, data: unknown): void {\n const content = yamlStringify(data)\n atomicWriteImpl(filePath, content)\n}\n\n/** Atomically write plain text to file */\nexport function atomicWriteText(filePath: string, content: string): void {\n atomicWriteImpl(filePath, content)\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { atomicWriteJson } from '../shared/fs-atomic.js'\nimport type { PaneRegistry, StateFileWrapper } from '../shared/types.js'\n\nexport const SESSION_TTL_DAYS = 7\nconst REGISTRY_FILENAME = 'pane-registry.json'\n\n/**\n * Save pane registry to .curdx/pane-registry.json wrapped in StateFileWrapper.\n */\nexport async function saveSession(data: PaneRegistry, projectRoot: string): Promise<void> {\n const filePath = join(projectRoot, '.curdx', REGISTRY_FILENAME)\n const wrapper: StateFileWrapper<PaneRegistry> = {\n version: 1,\n updatedAt: new Date().toISOString(),\n data,\n }\n await atomicWriteJson(filePath, wrapper)\n}\n\n/**\n * Load pane registry from .curdx/pane-registry.json.\n * Returns null if file doesn't exist.\n */\nexport async function loadSession(projectRoot: string): Promise<PaneRegistry | null> {\n const filePath = join(projectRoot, '.curdx', REGISTRY_FILENAME)\n\n if (!existsSync(filePath)) {\n return null\n }\n\n try {\n const raw = readFileSync(filePath, 'utf-8')\n const wrapper = JSON.parse(raw) as StateFileWrapper<PaneRegistry>\n return wrapper.data\n } catch {\n return null\n }\n}\n\n/**\n * Remove provider entries older than TTL days.\n */\nexport function cleanExpiredEntries(\n registry: PaneRegistry,\n ttlDays: number = SESSION_TTL_DAYS,\n): PaneRegistry {\n const cutoff = Date.now() - ttlDays * 24 * 60 * 60 * 1000\n const cleaned: PaneRegistry = {\n ...registry,\n providers: {},\n }\n\n for (const [key, entry] of Object.entries(registry.providers)) {\n if (entry.updatedAt >= cutoff) {\n cleaned.providers[key] = entry\n }\n }\n\n return cleaned\n}\n","/** Unified state file wrapper — all JSON state files use this format */\nexport interface StateFileWrapper<T> {\n version: number\n updatedAt: string // ISO 8601\n data: T\n}\n\n/** curdx project configuration (.curdx/config.yaml) */\nexport interface CurdxConfig {\n models: string[]\n mode: 0 | 1 | 2 | 3\n verifyLevel: number\n puaEnabled: true // always true, cannot be disabled\n projectName: string\n wezterm: boolean\n tmux: boolean\n}\n\n/** Loop execution state (.curdx/loop-state.json) */\nexport interface LoopState {\n taskIndex: number\n totalTasks: number\n retryCount: number\n phase: 'idle' | 'running' | 'waiting' | 'paused' | 'complete' | 'failed'\n maxRetries: number\n planName: string\n completedTaskIds: string[]\n failedTaskIds: string[]\n lastError: string | null\n}\n\n/** Single pane registry entry */\nexport interface PaneRegistryEntry {\n paneId: string\n provider: 'claude' | 'codex' | 'gemini'\n sessionId: string\n paneTitleMarker: string\n updatedAt: number // unix timestamp\n}\n\n/** Pane registry (.curdx/pane-registry.json) */\nexport interface PaneRegistry {\n ccbSessionId: string\n workDir: string\n terminal: 'wezterm' | 'tmux' | 'none'\n updatedAt: number\n providers: Record<string, PaneRegistryEntry>\n}\n\n/** Workflow execution state (.curdx/workflow-state.json) */\nexport interface WorkflowState {\n currentStage: 'start' | 'research' | 'spec' | 'plan' | 'dev' | 'review' | 'ship' | 'quick' | 'fix' | 'tdd' | 'idle'\n tasks: WorkflowTask[]\n waveIndex: number\n startedAt: string\n}\n\n/** Individual task within a workflow */\nexport interface WorkflowTask {\n id: string\n name: string\n status: 'pending' | 'in-progress' | 'complete' | 'failed'\n wave: number\n files: string[]\n verify: string\n done: string\n commitHash: string | null\n}\n\n/** Context layer type — three-tier context architecture */\nexport type ContextLayerType = 'persistent' | 'session' | 'ephemeral'\n\n/** A single context layer with estimated token usage */\nexport interface ContextLayer {\n type: ContextLayerType\n files: string[]\n estimatedTokens: number\n}\n\n/** Context utilization snapshot */\nexport interface ContextUtilization {\n totalTokens: number\n usedTokens: number\n ratio: number // 0.0 - 1.0\n layers: ContextLayer[]\n}\n\n/** Agent context bundle — clean context prepared for a sub-agent */\nexport interface AgentContextBundle {\n taskId: string\n projectContext: string // project-context.md content\n layers: ContextLayer[]\n totalTokens: number\n createdAt: string // ISO 8601\n}\n\n/** Base error class for all curdx errors */\nexport class CurdxError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly cause?: unknown,\n ) {\n super(message)\n this.name = 'CurdxError'\n }\n}\n\n/** Layer 1: Runtime errors */\nexport class RuntimeError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'RuntimeError'\n }\n}\n\n/** Layer 2: Flow engine errors */\nexport class FlowError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'FlowError'\n }\n}\n\n/** Layer 3: Context engine errors */\nexport class ContextError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'ContextError'\n }\n}\n\n/** Layer 4: Collaboration engine errors */\nexport class CollabError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'CollabError'\n }\n}\n\n/** Layer 5: Verification engine errors */\nexport class VerifyError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'VerifyError'\n }\n}\n\n/** Configuration errors */\nexport class ConfigError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'ConfigError'\n }\n}\n","import { randomBytes } from 'node:crypto'\nimport type { ParsedArgs, Provider } from './cli.js'\nimport { detectAvailableClis, validateProviders } from './detect.js'\nimport { detectTerminalBackend } from './terminal.js'\nimport type { Terminal } from './terminal.js'\nimport { WeztermTerminal } from './wezterm.js'\nimport { saveSession, loadSession, cleanExpiredEntries } from './registry.js'\nimport { RuntimeError } from '../shared/types.js'\nimport type { PaneRegistry, PaneRegistryEntry } from '../shared/types.js'\n\nexport interface LaunchResult {\n providers: string[]\n missing: string[]\n resume: boolean\n launched: boolean\n terminal: Terminal | null\n paneIds: Record<string, string>\n}\n\n/**\n * Launch the curdx orchestrator.\n * Detects available CLIs, validates providers, creates terminal panes, saves session.\n * When resume=true, attempts to restore previous session.\n */\nexport async function launch(options: ParsedArgs): Promise<LaunchResult> {\n const projectRoot = process.cwd()\n\n // Resume mode: try to restore previous session\n if (options.resume) {\n return resumeSession(options, projectRoot)\n }\n\n return freshLaunch(options, projectRoot)\n}\n\nasync function freshLaunch(options: ParsedArgs, projectRoot: string): Promise<LaunchResult> {\n const available = await detectAvailableClis()\n const { valid, missing } = validateProviders(options.providers, available)\n\n if (missing.length > 0) {\n process.stderr.write(\n `⚠️ 未检测到以下 AI CLI: ${missing.join(', ')}(已降级到可用模型)\\n`,\n )\n }\n\n if (valid.length === 0) {\n throw new RuntimeError(\n 'NO_CLI_AVAILABLE',\n '没有可用的 AI CLI 工具。请先安装 Claude Code: npm install -g @anthropic-ai/claude-code',\n )\n }\n\n const mode = valid.length >= 3 ? 3 : valid.length >= 2 ? 2 : 1\n\n // Detect and create terminal\n const backend = await detectTerminalBackend()\n let terminal: Terminal | null = null\n const paneIds: Record<string, string> = {}\n\n if (backend === 'wezterm') {\n terminal = new WeztermTerminal()\n\n const additionalProviders = valid.slice(1)\n for (let i = 0; i < additionalProviders.length; i++) {\n const provider = additionalProviders[i]\n try {\n const paneId = await terminal.createPane(provider, {\n direction: 'right',\n percent: Math.floor(100 / (additionalProviders.length - i + 1)),\n })\n paneIds[provider] = paneId\n } catch {\n process.stderr.write(`⚠️ 无法为 ${provider} 创建终端窗格\\n`)\n }\n }\n }\n\n process.stdout.write(`🚀 curdx 启动 — 模式: ${mode} 模型 (${valid.join(', ')})\\n`)\n\n if (terminal && Object.keys(paneIds).length > 0) {\n process.stdout.write(`📺 终端分屏: ${Object.entries(paneIds).map(([p, id]) => `${p}→pane:${id}`).join(', ')}\\n`)\n } else if (!terminal) {\n process.stderr.write('⚠️ 未检测到 WezTerm/tmux,运行在单窗格模式\\n')\n }\n\n // Save session to registry\n const now = Date.now()\n const registry: PaneRegistry = {\n ccbSessionId: `sess-${randomBytes(6).toString('hex')}`,\n workDir: projectRoot,\n terminal: backend ?? 'none',\n updatedAt: now,\n providers: {},\n }\n for (const [provider, paneId] of Object.entries(paneIds)) {\n registry.providers[provider] = {\n paneId,\n provider: provider as PaneRegistryEntry['provider'],\n sessionId: '',\n paneTitleMarker: `CCB-${provider}`,\n updatedAt: now,\n }\n }\n await saveSession(registry, projectRoot).catch(() => {\n // Non-fatal: session save failure doesn't block launch\n })\n\n return {\n providers: valid,\n missing,\n resume: false,\n launched: true,\n terminal,\n paneIds,\n }\n}\n\nasync function resumeSession(options: ParsedArgs, projectRoot: string): Promise<LaunchResult> {\n const saved = await loadSession(projectRoot)\n\n if (!saved) {\n process.stderr.write('⚠️ 无历史会话,将启动新会话\\n')\n return freshLaunch({ ...options, resume: false }, projectRoot)\n }\n\n const cleaned = cleanExpiredEntries(saved)\n const providerKeys = Object.keys(cleaned.providers)\n\n if (providerKeys.length === 0) {\n process.stderr.write('⚠️ 历史会话已过期,将启动新会话\\n')\n return freshLaunch({ ...options, resume: false }, projectRoot)\n }\n\n // Check if panes are still alive\n const backend = await detectTerminalBackend()\n let terminal: Terminal | null = null\n const paneIds: Record<string, string> = {}\n let aliveCount = 0\n\n if (backend === 'wezterm') {\n terminal = new WeztermTerminal()\n for (const [provider, entry] of Object.entries(cleaned.providers)) {\n const alive = await terminal.isAlive(entry.paneId)\n if (alive) {\n paneIds[provider] = entry.paneId\n aliveCount++\n }\n }\n }\n\n if (aliveCount === 0) {\n process.stderr.write('⚠️ 历史会话窗格已关闭,将启动新会话\\n')\n return freshLaunch({ ...options, resume: false }, projectRoot)\n }\n\n const allProviders = [...new Set(['claude', ...providerKeys])]\n const mode = allProviders.length >= 3 ? 3 : allProviders.length >= 2 ? 2 : 1\n process.stdout.write(`🔄 恢复会话 — 模式: ${mode} 模型 (${allProviders.join(', ')})\\n`)\n process.stdout.write(`📺 恢复窗格: ${Object.entries(paneIds).map(([p, id]) => `${p}→pane:${id}`).join(', ')}\\n`)\n\n return {\n providers: allProviders,\n missing: [],\n resume: true,\n launched: true,\n terminal,\n paneIds,\n }\n}\n","/**\n * Generate zsh completion script for curdx.\n */\nexport function generateZshCompletion(): string {\n return `#compdef curdx\n\n_curdx() {\n local -a commands providers options\n\n commands=(\n 'init:初始化 curdx 项目'\n 'completion:输出 zsh 补全脚本'\n )\n\n providers=(\n 'codex:启用 Codex CLI'\n 'gemini:启用 Gemini CLI'\n )\n\n options=(\n '-r[恢复上次终端会话]'\n '--resume[恢复上次终端会话]'\n '-V[显示版本号]'\n '--version[显示版本号]'\n '-h[显示帮助]'\n '--help[显示帮助]'\n )\n\n _arguments -C \\\\\n '1:command or provider:->first' \\\\\n '2:provider:->second' \\\\\n '*:options:->opts'\n\n case $state in\n first)\n _describe 'commands' commands\n _describe 'providers' providers\n _describe 'options' options\n ;;\n second)\n _describe 'providers' providers\n ;;\n opts)\n _describe 'options' options\n ;;\n esac\n}\n\ncompdef _curdx curdx\n`\n}\n\n/**\n * Print installation guide for zsh completion.\n */\nexport function printCompletionInstallGuide(): void {\n process.stdout.write(`\\n 💡 zsh 补全配置:\\n`)\n process.stdout.write(` 运行 \\`curdx completion > ~/.zsh/completions/_curdx\\`\\n`)\n process.stdout.write(` 然后在 .zshrc 中添加: fpath=(~/.zsh/completions $fpath)\\n`)\n}\n","import { existsSync } from 'node:fs'\nimport { join, basename } from 'node:path'\nimport { homedir } from 'node:os'\nimport { execa } from 'execa'\nimport { detectAvailableClis } from './detect.js'\nimport type { CliAvailability } from './detect.js'\nimport { detectTerminalBackend } from './terminal.js'\nimport type { TerminalBackend } from './terminal.js'\nimport { atomicWriteYaml } from '../shared/fs-atomic.js'\n\nexport interface EnvDetectionResult {\n clis: CliAvailability\n terminal: TerminalBackend | null\n claudeMem: boolean\n projectName: string\n}\n\n/**\n * Detect full environment: AI CLIs, terminal backend, claude-mem, project name.\n */\nexport async function detectEnvironment(projectRoot: string): Promise<EnvDetectionResult> {\n const [clis, terminal] = await Promise.all([\n detectAvailableClis(),\n detectTerminalBackend(),\n ])\n\n const claudeMemPath = join(homedir(), '.claude', 'plugins', 'claude-mem')\n const claudeMem = existsSync(claudeMemPath)\n const projectName = basename(projectRoot)\n\n return { clis, terminal, claudeMem, projectName }\n}\n\n/**\n * Generate .curdx/config.yaml from detection results.\n * Returns 'created' if new config was written, 'exists' if config already exists.\n */\nexport async function generateConfig(\n env: EnvDetectionResult,\n projectRoot: string,\n): Promise<'created' | 'exists'> {\n const configPath = join(projectRoot, '.curdx', 'config.yaml')\n\n if (existsSync(configPath)) {\n return 'exists'\n }\n\n const models: string[] = []\n if (env.clis.claude) models.push('claude')\n if (env.clis.codex) models.push('codex')\n if (env.clis.gemini) models.push('gemini')\n if (models.length === 0) models.push('claude') // default\n\n const mode = models.length >= 3 ? 3 : models.length >= 2 ? 2 : 1\n\n const config = {\n models,\n mode,\n verifyLevel: 5,\n puaEnabled: true,\n projectName: env.projectName,\n wezterm: env.terminal === 'wezterm',\n tmux: env.terminal === 'tmux',\n }\n\n await atomicWriteYaml(configPath, config)\n return 'created'\n}\n\n/**\n * Install claude-mem plugin if not already installed.\n * Returns 'already-installed', 'installed', or 'failed'.\n */\nexport async function installClaudeMem(\n installPath?: string,\n): Promise<'already-installed' | 'installed' | 'failed'> {\n const targetPath = installPath ?? join(homedir(), '.claude', 'plugins', 'claude-mem')\n\n if (existsSync(targetPath)) {\n return 'already-installed'\n }\n\n try {\n await execa('git', [\n 'clone',\n 'https://github.com/thedotmack/claude-mem.git',\n targetPath,\n ])\n return 'installed'\n } catch {\n return 'failed'\n }\n}\n\n/**\n * Run the complete init flow: detect → config → claude-mem → summary.\n */\nexport async function runInit(projectRoot: string): Promise<void> {\n process.stdout.write('\\n🔍 curdx init — 检测环境...\\n\\n')\n\n const env = await detectEnvironment(projectRoot)\n\n // Display detection results\n const check = (v: boolean) => (v ? '✅' : '❌')\n process.stdout.write(` AI CLI 检测:\\n`)\n process.stdout.write(` ${check(env.clis.claude)} Claude Code\\n`)\n process.stdout.write(` ${check(env.clis.codex)} Codex CLI\\n`)\n process.stdout.write(` ${check(env.clis.gemini)} Gemini CLI\\n`)\n process.stdout.write(` 终端后端:\\n`)\n process.stdout.write(` ${check(env.terminal === 'wezterm')} WezTerm\\n`)\n process.stdout.write(` ${check(env.terminal === 'tmux')} tmux\\n`)\n\n // Generate config\n const configResult = await generateConfig(env, projectRoot)\n if (configResult === 'created') {\n process.stdout.write(` 配置文件:\\n`)\n process.stdout.write(` ✅ 已生成 .curdx/config.yaml\\n`)\n } else {\n process.stdout.write(` 配置文件:\\n`)\n process.stdout.write(` ⏭️ .curdx/config.yaml 已存在(未覆盖)\\n`)\n }\n\n // Install claude-mem\n const memResult = await installClaudeMem()\n process.stdout.write(` claude-mem:\\n`)\n if (memResult === 'already-installed') {\n process.stdout.write(` ✅ 已安装\\n`)\n } else if (memResult === 'installed') {\n process.stdout.write(` ✅ 安装成功\\n`)\n } else {\n process.stderr.write(` ⚠️ 安装失败(不影响核心功能)\\n`)\n }\n\n // Completion install guide\n const { printCompletionInstallGuide } = await import('./completion.js')\n printCompletionInstallGuide()\n\n process.stdout.write(`\\n🚀 curdx 初始化完成!项目: ${env.projectName}\\n`)\n process.stdout.write(` 运行 \\`curdx\\` 开始使用\\n\\n`)\n}\n","import { Command } from 'commander'\nimport { readFileSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nfunction loadVersion(): string {\n // Walk up from current file to find package.json\n let dir = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 5; i++) {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'))\n if (pkg.name === '@curdx/cli') return pkg.version\n } catch { /* continue */ }\n dir = dirname(dir)\n }\n return '0.0.0'\n}\n\nconst version = loadVersion()\n\nexport const KNOWN_PROVIDERS = ['claude', 'codex', 'gemini'] as const\nexport type Provider = (typeof KNOWN_PROVIDERS)[number]\n\nexport interface ParsedArgs {\n providers: Provider[]\n resume: boolean\n}\n\n/**\n * Parse CLI arguments into structured options.\n * Exported for testability — does not call process.exit.\n */\nexport function parseArgs(argv: string[]): ParsedArgs {\n const program = new Command()\n\n program\n .name('curdx')\n .description('AI 代码压榨机 — 多模型对抗、五级验证、PUA 鞭策')\n .version(version)\n .argument('[providers...]', '额外的 AI 模型 (codex, gemini)')\n .option('-r, --resume', '恢复上次终端会话', false)\n .exitOverride()\n .configureOutput({\n writeOut: () => {},\n writeErr: () => {},\n })\n\n program.parse(argv)\n\n const opts = program.opts<{ resume: boolean }>()\n const rawProviders = program.args as string[]\n\n // Filter to known providers, always include claude, deduplicate\n const requestedProviders = rawProviders.filter((p): p is Provider =>\n KNOWN_PROVIDERS.includes(p as Provider),\n )\n\n const providers: Provider[] = ['claude']\n for (const p of requestedProviders) {\n if (!providers.includes(p)) {\n providers.push(p)\n }\n }\n\n return {\n providers,\n resume: opts.resume,\n }\n}\n\n/**\n * Create the main CLI program for direct execution.\n * Used by bin/curdx entry point.\n */\nexport function createCli(): Command {\n const program = new Command()\n\n program\n .name('curdx')\n .description('AI 代码压榨机 — 多模型对抗、五级验证、PUA 鞭策')\n .version(version)\n .argument('[providers...]', '额外的 AI 模型 (codex, gemini)')\n .option('-r, --resume', '恢复上次终端会话', false)\n .action(async (providers: string[], opts: { resume: boolean }) => {\n const { launch } = await import('./launcher.js')\n const parsed = parseArgs(['node', 'curdx', ...(opts.resume ? ['-r'] : []), ...providers])\n await launch(parsed)\n })\n\n program\n .command('init')\n .description('初始化 curdx 项目(检测环境、生成配置、安装插件)')\n .action(async () => {\n const { runInit } = await import('./init.js')\n await runInit(process.cwd())\n })\n\n program\n .command('completion')\n .description('输出 zsh 补全脚本')\n .action(async () => {\n const { generateZshCompletion } = await import('./completion.js')\n process.stdout.write(generateZshCompletion())\n })\n\n return program\n}\n"],"mappings":"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","names":["execa","join","randomBytes","existsSync","join","execa","printCompletionInstallGuide","readFileSync","join","dirname","launch","runInit","generateZshCompletion"]}
|
|
1
|
+
{"version":3,"sources":["../src/runtime/detect.ts","../src/runtime/terminal.ts","../src/runtime/wezterm.ts","../src/shared/fs-atomic.ts","../src/runtime/registry.ts","../src/shared/types.ts","../src/runtime/launcher.ts","../src/runtime/completion.ts","../src/runtime/init.ts","../src/runtime/cli.ts"],"sourcesContent":["import { execa } from 'execa'\nimport type { Provider } from './cli.js'\n\nexport interface CliAvailability {\n claude: boolean\n codex: boolean\n gemini: boolean\n}\n\nexport interface ValidationResult {\n valid: string[]\n missing: string[]\n}\n\n/**\n * Detect which AI CLI tools are installed on the system.\n * Uses `which` command for silent detection — never throws.\n */\nexport async function detectAvailableClis(): Promise<CliAvailability> {\n const check = async (cmd: string): Promise<boolean> => {\n try {\n const result = await execa('which', [cmd], { reject: false })\n return result.exitCode === 0\n } catch {\n return false\n }\n }\n\n const [claude, codex, gemini] = await Promise.all([\n check('claude'),\n check('codex'),\n check('gemini'),\n ])\n\n return { claude, codex, gemini }\n}\n\n/**\n * Validate requested providers against detected availability.\n * Returns which providers are valid and which are missing.\n */\nexport function validateProviders(\n requested: string[],\n available: CliAvailability,\n): ValidationResult {\n const valid: string[] = []\n const missing: string[] = []\n\n for (const provider of requested) {\n if (provider in available && available[provider as keyof CliAvailability]) {\n valid.push(provider)\n } else {\n missing.push(provider)\n }\n }\n\n return { valid, missing }\n}\n","import { execaCommand } from 'execa'\n\n/** Information about a terminal pane */\nexport interface PaneInfo {\n paneId: string\n title: string\n isActive: boolean\n}\n\n/** Options for creating a new pane */\nexport interface CreatePaneOptions {\n direction: 'right' | 'bottom'\n percent?: number\n cwd?: string\n title?: string\n cmdArgs?: string[]\n}\n\n/** Supported terminal backends */\nexport type TerminalBackend = 'wezterm' | 'tmux'\n\n/** Abstract terminal interface — all backends must implement this */\nexport interface Terminal {\n readonly backend: TerminalBackend\n\n /** Send text to a specific pane */\n sendText(paneId: string, text: string): Promise<void>\n\n /** Create a new split pane running a command */\n createPane(cmd: string, opts: CreatePaneOptions): Promise<string>\n\n /** Check if a pane is still alive */\n isAlive(paneId: string): Promise<boolean>\n\n /** Kill/close a pane */\n killPane(paneId: string): Promise<void>\n\n /** Activate/focus a pane */\n activatePane(paneId: string): Promise<void>\n\n /** List all panes in current window */\n listPanes(): Promise<PaneInfo[]>\n}\n\n/**\n * Detect which terminal backend is available.\n * Prefers WezTerm over tmux.\n */\nexport async function detectTerminalBackend(): Promise<TerminalBackend | null> {\n try {\n const result = await execaCommand('which wezterm', { reject: false })\n if (result.exitCode === 0) return 'wezterm'\n } catch { /* not available */ }\n\n try {\n const result = await execaCommand('which tmux', { reject: false })\n if (result.exitCode === 0) return 'tmux'\n } catch { /* not available */ }\n\n return null\n}\n","import { execa } from 'execa'\nimport type { Terminal, PaneInfo, CreatePaneOptions, TerminalBackend } from './terminal.js'\n\nconst MAX_ARGV_TEXT_LENGTH = 4000\n\n/** WezTerm terminal backend — operates via `wezterm cli` API */\nexport class WeztermTerminal implements Terminal {\n readonly backend: TerminalBackend = 'wezterm'\n\n async sendText(paneId: string, text: string): Promise<void> {\n if (text.length > MAX_ARGV_TEXT_LENGTH) {\n await execa('wezterm', ['cli', 'send-text', '--pane-id', paneId, '--no-paste'], {\n input: text,\n })\n } else {\n await execa('wezterm', [\n 'cli', 'send-text', '--pane-id', paneId, '--no-paste', '--', text,\n ])\n }\n }\n\n async createPane(cmd: string, opts: CreatePaneOptions): Promise<string> {\n // 校验 cmd 防止命令注入\n if (!cmd || /[;&|`$]/.test(cmd)) {\n throw new Error(`Invalid pane command: ${cmd}`)\n }\n\n const percent = opts.percent ?? 50\n const dirFlag = opts.direction === 'right' ? '--right' : '--bottom'\n\n const args = ['cli', 'split-pane', dirFlag, '--percent', String(percent)]\n\n if (opts.cwd) {\n args.push('--cwd', opts.cwd)\n }\n\n args.push('--', cmd, ...(opts.cmdArgs ?? []))\n\n const result = await execa('wezterm', args)\n const paneId = result.stdout.trim()\n if (!paneId) {\n throw new Error('wezterm split-pane returned empty pane ID')\n }\n return paneId\n }\n\n async isAlive(paneId: string): Promise<boolean> {\n try {\n const panes = await this.listPanes()\n return panes.some((p) => p.paneId === paneId)\n } catch {\n return false\n }\n }\n\n async killPane(paneId: string): Promise<void> {\n await execa('wezterm', ['cli', 'kill-pane', '--pane-id', paneId])\n }\n\n async activatePane(paneId: string): Promise<void> {\n await execa('wezterm', ['cli', 'activate-pane', '--pane-id', paneId])\n }\n\n async listPanes(): Promise<PaneInfo[]> {\n try {\n const result = await execa('wezterm', ['cli', 'list', '--format', 'json'])\n const raw = JSON.parse(result.stdout) as Array<{\n pane_id: number\n title: string\n is_active: boolean\n }>\n return raw.map((p) => ({\n paneId: String(p.pane_id),\n title: p.title,\n isActive: p.is_active,\n }))\n } catch {\n return []\n }\n }\n}\n","import { writeFileSync, renameSync, unlinkSync, mkdirSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { randomBytes } from 'node:crypto'\nimport { stringify as yamlStringify } from 'yaml'\n\nfunction ensureDir(filePath: string): void {\n mkdirSync(dirname(filePath), { recursive: true })\n}\n\nfunction tempPath(filePath: string): string {\n const rand = randomBytes(6).toString('hex')\n // tmp 文件放同目录,避免跨设备 EXDEV 错误\n return join(dirname(filePath), `.${rand}.tmp`)\n}\n\nfunction atomicWriteImpl(filePath: string, content: string): void {\n ensureDir(filePath)\n const tmp = tempPath(filePath)\n try {\n writeFileSync(tmp, content, 'utf-8')\n renameSync(tmp, filePath)\n } catch (err) {\n try { unlinkSync(tmp) } catch { /* 清理失败忽略 */ }\n throw err\n }\n}\n\n/** Atomically write text to file (synchronous) */\nexport function atomicWriteSync(filePath: string, content: string): void {\n atomicWriteImpl(filePath, content)\n}\n\n/** Atomically write JSON data to file */\nexport function atomicWriteJson(filePath: string, data: unknown): void {\n const content = JSON.stringify(data, null, 2)\n atomicWriteImpl(filePath, content)\n}\n\n/** Atomically write YAML data to file */\nexport function atomicWriteYaml(filePath: string, data: unknown): void {\n const content = yamlStringify(data)\n atomicWriteImpl(filePath, content)\n}\n\n/** Atomically write plain text to file */\nexport function atomicWriteText(filePath: string, content: string): void {\n atomicWriteImpl(filePath, content)\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { atomicWriteJson } from '../shared/fs-atomic.js'\nimport type { PaneRegistry, StateFileWrapper } from '../shared/types.js'\n\nexport const SESSION_TTL_DAYS = 7\nconst REGISTRY_FILENAME = 'pane-registry.json'\n\n/**\n * Save pane registry to .curdx/pane-registry.json wrapped in StateFileWrapper.\n */\nexport async function saveSession(data: PaneRegistry, projectRoot: string): Promise<void> {\n const filePath = join(projectRoot, '.curdx', REGISTRY_FILENAME)\n const wrapper: StateFileWrapper<PaneRegistry> = {\n version: 1,\n updatedAt: new Date().toISOString(),\n data,\n }\n await atomicWriteJson(filePath, wrapper)\n}\n\n/**\n * Load pane registry from .curdx/pane-registry.json.\n * Returns null if file doesn't exist.\n */\nexport async function loadSession(projectRoot: string): Promise<PaneRegistry | null> {\n const filePath = join(projectRoot, '.curdx', REGISTRY_FILENAME)\n\n if (!existsSync(filePath)) {\n return null\n }\n\n try {\n const raw = readFileSync(filePath, 'utf-8')\n const wrapper = JSON.parse(raw) as StateFileWrapper<PaneRegistry>\n return wrapper.data\n } catch {\n return null\n }\n}\n\n/**\n * Remove provider entries older than TTL days.\n */\nexport function cleanExpiredEntries(\n registry: PaneRegistry,\n ttlDays: number = SESSION_TTL_DAYS,\n): PaneRegistry {\n const cutoff = Date.now() - ttlDays * 24 * 60 * 60 * 1000\n const cleaned: PaneRegistry = {\n ...registry,\n providers: {},\n }\n\n for (const [key, entry] of Object.entries(registry.providers)) {\n if (entry.updatedAt >= cutoff) {\n cleaned.providers[key] = entry\n }\n }\n\n return cleaned\n}\n","/** Unified state file wrapper — all JSON state files use this format */\nexport interface StateFileWrapper<T> {\n version: number\n updatedAt: string // ISO 8601\n data: T\n}\n\n/** curdx project configuration (.curdx/config.yaml) */\nexport interface CurdxConfig {\n models: string[]\n mode: 0 | 1 | 2 | 3\n verifyLevel: number\n puaEnabled: true // always true, cannot be disabled\n projectName: string\n wezterm: boolean\n tmux: boolean\n}\n\n/** Loop execution state (.curdx/loop-state.json) */\nexport interface LoopState {\n taskIndex: number\n totalTasks: number\n retryCount: number\n phase: 'idle' | 'running' | 'waiting' | 'paused' | 'complete' | 'failed'\n maxRetries: number\n planName: string\n completedTaskIds: string[]\n failedTaskIds: string[]\n lastError: string | null\n}\n\n/** Single pane registry entry */\nexport interface PaneRegistryEntry {\n paneId: string\n provider: 'claude' | 'codex' | 'gemini'\n sessionId: string\n paneTitleMarker: string\n updatedAt: number // unix timestamp\n}\n\n/** Pane registry (.curdx/pane-registry.json) */\nexport interface PaneRegistry {\n ccbSessionId: string\n workDir: string\n terminal: 'wezterm' | 'tmux' | 'none'\n updatedAt: number\n providers: Record<string, PaneRegistryEntry>\n}\n\n/** Workflow execution state (.curdx/workflow-state.json) */\nexport interface WorkflowState {\n currentStage: 'start' | 'research' | 'spec' | 'plan' | 'dev' | 'review' | 'ship' | 'quick' | 'fix' | 'tdd' | 'idle'\n tasks: WorkflowTask[]\n waveIndex: number\n startedAt: string\n}\n\n/** Individual task within a workflow */\nexport interface WorkflowTask {\n id: string\n name: string\n status: 'pending' | 'in-progress' | 'complete' | 'failed'\n wave: number\n files: string[]\n verify: string\n done: string\n commitHash: string | null\n}\n\n/** Context layer type — three-tier context architecture */\nexport type ContextLayerType = 'persistent' | 'session' | 'ephemeral'\n\n/** A single context layer with estimated token usage */\nexport interface ContextLayer {\n type: ContextLayerType\n files: string[]\n estimatedTokens: number\n}\n\n/** Context utilization snapshot */\nexport interface ContextUtilization {\n totalTokens: number\n usedTokens: number\n ratio: number // 0.0 - 1.0\n layers: ContextLayer[]\n}\n\n/** Agent context bundle — clean context prepared for a sub-agent */\nexport interface AgentContextBundle {\n taskId: string\n projectContext: string // project-context.md content\n layers: ContextLayer[]\n totalTokens: number\n createdAt: string // ISO 8601\n}\n\n/** Base error class for all curdx errors */\nexport class CurdxError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly cause?: unknown,\n ) {\n super(message)\n this.name = 'CurdxError'\n }\n}\n\n/** Layer 1: Runtime errors */\nexport class RuntimeError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'RuntimeError'\n }\n}\n\n/** Layer 2: Flow engine errors */\nexport class FlowError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'FlowError'\n }\n}\n\n/** Layer 3: Context engine errors */\nexport class ContextError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'ContextError'\n }\n}\n\n/** Layer 4: Collaboration engine errors */\nexport class CollabError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'CollabError'\n }\n}\n\n/** Layer 5: Verification engine errors */\nexport class VerifyError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'VerifyError'\n }\n}\n\n/** Configuration errors */\nexport class ConfigError extends CurdxError {\n constructor(code: string, message: string, cause?: unknown) {\n super(code, message, cause)\n this.name = 'ConfigError'\n }\n}\n","import { randomBytes } from 'node:crypto'\nimport { execa } from 'execa'\nimport type { ParsedArgs, Provider } from './cli.js'\nimport { detectAvailableClis, validateProviders } from './detect.js'\nimport { detectTerminalBackend } from './terminal.js'\nimport type { Terminal } from './terminal.js'\nimport { WeztermTerminal } from './wezterm.js'\nimport { saveSession, loadSession, cleanExpiredEntries } from './registry.js'\nimport { RuntimeError } from '../shared/types.js'\nimport type { PaneRegistry, PaneRegistryEntry } from '../shared/types.js'\n\nexport interface LaunchResult {\n providers: string[]\n missing: string[]\n resume: boolean\n launched: boolean\n terminal: Terminal | null\n paneIds: Record<string, string>\n}\n\n/** Build the CLI command + args for a given provider */\nexport function buildProviderCommand(provider: string, allowAll: boolean): { cmd: string; args: string[] } {\n switch (provider) {\n case 'claude':\n return {\n cmd: 'claude',\n args: allowAll ? ['--dangerously-skip-permissions'] : [],\n }\n case 'codex':\n // Codex 不支持 --full-auto flag,需要通过 -c 注入运行时配置\n // 参考 CCB: trust_level + approval_policy + sandbox_mode\n return {\n cmd: 'codex',\n args: allowAll\n ? [\n '-c', 'disable_paste_burst=true',\n '-c', 'trust_level=\"trusted\"',\n '-c', 'approval_policy=\"never\"',\n '-c', 'sandbox_mode=\"danger-full-access\"',\n ]\n : [],\n }\n case 'gemini':\n return {\n cmd: 'gemini',\n args: allowAll ? ['--yolo'] : [],\n }\n default:\n return { cmd: provider, args: [] }\n }\n}\n\n/**\n * Launch the curdx orchestrator.\n * Detects available CLIs, validates providers, creates terminal panes, saves session.\n * When resume=true, attempts to restore previous session.\n */\nexport async function launch(options: ParsedArgs): Promise<LaunchResult> {\n const projectRoot = process.cwd()\n\n // Resume mode: try to restore previous session\n if (options.resume) {\n return resumeSession(options, projectRoot)\n }\n\n return freshLaunch(options, projectRoot)\n}\n\nasync function freshLaunch(options: ParsedArgs, projectRoot: string): Promise<LaunchResult> {\n const available = await detectAvailableClis()\n const { valid, missing } = validateProviders(options.providers, available)\n\n if (missing.length > 0) {\n process.stderr.write(\n `⚠️ 未检测到以下 AI CLI: ${missing.join(', ')}(已降级到可用模型)\\n`,\n )\n }\n\n if (valid.length === 0) {\n throw new RuntimeError(\n 'NO_CLI_AVAILABLE',\n '没有可用的 AI CLI 工具。请先安装 Claude Code: npm install -g @anthropic-ai/claude-code',\n )\n }\n\n const mode = valid.length >= 3 ? 3 : valid.length >= 2 ? 2 : 1\n\n // Detect and create terminal\n const backend = await detectTerminalBackend()\n let terminal: Terminal | null = null\n const paneIds: Record<string, string> = {}\n\n if (backend === 'wezterm') {\n terminal = new WeztermTerminal()\n\n const additionalProviders = valid.slice(1)\n for (let i = 0; i < additionalProviders.length; i++) {\n const provider = additionalProviders[i]\n try {\n const { args: providerArgs } = buildProviderCommand(provider, options.allowAll)\n const paneId = await terminal.createPane(provider, {\n direction: 'right',\n percent: Math.floor(100 / (additionalProviders.length - i + 1)),\n cmdArgs: providerArgs,\n })\n paneIds[provider] = paneId\n } catch {\n process.stderr.write(`⚠️ 无法为 ${provider} 创建终端窗格\\n`)\n }\n }\n }\n\n process.stdout.write(`🚀 curdx 启动 — 模式: ${mode} 模型 (${valid.join(', ')})\\n`)\n\n if (terminal && Object.keys(paneIds).length > 0) {\n process.stdout.write(`📺 终端分屏: ${Object.entries(paneIds).map(([p, id]) => `${p}→pane:${id}`).join(', ')}\\n`)\n } else if (!terminal) {\n process.stderr.write('⚠️ 未检测到 WezTerm/tmux,运行在单窗格模式\\n')\n }\n\n // Save session to registry\n const now = Date.now()\n const registry: PaneRegistry = {\n ccbSessionId: `sess-${randomBytes(6).toString('hex')}`,\n workDir: projectRoot,\n terminal: backend ?? 'none',\n updatedAt: now,\n providers: {},\n }\n for (const [provider, paneId] of Object.entries(paneIds)) {\n registry.providers[provider] = {\n paneId,\n provider: provider as PaneRegistryEntry['provider'],\n sessionId: '',\n paneTitleMarker: `CCB-${provider}`,\n updatedAt: now,\n }\n }\n await saveSession(registry, projectRoot).catch(() => {\n // Non-fatal: session save failure doesn't block launch\n })\n\n // Launch the primary provider (claude) in the current terminal\n const primary = buildProviderCommand(valid[0], options.allowAll)\n const child = execa(primary.cmd, primary.args, {\n stdio: 'inherit',\n cwd: projectRoot,\n reject: false,\n })\n\n // Wait for the primary process to exit\n await child\n\n return {\n providers: valid,\n missing,\n resume: false,\n launched: true,\n terminal,\n paneIds,\n }\n}\n\nasync function resumeSession(options: ParsedArgs, projectRoot: string): Promise<LaunchResult> {\n const saved = await loadSession(projectRoot)\n\n if (!saved) {\n process.stderr.write('⚠️ 无历史会话,将启动新会话\\n')\n return freshLaunch({ ...options, resume: false }, projectRoot)\n }\n\n const cleaned = cleanExpiredEntries(saved)\n const providerKeys = Object.keys(cleaned.providers)\n\n if (providerKeys.length === 0) {\n process.stderr.write('⚠️ 历史会话已过期,将启动新会话\\n')\n return freshLaunch({ ...options, resume: false }, projectRoot)\n }\n\n // Check if panes are still alive\n const backend = await detectTerminalBackend()\n let terminal: Terminal | null = null\n const paneIds: Record<string, string> = {}\n let aliveCount = 0\n\n if (backend === 'wezterm') {\n terminal = new WeztermTerminal()\n for (const [provider, entry] of Object.entries(cleaned.providers)) {\n const alive = await terminal.isAlive(entry.paneId)\n if (alive) {\n paneIds[provider] = entry.paneId\n aliveCount++\n }\n }\n }\n\n if (aliveCount === 0) {\n process.stderr.write('⚠️ 历史会话窗格已关闭,将启动新会话\\n')\n return freshLaunch({ ...options, resume: false }, projectRoot)\n }\n\n const allProviders = [...new Set(['claude', ...providerKeys])]\n const mode = allProviders.length >= 3 ? 3 : allProviders.length >= 2 ? 2 : 1\n process.stdout.write(`🔄 恢复会话 — 模式: ${mode} 模型 (${allProviders.join(', ')})\\n`)\n process.stdout.write(`📺 恢复窗格: ${Object.entries(paneIds).map(([p, id]) => `${p}→pane:${id}`).join(', ')}\\n`)\n\n return {\n providers: allProviders,\n missing: [],\n resume: true,\n launched: true,\n terminal,\n paneIds,\n }\n}\n","/**\n * Generate zsh completion script for curdx.\n */\nexport function generateZshCompletion(): string {\n return `#compdef curdx\n\n_curdx() {\n local -a commands providers options\n\n commands=(\n 'init:初始化 curdx 项目'\n 'completion:输出 zsh 补全脚本'\n )\n\n providers=(\n 'codex:启用 Codex CLI'\n 'gemini:启用 Gemini CLI'\n )\n\n options=(\n '-r[恢复上次终端会话]'\n '--resume[恢复上次终端会话]'\n '-V[显示版本号]'\n '--version[显示版本号]'\n '-h[显示帮助]'\n '--help[显示帮助]'\n )\n\n _arguments -C \\\\\n '1:command or provider:->first' \\\\\n '2:provider:->second' \\\\\n '*:options:->opts'\n\n case $state in\n first)\n _describe 'commands' commands\n _describe 'providers' providers\n _describe 'options' options\n ;;\n second)\n _describe 'providers' providers\n ;;\n opts)\n _describe 'options' options\n ;;\n esac\n}\n\ncompdef _curdx curdx\n`\n}\n\n/**\n * Print installation guide for zsh completion.\n */\nexport function printCompletionInstallGuide(): void {\n process.stdout.write(`\\n 💡 zsh 补全配置:\\n`)\n process.stdout.write(` 运行 \\`curdx completion > ~/.zsh/completions/_curdx\\`\\n`)\n process.stdout.write(` 然后在 .zshrc 中添加: fpath=(~/.zsh/completions $fpath)\\n`)\n}\n","import { existsSync } from 'node:fs'\nimport { join, basename } from 'node:path'\nimport { homedir } from 'node:os'\nimport { execa } from 'execa'\nimport { detectAvailableClis } from './detect.js'\nimport type { CliAvailability } from './detect.js'\nimport { detectTerminalBackend } from './terminal.js'\nimport type { TerminalBackend } from './terminal.js'\nimport { atomicWriteYaml } from '../shared/fs-atomic.js'\n\nexport interface EnvDetectionResult {\n clis: CliAvailability\n terminal: TerminalBackend | null\n claudeMem: boolean\n projectName: string\n}\n\n/**\n * Detect full environment: AI CLIs, terminal backend, claude-mem, project name.\n */\nexport async function detectEnvironment(projectRoot: string): Promise<EnvDetectionResult> {\n const [clis, terminal] = await Promise.all([\n detectAvailableClis(),\n detectTerminalBackend(),\n ])\n\n const claudeMemPath = join(homedir(), '.claude', 'plugins', 'claude-mem')\n const claudeMem = existsSync(claudeMemPath)\n const projectName = basename(projectRoot)\n\n return { clis, terminal, claudeMem, projectName }\n}\n\n/**\n * Generate .curdx/config.yaml from detection results.\n * Returns 'created' if new config was written, 'exists' if config already exists.\n */\nexport async function generateConfig(\n env: EnvDetectionResult,\n projectRoot: string,\n): Promise<'created' | 'exists'> {\n const configPath = join(projectRoot, '.curdx', 'config.yaml')\n\n if (existsSync(configPath)) {\n return 'exists'\n }\n\n const models: string[] = []\n if (env.clis.claude) models.push('claude')\n if (env.clis.codex) models.push('codex')\n if (env.clis.gemini) models.push('gemini')\n if (models.length === 0) models.push('claude') // default\n\n const mode = models.length >= 3 ? 3 : models.length >= 2 ? 2 : 1\n\n const config = {\n models,\n mode,\n verifyLevel: 5,\n puaEnabled: true,\n projectName: env.projectName,\n wezterm: env.terminal === 'wezterm',\n tmux: env.terminal === 'tmux',\n }\n\n await atomicWriteYaml(configPath, config)\n return 'created'\n}\n\n/**\n * Install claude-mem plugin if not already installed.\n * Returns 'already-installed', 'installed', or 'failed'.\n */\nexport async function installClaudeMem(\n installPath?: string,\n): Promise<'already-installed' | 'installed' | 'failed'> {\n const targetPath = installPath ?? join(homedir(), '.claude', 'plugins', 'claude-mem')\n\n if (existsSync(targetPath)) {\n return 'already-installed'\n }\n\n try {\n await execa('git', [\n 'clone',\n 'https://github.com/thedotmack/claude-mem.git',\n targetPath,\n ])\n return 'installed'\n } catch {\n return 'failed'\n }\n}\n\n/**\n * Run the complete init flow: detect → config → claude-mem → summary.\n */\nexport async function runInit(projectRoot: string): Promise<void> {\n process.stdout.write('\\n🔍 curdx init — 检测环境...\\n\\n')\n\n const env = await detectEnvironment(projectRoot)\n\n // Display detection results\n const check = (v: boolean) => (v ? '✅' : '❌')\n process.stdout.write(` AI CLI 检测:\\n`)\n process.stdout.write(` ${check(env.clis.claude)} Claude Code\\n`)\n process.stdout.write(` ${check(env.clis.codex)} Codex CLI\\n`)\n process.stdout.write(` ${check(env.clis.gemini)} Gemini CLI\\n`)\n process.stdout.write(` 终端后端:\\n`)\n process.stdout.write(` ${check(env.terminal === 'wezterm')} WezTerm\\n`)\n process.stdout.write(` ${check(env.terminal === 'tmux')} tmux\\n`)\n\n // Generate config\n const configResult = await generateConfig(env, projectRoot)\n if (configResult === 'created') {\n process.stdout.write(` 配置文件:\\n`)\n process.stdout.write(` ✅ 已生成 .curdx/config.yaml\\n`)\n } else {\n process.stdout.write(` 配置文件:\\n`)\n process.stdout.write(` ⏭️ .curdx/config.yaml 已存在(未覆盖)\\n`)\n }\n\n // Install claude-mem\n const memResult = await installClaudeMem()\n process.stdout.write(` claude-mem:\\n`)\n if (memResult === 'already-installed') {\n process.stdout.write(` ✅ 已安装\\n`)\n } else if (memResult === 'installed') {\n process.stdout.write(` ✅ 安装成功\\n`)\n } else {\n process.stderr.write(` ⚠️ 安装失败(不影响核心功能)\\n`)\n }\n\n // Completion install guide\n const { printCompletionInstallGuide } = await import('./completion.js')\n printCompletionInstallGuide()\n\n process.stdout.write(`\\n🚀 curdx 初始化完成!项目: ${env.projectName}\\n`)\n process.stdout.write(` 运行 \\`curdx\\` 开始使用\\n\\n`)\n}\n","import { Command } from 'commander'\nimport { readFileSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nfunction loadVersion(): string {\n // Walk up from current file to find package.json\n let dir = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 5; i++) {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'))\n if (pkg.name === '@curdx/cli') return pkg.version\n } catch { /* continue */ }\n dir = dirname(dir)\n }\n return '0.0.0'\n}\n\nconst version = loadVersion()\n\nexport const KNOWN_PROVIDERS = ['claude', 'codex', 'gemini'] as const\nexport type Provider = (typeof KNOWN_PROVIDERS)[number]\n\nexport interface ParsedArgs {\n providers: Provider[]\n resume: boolean\n allowAll: boolean\n}\n\n/**\n * Parse CLI arguments into structured options.\n * Exported for testability — does not call process.exit.\n */\nexport function parseArgs(argv: string[]): ParsedArgs {\n const program = new Command()\n\n program\n .name('curdx')\n .description('AI 代码压榨机 — 多模型对抗、五级验证、PUA 鞭策')\n .version(version)\n .argument('[providers...]', '额外的 AI 模型 (codex, gemini)')\n .option('-r, --resume', '恢复上次终端会话', false)\n .option('-a, --allow-all', '跳过所有权限确认(claude: --dangerously-skip-permissions, codex: --full-auto)', false)\n .exitOverride()\n .configureOutput({\n writeOut: () => {},\n writeErr: () => {},\n })\n\n program.parse(argv)\n\n const opts = program.opts<{ resume: boolean; allowAll: boolean }>()\n const rawProviders = program.args as string[]\n\n // Filter to known providers, always include claude, deduplicate\n const requestedProviders = rawProviders.filter((p): p is Provider =>\n KNOWN_PROVIDERS.includes(p as Provider),\n )\n\n const providers: Provider[] = ['claude']\n for (const p of requestedProviders) {\n if (!providers.includes(p)) {\n providers.push(p)\n }\n }\n\n return {\n providers,\n resume: opts.resume,\n allowAll: opts.allowAll,\n }\n}\n\n/**\n * Create the main CLI program for direct execution.\n * Used by bin/curdx entry point.\n */\nexport function createCli(): Command {\n const program = new Command()\n\n program\n .name('curdx')\n .description('AI 代码压榨机 — 多模型对抗、五级验证、PUA 鞭策')\n .version(version)\n .argument('[providers...]', '额外的 AI 模型 (codex, gemini)')\n .option('-r, --resume', '恢复上次终端会话', false)\n .option('-a, --allow-all', '跳过所有权限确认', false)\n .action(async (providers: string[], opts: { resume: boolean; allowAll: boolean }) => {\n const { launch } = await import('./launcher.js')\n const parsed = parseArgs(['node', 'curdx', ...(opts.resume ? ['-r'] : []), ...(opts.allowAll ? ['-a'] : []), ...providers])\n await launch(parsed)\n })\n\n program\n .command('init')\n .description('初始化 curdx 项目(检测环境、生成配置、安装插件)')\n .action(async () => {\n const { runInit } = await import('./init.js')\n await runInit(process.cwd())\n })\n\n program\n .command('completion')\n .description('输出 zsh 补全脚本')\n .action(async () => {\n const { generateZshCompletion } = await import('./completion.js')\n process.stdout.write(generateZshCompletion())\n })\n\n return program\n}\n"],"mappings":"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","names":["execa","join","randomBytes","execa","existsSync","join","execa","printCompletionInstallGuide","readFileSync","join","dirname","launch","runInit","generateZshCompletion"]}
|