aiwcli 0.15.7 → 0.17.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/README.md +106 -1125
- package/bin/run.js +0 -4
- package/dist/capabilities/installation/control-plane/clear-command.d.ts +2 -0
- package/dist/capabilities/installation/control-plane/clear-command.js +32 -3
- package/dist/capabilities/installation/control-plane/init-command.js +2 -2
- package/dist/capabilities/launch/contracts.d.ts +39 -4
- package/dist/capabilities/launch/control-plane/execute-launch.js +158 -119
- package/dist/capabilities/launch/runtime-core/launch-decisions.d.ts +82 -0
- package/dist/capabilities/launch/runtime-core/launch-decisions.js +202 -0
- package/dist/commands/branch.d.ts +1 -1
- package/dist/commands/branch.js +1 -1
- package/dist/commands/launch.d.ts +0 -5
- package/dist/commands/launch.js +2 -37
- package/dist/lib/config.js +1 -2
- package/dist/lib/context/context-store.js +28 -2
- package/dist/lib/core-installer.d.ts +1 -1
- package/dist/lib/core-installer.js +6 -27
- package/dist/lib/debug.d.ts +0 -10
- package/dist/lib/debug.js +0 -10
- package/dist/lib/env-sanitizer.d.ts +25 -0
- package/dist/lib/env-sanitizer.js +46 -0
- package/dist/lib/errors.d.ts +0 -13
- package/dist/lib/errors.js +0 -15
- package/dist/lib/git-exclude-manager.js +1 -1
- package/dist/lib/hooks/context-monitor-logic.d.ts +6 -0
- package/dist/lib/hooks/context-monitor-logic.js +25 -0
- package/dist/lib/hooks/hook-utils.js +11 -0
- package/dist/lib/hooks/prompt-binding-logic.d.ts +7 -0
- package/dist/lib/hooks/prompt-binding-logic.js +50 -0
- package/dist/lib/hooks/session-end-logic.js +2 -14
- package/dist/lib/install-state.js +6 -13
- package/dist/lib/json-io.d.ts +12 -0
- package/dist/lib/json-io.js +30 -0
- package/dist/lib/multiplexer.d.ts +43 -35
- package/dist/lib/multiplexer.js +21 -2
- package/dist/lib/multiplexers/psmux.d.ts +14 -34
- package/dist/lib/multiplexers/psmux.js +70 -130
- package/dist/lib/multiplexers/tmux.d.ts +11 -19
- package/dist/lib/multiplexers/tmux.js +79 -120
- package/dist/lib/multiplexers/wezterm.d.ts +38 -0
- package/dist/lib/multiplexers/wezterm.js +225 -0
- package/dist/lib/mux-utils.d.ts +4 -3
- package/dist/lib/mux-utils.js +7 -13
- package/dist/lib/prompt-file-manager.d.ts +23 -0
- package/dist/lib/prompt-file-manager.js +41 -0
- package/dist/lib/runtime/agent-launcher.d.ts +67 -0
- package/dist/lib/runtime/agent-launcher.js +262 -0
- package/dist/lib/runtime/aiw-cli.d.ts +2 -0
- package/dist/lib/runtime/aiw-cli.js +3 -1
- package/dist/lib/runtime/cli-args.d.ts +5 -2
- package/dist/lib/runtime/cli-args.js +18 -3
- package/dist/lib/runtime/inference.js +3 -14
- package/dist/lib/runtime/models.d.ts +6 -0
- package/dist/lib/runtime/models.js +6 -0
- package/dist/lib/runtime/state-io.d.ts +2 -1
- package/dist/lib/runtime/state-io.js +9 -4
- package/dist/lib/runtime/utils.d.ts +8 -0
- package/dist/lib/runtime/utils.js +31 -1
- package/dist/lib/schemas.d.ts +250 -0
- package/dist/lib/schemas.js +216 -0
- package/dist/lib/sentinel-manager.d.ts +32 -0
- package/dist/lib/sentinel-manager.js +62 -0
- package/dist/lib/sentinel-wrapper.d.ts +1 -0
- package/dist/lib/sentinel-wrapper.js +12 -3
- package/dist/lib/settings-hierarchy.js +3 -20
- package/dist/lib/shell-adapters/bash-adapter.d.ts +18 -0
- package/dist/lib/shell-adapters/bash-adapter.js +69 -0
- package/dist/lib/shell-adapters/index.d.ts +5 -0
- package/dist/lib/shell-adapters/index.js +7 -0
- package/dist/lib/shell-adapters/powershell-adapter.d.ts +18 -0
- package/dist/lib/shell-adapters/powershell-adapter.js +62 -0
- package/dist/lib/shell-adapters/shell-adapter.d.ts +45 -0
- package/dist/lib/shell-adapters/shell-adapter.js +5 -0
- package/dist/lib/spawn-errors.d.ts +3 -0
- package/dist/lib/spawn-errors.js +15 -1
- package/dist/lib/spinner.d.ts +0 -5
- package/dist/lib/spinner.js +0 -16
- package/dist/lib/template-installer.d.ts +10 -0
- package/dist/lib/template-installer.js +4 -4
- package/dist/lib/terminal-strategy.d.ts +1 -0
- package/dist/lib/terminal-strategy.js +12 -6
- package/dist/lib/terminal.d.ts +7 -5
- package/dist/lib/terminal.js +42 -19
- package/dist/lib/tmux-primitives.d.ts +0 -2
- package/dist/lib/tmux-primitives.js +0 -4
- package/dist/lib/tmux-session.js +2 -1
- package/dist/lib/windsurf-hooks-hierarchy.js +6 -23
- package/dist/platform/launch.d.ts +2 -1
- package/dist/platform/launch.js +1 -0
- package/dist/templates/CLAUDE.md +0 -1
- package/dist/templates/cc-native/.claude/settings.json +0 -10
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +11 -4
- package/dist/templates/cc-native/_cc-native/cc-native.config.json +3 -7
- package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +26 -47
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +7 -9
- package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +2 -3
- package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +2 -2
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +0 -25
- package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +4 -4
- package/dist/templates/cc-native/_cc-native/lib-ts/.mocharc.json +9 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/aggregate-agents.test.ts +118 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/artifacts.test.ts +234 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/cc-native-state.test.ts +170 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/cli-output-parser.test.ts +73 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/config.test.ts +64 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/constants.test.ts +40 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/debug.test.ts +42 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/exports.test.ts +58 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/helpers.ts +107 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/add-plan-context.hook.test.ts +97 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/plan-questions.hook.test.ts +81 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/plan-review.hook.test.ts +71 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/json-parser.test.ts +99 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/orchestrator-agent.test.ts +288 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/orchestrator.test.ts +48 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/reviewers.test.ts +32 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/state.test.ts +124 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/verdict.test.ts +93 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/agent-selection.ts +163 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +6 -14
- package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/format.ts +597 -599
- package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/index.ts +26 -26
- package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/tracker.ts +106 -107
- package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/write.ts +118 -119
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +21 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +16 -15
- package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +132 -10
- package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +6 -6
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/corroboration.ts +119 -119
- package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +1 -2
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/graduation.ts +132 -132
- package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +88 -86
- package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +5 -6
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/orchestrator.ts +70 -70
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/output-builder.ts +130 -121
- package/dist/templates/cc-native/_cc-native/lib-ts/package-lock.json +1679 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/package.json +24 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +4 -4
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +1 -6
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/plan-questions.ts +101 -101
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/review-pipeline.ts +511 -543
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/__tests__/agent-providers.test.ts +262 -0
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/agent.ts +71 -85
- package/dist/templates/{core/lib-ts/agent-exec → cc-native/_cc-native/lib-ts/reviewers/base}/base-agent.ts +138 -152
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/index.ts +12 -12
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/claude-agent.ts +66 -57
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/codex-agent.ts +185 -200
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/gemini-agent.ts +39 -40
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/orchestrator-claude-agent.ts +196 -224
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/schemas.ts +201 -201
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/types.ts +21 -23
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/__tests__/hyde.test.ts +365 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/__tests__/ollama-client.test.ts +223 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +12 -16
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +3 -2
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +31 -31
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +6 -7
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +7 -9
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +14 -17
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +37 -41
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +33 -43
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +20 -20
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +8 -9
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +3 -4
- package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +50 -126
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +19 -21
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +13 -88
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/verdict.ts +72 -72
- package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +35 -0
- package/dist/templates/cc-native/_cc-native/plan-review/lib/agent-selection.ts +1 -1
- package/dist/templates/cc-native/_cc-native/scripts/council_debate.ts +242 -0
- package/dist/templates/cc-native/_cc-native/scripts/council_debate_simple.ts +294 -0
- package/dist/templates/cc-native/_cc-native/{plan-review/workflows → workflows}/specdev.md +9 -9
- package/dist/templates/core/.claude/skills/codex/SKILL.md +25 -0
- package/dist/templates/core/.claude/skills/devin/SKILL.md +25 -0
- package/dist/templates/core/.claude/skills/handoff/SKILL.md +11 -0
- package/dist/templates/core/.claude/skills/handoff-resume/SKILL.md +11 -0
- package/dist/templates/core/.claude/skills/meta-plan/SKILL.md +13 -0
- package/dist/templates/core/.codex/skills/codex/SKILL.md +13 -0
- package/dist/templates/core/.codex/skills/devin/SKILL.md +19 -0
- package/dist/templates/core/.codex/skills/handoff/SKILL.md +11 -0
- package/dist/templates/core/.codex/skills/handoff-resume/SKILL.md +11 -0
- package/dist/templates/core/.codex/{workflows/meta-plan.md → skills/meta-plan/SKILL.md} +6 -0
- package/dist/templates/core/{.cognition → .devin}/AGENTS.md +2 -2
- package/dist/templates/core/.devin/skills/codex/SKILL.md +19 -0
- package/dist/templates/core/.devin/skills/devin/SKILL.md +13 -0
- package/dist/templates/core/.devin/skills/handoff/SKILL.md +11 -0
- package/dist/templates/core/.devin/skills/handoff-resume/SKILL.md +11 -0
- package/dist/templates/core/.devin/skills/meta-plan/SKILL.md +13 -0
- package/dist/templates/core/.windsurf/workflows/handoff-resume.md +9 -0
- package/dist/templates/core/hooks-ts/archive_plan.ts +1 -21
- package/dist/templates/core/hooks-ts/file-suggestion.ts +1 -19
- package/dist/templates/core/hooks-ts/pre_compact.ts +5 -18
- package/dist/templates/core/lib-ts/context/context-store.ts +29 -2
- package/dist/templates/core/lib-ts/hooks/hook-utils.ts +11 -0
- package/dist/templates/core/lib-ts/hooks/session-end-logic.ts +2 -13
- package/dist/templates/core/lib-ts/runtime/agent-launcher.ts +74 -0
- package/dist/templates/core/lib-ts/runtime/aiw-cli.ts +4 -2
- package/dist/templates/core/lib-ts/runtime/cli-args.ts +18 -4
- package/dist/templates/core/lib-ts/runtime/inference.ts +3 -15
- package/dist/templates/core/lib-ts/runtime/models.ts +7 -0
- package/dist/templates/core/lib-ts/runtime/state-io.ts +9 -4
- package/dist/templates/core/lib-ts/runtime/utils.ts +30 -1
- package/dist/templates/core/lib-ts/schemas.ts +233 -0
- package/dist/templates/core/scripts/resolve-run.ts +34 -2
- package/dist/templates/core/scripts/status_line.ts +1 -1
- package/dist/templates/core/skills/codex/CLAUDE.md +9 -4
- package/dist/templates/core/skills/codex/SKILL.md +6 -0
- package/dist/templates/core/skills/codex/lib/codex-watcher.ts +3 -10
- package/dist/templates/core/skills/codex/scripts/launch-codex.ts +26 -26
- package/dist/templates/core/skills/devin/CLAUDE.md +63 -6
- package/dist/templates/core/skills/devin/lib/devin-watcher.ts +116 -96
- package/dist/templates/core/skills/devin/scripts/launch-devin.ts +22 -21
- package/dist/templates/core/skills/handoff-system/CLAUDE.md +1 -1
- package/oclif.manifest.json +4 -4
- package/package.json +4 -4
- package/dist/lib/base-command.d.ts +0 -1
- package/dist/lib/base-command.js +0 -1
- package/dist/lib/env-compat.d.ts +0 -18
- package/dist/lib/env-compat.js +0 -23
- package/dist/lib/launch-options.d.ts +0 -1
- package/dist/lib/launch-options.js +0 -1
- package/dist/lib/stdin.d.ts +0 -48
- package/dist/lib/stdin.js +0 -60
- package/dist/templates/cc-native/_cc-native/CLAUDE.md +0 -73
- package/dist/templates/cc-native/_cc-native/artifacts/CLAUDE.md +0 -64
- package/dist/templates/cc-native/_cc-native/lib-ts/CLAUDE.md +0 -70
- package/dist/templates/cc-native/_cc-native/plan-review/CODING-STANDARDS-CHECKLIST.md +0 -75
- package/dist/templates/cc-native/_cc-native/plan-review/agents/CLAUDE.md +0 -143
- package/dist/templates/cc-native/_cc-native/plan-review/agents/PLAN-ORCHESTRATOR.md +0 -213
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-questions/PLAN-QUESTIONER.md +0 -70
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-EVOLUTION.md +0 -62
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-PATTERNS.md +0 -61
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-STRUCTURE.md +0 -62
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ASSUMPTION-TRACER.md +0 -56
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CLARITY-AUDITOR.md +0 -53
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-FEASIBILITY.md +0 -66
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-GAPS.md +0 -70
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-ORDERING.md +0 -62
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CONSTRAINT-VALIDATOR.md +0 -72
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-ADR-VALIDATOR.md +0 -61
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-SCALE-MATCHER.md +0 -64
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DEVILS-ADVOCATE.md +0 -56
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DOCUMENTATION-PHILOSOPHY.md +0 -86
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HANDOFF-READINESS.md +0 -59
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HIDDEN-COMPLEXITY.md +0 -58
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/INCREMENTAL-DELIVERY.md +0 -66
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-DEPENDENCY.md +0 -62
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-FMEA.md +0 -66
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-PREMORTEM.md +0 -71
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-REVERSIBILITY.md +0 -74
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SCOPE-BOUNDARY.md +0 -77
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SIMPLICITY-GUARDIAN.md +0 -62
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SKEPTIC.md +0 -68
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-BEHAVIOR-AUDITOR.md +0 -61
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-CHARACTERIZATION.md +0 -71
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-FIRST-VALIDATOR.md +0 -61
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-PYRAMID-ANALYZER.md +0 -61
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-COSTS.md +0 -67
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-STAKEHOLDERS.md +0 -65
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-COVERAGE.md +0 -74
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-STRENGTH.md +0 -69
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/base/base-agent.ts +0 -7
- package/dist/templates/core/.codex/workflows/codex.md +0 -17
- package/dist/templates/core/.codex/workflows/handoff.md +0 -5
- package/dist/templates/core/lib-ts/agent-exec/backends/headless.ts +0 -34
- package/dist/templates/core/lib-ts/agent-exec/backends/index.ts +0 -6
- package/dist/templates/core/lib-ts/agent-exec/backends/tmux.ts +0 -148
- package/dist/templates/core/lib-ts/agent-exec/execution-backend.ts +0 -50
- package/dist/templates/core/lib-ts/agent-exec/index.ts +0 -6
- package/dist/templates/core/lib-ts/agent-exec/structured-output.ts +0 -165
- /package/dist/templates/core/{.cognition → .devin}/config.json +0 -0
|
@@ -1,42 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TmuxMultiplexer — unified tmux backend.
|
|
3
|
-
*
|
|
3
|
+
* Composes with BashAdapter for command building.
|
|
4
|
+
* Owns: split direction resolution, tmux session config, Windows bootstrap.
|
|
4
5
|
*/
|
|
5
6
|
import { execSync } from 'node:child_process';
|
|
6
7
|
import * as fs from 'node:fs';
|
|
7
|
-
import {
|
|
8
|
+
import { sanitizedProcessEnv } from '../env-sanitizer.js';
|
|
9
|
+
import { PANE_HOLD_MESSAGE, getLastLine, spawnAttached, splitFlagFromDimensions } from '../mux-utils.js';
|
|
8
10
|
import { isNonWindowsPlatform, isWindowsPlatform } from '../runtime/platform-adapter.js';
|
|
9
|
-
import { cleanupSentinelIpc, createSentinelIpcPaths } from '../runtime/sentinel-ipc.js';
|
|
10
11
|
import { execFileAsync, findExecutable } from '../runtime/subprocess-utils.js';
|
|
11
|
-
import {
|
|
12
|
+
import { BashAdapter } from '../shell-adapters/bash-adapter.js';
|
|
12
13
|
import { findBestSplit, listPanes } from '../tmux-pane-placement.js';
|
|
13
|
-
import {
|
|
14
|
-
import { buildShellCommand, buildTmuxRuntimeBootstrapCommands } from '../tmux-session.js';
|
|
15
|
-
/** @internal */
|
|
16
|
-
export function
|
|
17
|
-
return
|
|
18
|
-
.map(([key, value]) => `${key}=${quoteForSh(value)}`)
|
|
19
|
-
.join(' ');
|
|
20
|
-
}
|
|
21
|
-
/** @internal */
|
|
22
|
-
export function buildShToolCommand(params) {
|
|
23
|
-
const { toolPath, args, env, mode, promptPath, promptText } = params;
|
|
24
|
-
const envPrefix = buildEnvPrefix(env);
|
|
25
|
-
const commandArgs = buildCommandArgs(args, mode, promptText);
|
|
26
|
-
const argPart = commandArgs.map((arg) => quoteForSh(arg)).join(' ');
|
|
27
|
-
const base = [envPrefix, quoteForSh(toolPath), argPart]
|
|
28
|
-
.filter(Boolean)
|
|
29
|
-
.join(' ');
|
|
30
|
-
if (mode === 'exec' && promptPath) {
|
|
31
|
-
return `${base} < ${quoteForSh(promptPath)}`;
|
|
32
|
-
}
|
|
33
|
-
return base;
|
|
34
|
-
}
|
|
35
|
-
/** @internal */
|
|
36
|
-
export function buildCommandArgs(args, mode, promptText) {
|
|
37
|
-
if (mode !== 'repl' || promptText === undefined)
|
|
38
|
-
return args;
|
|
39
|
-
return [...args, promptText];
|
|
14
|
+
import { toMsysPosixPath } from '../tmux-primitives.js';
|
|
15
|
+
import { buildShellCommand, buildTmuxRuntimeBootstrapCommands, configureTmuxSession } from '../tmux-session.js';
|
|
16
|
+
/** @internal — translate unified SplitDirection to tmux flag. */
|
|
17
|
+
export function toTmuxSplitFlag(direction) {
|
|
18
|
+
return direction === 'horizontal' ? '-h' : '-v';
|
|
40
19
|
}
|
|
41
20
|
/** @internal */
|
|
42
21
|
export function withWindowsTmuxBootstrap(command, platform = process.platform) {
|
|
@@ -45,15 +24,25 @@ export function withWindowsTmuxBootstrap(command, platform = process.platform) {
|
|
|
45
24
|
const bootstrap = buildTmuxRuntimeBootstrapCommands(platform).join('; ');
|
|
46
25
|
return `${bootstrap}; ${command}`;
|
|
47
26
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
27
|
+
/** @internal */
|
|
28
|
+
export function buildTmuxSplitWindowArgs(params) {
|
|
29
|
+
const args = ['split-window', params.splitFlag, '-P', '-F', '#{pane_id}'];
|
|
30
|
+
if (params.cwd) {
|
|
31
|
+
args.push('-c', params.cwd);
|
|
32
|
+
}
|
|
33
|
+
if (params.splitTarget) {
|
|
34
|
+
args.push('-t', params.splitTarget);
|
|
35
|
+
}
|
|
36
|
+
args.push(params.command);
|
|
37
|
+
return args;
|
|
38
|
+
}
|
|
39
|
+
/** @internal */
|
|
40
|
+
export function buildTmuxCreateSessionArgs(params) {
|
|
41
|
+
const args = ['new-session'];
|
|
42
|
+
if (params.reattach)
|
|
43
|
+
args.push('-A');
|
|
44
|
+
args.push('-c', params.cwd, '-s', params.sessionName, params.shellCommand);
|
|
45
|
+
return args;
|
|
57
46
|
}
|
|
58
47
|
async function resolveAutoSplit(tmuxPath, splitTarget) {
|
|
59
48
|
const explicitTarget = splitTarget?.trim();
|
|
@@ -83,31 +72,13 @@ async function resolveAutoSplit(tmuxPath, splitTarget) {
|
|
|
83
72
|
splitTarget: placement.targetPane,
|
|
84
73
|
};
|
|
85
74
|
}
|
|
86
|
-
/** @internal */
|
|
87
|
-
export function buildTmuxSplitWindowArgs(params) {
|
|
88
|
-
const args = ['split-window', params.splitFlag, '-P', '-F', '#{pane_id}'];
|
|
89
|
-
if (params.cwd) {
|
|
90
|
-
args.push('-c', params.cwd);
|
|
91
|
-
}
|
|
92
|
-
if (params.splitTarget) {
|
|
93
|
-
args.push('-t', params.splitTarget);
|
|
94
|
-
}
|
|
95
|
-
args.push(params.command);
|
|
96
|
-
return args;
|
|
97
|
-
}
|
|
98
|
-
/** @internal */
|
|
99
|
-
export function buildTmuxCreateSessionArgs(params) {
|
|
100
|
-
const args = ['new-session'];
|
|
101
|
-
if (params.reattach)
|
|
102
|
-
args.push('-A');
|
|
103
|
-
args.push('-c', params.cwd, '-s', params.sessionName, params.shellCommand);
|
|
104
|
-
return args;
|
|
105
|
-
}
|
|
106
75
|
export class TmuxMultiplexer {
|
|
107
76
|
backend = 'tmux';
|
|
108
77
|
tmuxPath;
|
|
78
|
+
shell;
|
|
109
79
|
constructor(tmuxPath) {
|
|
110
80
|
this.tmuxPath = tmuxPath;
|
|
81
|
+
this.shell = new BashAdapter();
|
|
111
82
|
}
|
|
112
83
|
static create() {
|
|
113
84
|
const tmuxPath = findExecutable('tmux');
|
|
@@ -115,12 +86,21 @@ export class TmuxMultiplexer {
|
|
|
115
86
|
return null;
|
|
116
87
|
return new TmuxMultiplexer(tmuxPath);
|
|
117
88
|
}
|
|
89
|
+
resolveStrategy(ctx) {
|
|
90
|
+
if (ctx.disableMux) {
|
|
91
|
+
return { strategy: 'inline', reason: 'Multiplexer disabled via --no-tmux' };
|
|
92
|
+
}
|
|
93
|
+
if (Boolean(process.env.TMUX)) {
|
|
94
|
+
return { strategy: 'split', reason: 'Inside tmux session' };
|
|
95
|
+
}
|
|
96
|
+
return { strategy: 'create-session', reason: 'Outside tmux — will create new session' };
|
|
97
|
+
}
|
|
118
98
|
async createSession(options) {
|
|
119
|
-
const { sessionName, reattach } = options;
|
|
99
|
+
const { sessionName, reattach, cwd } = options;
|
|
120
100
|
if (!isNonWindowsPlatform()) {
|
|
121
|
-
return { exitCode: -1,
|
|
101
|
+
return { launched: false, exitCode: -1, backend: this.backend, reason: 'tmux not available on this platform' };
|
|
122
102
|
}
|
|
123
|
-
// Set default-terminal BEFORE session creation
|
|
103
|
+
// Set default-terminal BEFORE session creation
|
|
124
104
|
try {
|
|
125
105
|
execSync(String.raw `tmux start-server \; set -g default-terminal "tmux-256color"`, { stdio: 'ignore', timeout: 3000 });
|
|
126
106
|
}
|
|
@@ -139,119 +119,98 @@ export class TmuxMultiplexer {
|
|
|
139
119
|
});
|
|
140
120
|
const args = buildTmuxCreateSessionArgs({
|
|
141
121
|
sessionName,
|
|
142
|
-
cwd
|
|
122
|
+
cwd,
|
|
143
123
|
shellCommand,
|
|
144
124
|
reattach,
|
|
145
125
|
});
|
|
146
|
-
return spawnAttached('tmux', args,
|
|
147
|
-
}
|
|
148
|
-
isInsideSession() {
|
|
149
|
-
return Boolean(process.env.TMUX);
|
|
126
|
+
return spawnAttached('tmux', args, sanitizedProcessEnv(), this.backend);
|
|
150
127
|
}
|
|
151
|
-
async kill(
|
|
152
|
-
if (!
|
|
128
|
+
async kill(handle) {
|
|
129
|
+
if (!handle)
|
|
153
130
|
return;
|
|
154
|
-
await execFileAsync(this.tmuxPath, ['kill-pane', '-t',
|
|
131
|
+
await execFileAsync(this.tmuxPath, ['kill-pane', '-t', handle], { timeout: 3000 });
|
|
155
132
|
}
|
|
156
|
-
async
|
|
157
|
-
const mode = options
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const cwd = options.cwd ?? process.cwd();
|
|
133
|
+
async split(options) {
|
|
134
|
+
const { toolName, args, env, cwd, mode, sentinelPath } = options;
|
|
135
|
+
// Configure tmux session defaults (mouse, scrollback, color)
|
|
136
|
+
configureTmuxSession();
|
|
161
137
|
// Resolve tool path
|
|
162
|
-
const
|
|
163
|
-
if (!
|
|
164
|
-
return { launched: false, backend: this.backend, reason: `${
|
|
138
|
+
const nativePath = findExecutable(toolName);
|
|
139
|
+
if (!nativePath) {
|
|
140
|
+
return { launched: false, backend: this.backend, reason: `${toolName} not found on PATH` };
|
|
165
141
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const bashPath = await resolveToolForBash(options.toolName);
|
|
170
|
-
if (bashPath) {
|
|
171
|
-
effectiveToolPath = bashPath;
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
return { launched: false, backend: this.backend, reason: `${options.toolName} not found in bash PATH (required for tmux pane)` };
|
|
175
|
-
}
|
|
142
|
+
const effectiveToolPath = await this.shell.resolveToolPath(toolName, nativePath);
|
|
143
|
+
if (!effectiveToolPath) {
|
|
144
|
+
return { launched: false, backend: this.backend, reason: `${toolName} not found in bash PATH (required for tmux pane)` };
|
|
176
145
|
}
|
|
177
|
-
// Sentinel IPC for exit code tracking
|
|
178
|
-
const useSentinel = options.sentinel !== false;
|
|
179
|
-
const sentinel = useSentinel ? createSentinelIpcPaths(`aiwcli-pane-${options.toolName}`) : null;
|
|
180
146
|
// Inject COLORTERM=truecolor for tmux
|
|
181
|
-
const
|
|
147
|
+
const effectiveEnv = { COLORTERM: 'truecolor', ...env };
|
|
182
148
|
try {
|
|
183
149
|
const promptText = mode === 'repl' && options.promptPath
|
|
184
150
|
? fs.readFileSync(options.promptPath, 'utf8')
|
|
185
151
|
: undefined;
|
|
186
|
-
|
|
152
|
+
let baseCommand = this.shell.buildToolCommand({
|
|
187
153
|
toolPath: effectiveToolPath,
|
|
188
154
|
args,
|
|
189
|
-
env:
|
|
155
|
+
env: effectiveEnv,
|
|
190
156
|
mode,
|
|
191
157
|
promptText,
|
|
192
158
|
...(options.promptPath ? { promptPath: options.promptPath } : {}),
|
|
193
159
|
});
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const holdMessage = options.holdMessage ?? '[aiwcli] Driver exited. Pane held open.';
|
|
197
|
-
paneCommand = wrapSentinelSh({
|
|
198
|
-
command: baseCommand,
|
|
199
|
-
sentinelPath: sentinel.sentinelPath,
|
|
200
|
-
autoClose: Boolean(options.autoClose),
|
|
201
|
-
holdPane: Boolean(options.holdPane),
|
|
202
|
-
holdMessage,
|
|
203
|
-
});
|
|
160
|
+
if (options.retryOnQuickExit) {
|
|
161
|
+
baseCommand = this.shell.wrapQuickExitRetry(baseCommand, this.shell.quote(effectiveToolPath));
|
|
204
162
|
}
|
|
163
|
+
const holdMessage = PANE_HOLD_MESSAGE;
|
|
164
|
+
const paneCommand = this.shell.wrapSentinel({
|
|
165
|
+
command: baseCommand,
|
|
166
|
+
sentinelPath,
|
|
167
|
+
autoClose: false,
|
|
168
|
+
holdPane: false,
|
|
169
|
+
holdMessage,
|
|
170
|
+
});
|
|
205
171
|
// Resolve split direction
|
|
206
|
-
const splitDirection = options.split
|
|
172
|
+
const splitDirection = options.split;
|
|
207
173
|
let splitFlag;
|
|
208
174
|
let splitTarget;
|
|
209
175
|
if (splitDirection === 'auto') {
|
|
210
176
|
try {
|
|
211
|
-
const resolved = await resolveAutoSplit(this.tmuxPath
|
|
177
|
+
const resolved = await resolveAutoSplit(this.tmuxPath);
|
|
212
178
|
splitFlag = resolved.splitFlag;
|
|
213
179
|
splitTarget = resolved.splitTarget;
|
|
214
180
|
}
|
|
215
181
|
catch {
|
|
216
182
|
splitFlag = '-h';
|
|
217
|
-
splitTarget = options.splitTarget?.trim();
|
|
218
183
|
}
|
|
219
184
|
}
|
|
220
185
|
else {
|
|
221
|
-
splitFlag = splitDirection
|
|
222
|
-
splitTarget = options.splitTarget?.trim();
|
|
186
|
+
splitFlag = toTmuxSplitFlag(splitDirection);
|
|
223
187
|
}
|
|
224
188
|
// Build tmux split-window command
|
|
225
|
-
const cwdPath =
|
|
189
|
+
const cwdPath = isWindowsPlatform() ? toMsysPosixPath(cwd) : cwd;
|
|
226
190
|
const bootstrappedCommand = withWindowsTmuxBootstrap(paneCommand);
|
|
227
191
|
const tmuxArgs = buildTmuxSplitWindowArgs({
|
|
228
192
|
splitFlag,
|
|
229
|
-
command: `bash -lc ${
|
|
193
|
+
command: `bash -lc ${this.shell.quote(bootstrappedCommand)}`,
|
|
230
194
|
cwd: cwdPath,
|
|
231
195
|
splitTarget,
|
|
232
196
|
});
|
|
233
197
|
const split = await execFileAsync(this.tmuxPath, tmuxArgs, { timeout: 5000 });
|
|
234
198
|
if (split.exitCode !== 0) {
|
|
235
|
-
if (sentinel)
|
|
236
|
-
cleanupSentinelIpc(sentinel);
|
|
237
199
|
return {
|
|
238
200
|
launched: false,
|
|
239
201
|
backend: this.backend,
|
|
240
202
|
reason: 'tmux split-window failed',
|
|
241
|
-
stderr: split.stderr.trim() || undefined,
|
|
242
203
|
};
|
|
243
204
|
}
|
|
244
|
-
const
|
|
205
|
+
const handle = getLastLine(split.stdout) || undefined;
|
|
245
206
|
return {
|
|
246
207
|
launched: true,
|
|
247
208
|
backend: this.backend,
|
|
248
|
-
|
|
249
|
-
sentinelPath
|
|
209
|
+
handle,
|
|
210
|
+
sentinelPath,
|
|
250
211
|
};
|
|
251
212
|
}
|
|
252
213
|
catch (error) {
|
|
253
|
-
if (sentinel)
|
|
254
|
-
cleanupSentinelIpc(sentinel);
|
|
255
214
|
return {
|
|
256
215
|
launched: false,
|
|
257
216
|
backend: this.backend,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WeztermMultiplexer — WezTerm backend for Windows.
|
|
3
|
+
* Composes with BashAdapter for command building.
|
|
4
|
+
* Owns: REPL-context gating (resolveStrategy), WezTerm pane management,
|
|
5
|
+
* holdPane behavior, auto-close command.
|
|
6
|
+
*/
|
|
7
|
+
import type { CreateSessionOptions, LaunchResult, Multiplexer, ResolvedStrategy, SplitOptions, StrategyContext } from '../multiplexer.js';
|
|
8
|
+
type WeztermSplitFlag = '--bottom' | '--right';
|
|
9
|
+
/** @internal — translate unified SplitDirection to wezterm flag. */
|
|
10
|
+
export declare function toWeztermSplitFlag(direction: 'horizontal' | 'vertical'): WeztermSplitFlag;
|
|
11
|
+
/** @internal */
|
|
12
|
+
export declare function buildWeztermSplitArgs(params: {
|
|
13
|
+
bashPath?: string | undefined;
|
|
14
|
+
command: string;
|
|
15
|
+
cwd?: string | undefined;
|
|
16
|
+
paneId?: string | undefined;
|
|
17
|
+
splitFlag: WeztermSplitFlag;
|
|
18
|
+
}): string[];
|
|
19
|
+
/** @internal */
|
|
20
|
+
export declare function buildWeztermSpawnArgs(params: {
|
|
21
|
+
bashPath?: string | undefined;
|
|
22
|
+
command: string;
|
|
23
|
+
cwd?: string | undefined;
|
|
24
|
+
}): string[];
|
|
25
|
+
/** @internal */
|
|
26
|
+
export declare function buildWeztermKillArgs(paneId: string): string[];
|
|
27
|
+
export declare class WeztermMultiplexer implements Multiplexer {
|
|
28
|
+
readonly backend: "wezterm";
|
|
29
|
+
private readonly weztermPath;
|
|
30
|
+
private readonly shell;
|
|
31
|
+
private constructor();
|
|
32
|
+
static create(): null | WeztermMultiplexer;
|
|
33
|
+
resolveStrategy(ctx: StrategyContext): ResolvedStrategy;
|
|
34
|
+
kill(handle: string): Promise<void>;
|
|
35
|
+
split(options: SplitOptions): Promise<LaunchResult>;
|
|
36
|
+
createSession(options: CreateSessionOptions): Promise<LaunchResult>;
|
|
37
|
+
}
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WeztermMultiplexer — WezTerm backend for Windows.
|
|
3
|
+
* Composes with BashAdapter for command building.
|
|
4
|
+
* Owns: REPL-context gating (resolveStrategy), WezTerm pane management,
|
|
5
|
+
* holdPane behavior, auto-close command.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import { PANE_HOLD_MESSAGE, getLastLine, splitFlagFromDimensions } from '../mux-utils.js';
|
|
9
|
+
import { execFileAsync, findExecutable } from '../runtime/subprocess-utils.js';
|
|
10
|
+
import { BashAdapter } from '../shell-adapters/bash-adapter.js';
|
|
11
|
+
/** @internal — translate unified SplitDirection to wezterm flag. */
|
|
12
|
+
export function toWeztermSplitFlag(direction) {
|
|
13
|
+
return direction === 'horizontal' ? '--right' : '--bottom';
|
|
14
|
+
}
|
|
15
|
+
/** @internal */
|
|
16
|
+
export function buildWeztermSplitArgs(params) {
|
|
17
|
+
const args = ['cli', 'split-pane', params.splitFlag];
|
|
18
|
+
if (params.cwd) {
|
|
19
|
+
args.push('--cwd', params.cwd);
|
|
20
|
+
}
|
|
21
|
+
if (params.paneId) {
|
|
22
|
+
args.push('--pane-id', params.paneId);
|
|
23
|
+
}
|
|
24
|
+
// Use -c (not -lc): login shell profiles may exec another shell (e.g. zsh),
|
|
25
|
+
// preventing the command from running. Tool paths are already absolute.
|
|
26
|
+
args.push('--', params.bashPath ?? 'bash', '-c', params.command);
|
|
27
|
+
return args;
|
|
28
|
+
}
|
|
29
|
+
/** @internal */
|
|
30
|
+
export function buildWeztermSpawnArgs(params) {
|
|
31
|
+
const args = ['cli', 'spawn', '--new-window'];
|
|
32
|
+
if (params.cwd) {
|
|
33
|
+
args.push('--cwd', params.cwd);
|
|
34
|
+
}
|
|
35
|
+
args.push('--', params.bashPath ?? 'bash', '-c', params.command);
|
|
36
|
+
return args;
|
|
37
|
+
}
|
|
38
|
+
/** @internal */
|
|
39
|
+
export function buildWeztermKillArgs(paneId) {
|
|
40
|
+
return ['cli', 'kill-pane', '--pane-id', paneId];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve Git Bash path on Windows. WezTerm may resolve bare `bash` to
|
|
44
|
+
* WSL's bash.exe instead of Git Bash.
|
|
45
|
+
*/
|
|
46
|
+
function resolveGitBash() {
|
|
47
|
+
return findExecutable('bash');
|
|
48
|
+
}
|
|
49
|
+
async function resolveAutoSplit(weztermPath, currentPaneId) {
|
|
50
|
+
try {
|
|
51
|
+
const result = await execFileAsync(weztermPath, ['cli', 'list', '--format', 'json'], { timeout: 3000 });
|
|
52
|
+
if (result.exitCode !== 0)
|
|
53
|
+
return '--right';
|
|
54
|
+
const panes = JSON.parse(result.stdout);
|
|
55
|
+
const targetId = currentPaneId ?? process.env.WEZTERM_PANE;
|
|
56
|
+
if (!targetId)
|
|
57
|
+
return '--right';
|
|
58
|
+
const pane = panes.find((p) => String(p.pane_id) === targetId);
|
|
59
|
+
if (!pane?.size)
|
|
60
|
+
return '--right';
|
|
61
|
+
const muxFlag = splitFlagFromDimensions(pane.size.cols, pane.size.rows);
|
|
62
|
+
return muxFlag === '-h' ? '--right' : '--bottom';
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return '--right';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export class WeztermMultiplexer {
|
|
69
|
+
backend = 'wezterm';
|
|
70
|
+
weztermPath;
|
|
71
|
+
shell;
|
|
72
|
+
constructor(weztermPath) {
|
|
73
|
+
this.weztermPath = weztermPath;
|
|
74
|
+
this.shell = new BashAdapter();
|
|
75
|
+
}
|
|
76
|
+
static create() {
|
|
77
|
+
if (!process.env.WEZTERM_PANE && process.env.TERM_PROGRAM !== 'WezTerm')
|
|
78
|
+
return null;
|
|
79
|
+
const weztermPath = findExecutable('wezterm');
|
|
80
|
+
if (!weztermPath)
|
|
81
|
+
return null;
|
|
82
|
+
return new WeztermMultiplexer(weztermPath);
|
|
83
|
+
}
|
|
84
|
+
resolveStrategy(ctx) {
|
|
85
|
+
if (ctx.disableMux) {
|
|
86
|
+
return { strategy: 'inline', reason: 'Multiplexer disabled via --no-tmux' };
|
|
87
|
+
}
|
|
88
|
+
// REPL-context gating: only split when called from a REPL session.
|
|
89
|
+
// From a shell (no REPL vars), launch inline.
|
|
90
|
+
if (!ctx.calledFromRepl) {
|
|
91
|
+
return { strategy: 'inline', reason: 'WezTerm shell — no REPL context, launching inline' };
|
|
92
|
+
}
|
|
93
|
+
return { strategy: 'split', reason: 'Inside WezTerm REPL — splitting pane' };
|
|
94
|
+
}
|
|
95
|
+
async kill(handle) {
|
|
96
|
+
if (!handle)
|
|
97
|
+
return;
|
|
98
|
+
await execFileAsync(this.weztermPath, buildWeztermKillArgs(handle), { timeout: 3000 });
|
|
99
|
+
}
|
|
100
|
+
async split(options) {
|
|
101
|
+
const { toolName, args, env, cwd, mode, sentinelPath } = options;
|
|
102
|
+
// Resolve tool path
|
|
103
|
+
const nativePath = findExecutable(toolName);
|
|
104
|
+
if (!nativePath) {
|
|
105
|
+
return { launched: false, backend: this.backend, reason: `${toolName} not found on PATH` };
|
|
106
|
+
}
|
|
107
|
+
const effectiveToolPath = await this.shell.resolveToolPath(toolName, nativePath);
|
|
108
|
+
if (!effectiveToolPath) {
|
|
109
|
+
return { launched: false, backend: this.backend, reason: `${toolName} not found in bash PATH (required for wezterm pane)` };
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const promptText = mode === 'repl' && options.promptPath
|
|
113
|
+
? fs.readFileSync(options.promptPath, 'utf8')
|
|
114
|
+
: undefined;
|
|
115
|
+
let baseCommand = this.shell.buildToolCommand({
|
|
116
|
+
toolPath: effectiveToolPath,
|
|
117
|
+
args,
|
|
118
|
+
env,
|
|
119
|
+
mode,
|
|
120
|
+
promptText,
|
|
121
|
+
...(options.promptPath ? { promptPath: options.promptPath } : {}),
|
|
122
|
+
});
|
|
123
|
+
if (options.retryOnQuickExit) {
|
|
124
|
+
baseCommand = this.shell.wrapQuickExitRetry(baseCommand, this.shell.quote(effectiveToolPath));
|
|
125
|
+
}
|
|
126
|
+
const gitBash = process.platform === 'win32' ? resolveGitBash() ?? undefined : undefined;
|
|
127
|
+
// WezTerm always holds pane and uses auto-close via wezterm kill-pane
|
|
128
|
+
const holdMessage = PANE_HOLD_MESSAGE;
|
|
129
|
+
let paneCommand = this.shell.wrapSentinel({
|
|
130
|
+
command: baseCommand,
|
|
131
|
+
sentinelPath,
|
|
132
|
+
autoClose: false,
|
|
133
|
+
autoCloseCommand: `wezterm cli kill-pane --pane-id $WEZTERM_PANE >/dev/null 2>&1 || true`,
|
|
134
|
+
holdPane: true,
|
|
135
|
+
holdMessage,
|
|
136
|
+
});
|
|
137
|
+
// Prepend nesting cleanup (PATH fix + unset REPL vars)
|
|
138
|
+
paneCommand = `${this.shell.buildNestingCleanup()} ${paneCommand}`;
|
|
139
|
+
// Resolve split direction
|
|
140
|
+
const splitDirection = options.split;
|
|
141
|
+
let splitFlag;
|
|
142
|
+
if (splitDirection === 'auto') {
|
|
143
|
+
splitFlag = await resolveAutoSplit(this.weztermPath);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
splitFlag = toWeztermSplitFlag(splitDirection);
|
|
147
|
+
}
|
|
148
|
+
const weztermArgs = buildWeztermSplitArgs({
|
|
149
|
+
splitFlag,
|
|
150
|
+
command: paneCommand,
|
|
151
|
+
cwd,
|
|
152
|
+
paneId: process.env.WEZTERM_PANE,
|
|
153
|
+
bashPath: gitBash,
|
|
154
|
+
});
|
|
155
|
+
const split = await execFileAsync(this.weztermPath, weztermArgs, { timeout: 5000 });
|
|
156
|
+
if (split.exitCode !== 0) {
|
|
157
|
+
return {
|
|
158
|
+
launched: false,
|
|
159
|
+
backend: this.backend,
|
|
160
|
+
reason: 'wezterm split-pane failed',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const handle = getLastLine(split.stdout) || undefined;
|
|
164
|
+
return {
|
|
165
|
+
launched: true,
|
|
166
|
+
backend: this.backend,
|
|
167
|
+
handle,
|
|
168
|
+
sentinelPath,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
return {
|
|
173
|
+
launched: false,
|
|
174
|
+
backend: this.backend,
|
|
175
|
+
reason: `pane launch failed: ${String(error)}`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async createSession(options) {
|
|
180
|
+
const { toolPath, toolArgs, cwd } = options;
|
|
181
|
+
// On Windows, resolve tool path from bash's perspective
|
|
182
|
+
let effectiveToolPath = toolPath;
|
|
183
|
+
if (process.platform === 'win32') {
|
|
184
|
+
const toolName = toolPath.split(/[\\/]/).pop()?.replace(/\.exe$/i, '') ?? toolPath;
|
|
185
|
+
const bashPath = await this.shell.resolveToolPath(toolName, toolPath);
|
|
186
|
+
if (bashPath) {
|
|
187
|
+
effectiveToolPath = bashPath;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const baseCommand = this.shell.buildToolCommand({
|
|
191
|
+
toolPath: effectiveToolPath,
|
|
192
|
+
args: toolArgs,
|
|
193
|
+
env: {},
|
|
194
|
+
mode: 'repl',
|
|
195
|
+
promptText: options.promptText,
|
|
196
|
+
});
|
|
197
|
+
// Prepend nesting cleanup
|
|
198
|
+
const spawnCommand = `${this.shell.buildNestingCleanup()} ${baseCommand}`;
|
|
199
|
+
const weztermArgs = buildWeztermSpawnArgs({
|
|
200
|
+
command: spawnCommand,
|
|
201
|
+
cwd,
|
|
202
|
+
bashPath: process.platform === 'win32' ? resolveGitBash() ?? undefined : undefined,
|
|
203
|
+
});
|
|
204
|
+
try {
|
|
205
|
+
const result = await execFileAsync(this.weztermPath, weztermArgs, { timeout: 5000 });
|
|
206
|
+
if (result.exitCode !== 0) {
|
|
207
|
+
return {
|
|
208
|
+
launched: false,
|
|
209
|
+
exitCode: result.exitCode,
|
|
210
|
+
backend: this.backend,
|
|
211
|
+
reason: `wezterm spawn failed: ${result.stderr.trim() || 'unknown error'}`,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return { launched: true, exitCode: 0, backend: this.backend };
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
return {
|
|
218
|
+
launched: false,
|
|
219
|
+
exitCode: -1,
|
|
220
|
+
backend: this.backend,
|
|
221
|
+
reason: `wezterm spawn failed: ${String(error)}`,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
package/dist/lib/mux-utils.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LaunchResult } from './multiplexer.js';
|
|
2
2
|
export declare function getLastLine(text: string): string;
|
|
3
|
-
export declare function spawnAttached(command: string, args: string[], env: NodeJS.ProcessEnv | undefined, backendLabel: string): Promise<
|
|
3
|
+
export declare function spawnAttached(command: string, args: string[], env: NodeJS.ProcessEnv | undefined, backendLabel: string): Promise<LaunchResult>;
|
|
4
4
|
export declare function splitFlagFromDimensions(width: number, height: number): '-h' | '-v';
|
|
5
|
-
export declare
|
|
5
|
+
export declare const PANE_HOLD_MESSAGE = "[aiwcli] Driver exited. Pane held open.";
|
|
6
|
+
export declare function buildBootstrapPrompt(filePath: string): string;
|
package/dist/lib/mux-utils.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { getInternalSubprocessEnv } from './runtime/subprocess-utils.js';
|
|
3
2
|
const CELL_ASPECT_RATIO = 2;
|
|
4
3
|
export function getLastLine(text) {
|
|
5
4
|
const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
@@ -12,18 +11,18 @@ export function spawnAttached(command, args, env, backendLabel) {
|
|
|
12
11
|
child = spawn(command, args, { stdio: 'inherit', env: env ?? process.env });
|
|
13
12
|
}
|
|
14
13
|
catch (error) {
|
|
15
|
-
resolve({ exitCode: -1,
|
|
14
|
+
resolve({ launched: false, exitCode: -1, backend: backendLabel, reason: error instanceof Error ? error.message : String(error) });
|
|
16
15
|
return;
|
|
17
16
|
}
|
|
18
17
|
child.on('error', (error) => {
|
|
19
|
-
resolve({ exitCode: -1,
|
|
18
|
+
resolve({ launched: false, exitCode: -1, backend: backendLabel, reason: error.message });
|
|
20
19
|
});
|
|
21
20
|
child.on('close', (code) => {
|
|
22
21
|
if (code === 0) {
|
|
23
|
-
resolve({ exitCode: 0,
|
|
22
|
+
resolve({ launched: true, exitCode: 0, backend: backendLabel });
|
|
24
23
|
}
|
|
25
24
|
else {
|
|
26
|
-
resolve({ exitCode: code ?? 1,
|
|
25
|
+
resolve({ launched: false, exitCode: code ?? 1, backend: backendLabel, reason: `${backendLabel} exited with code ${code ?? 1}` });
|
|
27
26
|
}
|
|
28
27
|
});
|
|
29
28
|
});
|
|
@@ -31,12 +30,7 @@ export function spawnAttached(command, args, env, backendLabel) {
|
|
|
31
30
|
export function splitFlagFromDimensions(width, height) {
|
|
32
31
|
return width >= height * CELL_ASPECT_RATIO ? '-h' : '-v';
|
|
33
32
|
}
|
|
34
|
-
export
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
...extra,
|
|
38
|
-
};
|
|
39
|
-
delete env['CLAUDECODE'];
|
|
40
|
-
delete env['CLAUDE_CODE_ENTRYPOINT'];
|
|
41
|
-
return env;
|
|
33
|
+
export const PANE_HOLD_MESSAGE = '[aiwcli] Driver exited. Pane held open.';
|
|
34
|
+
export function buildBootstrapPrompt(filePath) {
|
|
35
|
+
return `Read startup instructions from this file path before taking action: ${filePath}. Use that file as the initial context.`;
|
|
42
36
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PromptFileManager — owns prompt file lifecycle (creation, cleanup).
|
|
3
|
+
* Replaces scattered writeFileSync calls for prompt temp files.
|
|
4
|
+
*/
|
|
5
|
+
export declare class PromptFileManager {
|
|
6
|
+
private readonly files;
|
|
7
|
+
private readonly tempDir;
|
|
8
|
+
private readonly now;
|
|
9
|
+
private readonly pid;
|
|
10
|
+
constructor(options: {
|
|
11
|
+
tempDir: string;
|
|
12
|
+
now: () => number;
|
|
13
|
+
pid: number;
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* Write prompt text to a temp file and return the path.
|
|
17
|
+
*/
|
|
18
|
+
materialize(promptText: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Clean up all created prompt files. Call in finally block.
|
|
21
|
+
*/
|
|
22
|
+
cleanup(): void;
|
|
23
|
+
}
|