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
package/bin/run.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// Load environment variable compatibility layer first
|
|
4
|
-
const {loadEnvWithCompatibility} = await import('../dist/lib/env-compat.js')
|
|
5
|
-
loadEnvWithCompatibility()
|
|
6
|
-
|
|
7
3
|
import {execute} from '@oclif/core'
|
|
8
4
|
|
|
9
5
|
// Handle default command: inject 'launch' when no command is specified
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import BaseCommand from '../../../cli/base-command.js';
|
|
2
|
+
export declare const PROTECTED_OUTPUT_DIRS: Set<string>;
|
|
2
3
|
/**
|
|
3
4
|
* Clear method runtime folders, output folders, IDE method folders, and update configurations.
|
|
4
5
|
*/
|
|
@@ -139,6 +140,7 @@ export default class ClearCommand extends BaseCommand {
|
|
|
139
140
|
* @param cleanup.removedAiwcliContainer - Whether .aiwcli dir was removed
|
|
140
141
|
* @param cleanup.removedClaudeDir - Whether .claude dir was removed
|
|
141
142
|
* @param cleanup.removedCodexDir - Whether .codex dir was removed
|
|
143
|
+
* @param cleanup.removedDevinDir - Whether .devin dir was removed
|
|
142
144
|
* @param cleanup.removedWindsurfDir - Whether .windsurf dir was removed
|
|
143
145
|
* @param cleanup.removedCoreIdeFiles - Number of core IDE files removed
|
|
144
146
|
* @param cleanup.updatedClaudeSettings - Whether Claude settings were updated
|
|
@@ -22,6 +22,7 @@ const OUTPUT_FOLDER_NAME = '_output';
|
|
|
22
22
|
const CORE_TEMPLATE_NAME = 'core';
|
|
23
23
|
const SETTINGS_FILES_TO_SKIP = new Set(['hooks.json', 'settings.json']);
|
|
24
24
|
const CORE_RUNTIME_FOLDERS = ['_core'];
|
|
25
|
+
export const PROTECTED_OUTPUT_DIRS = new Set(['contexts', 'cache', '_archive']);
|
|
25
26
|
/**
|
|
26
27
|
* IDE configuration folder names and settings file locations.
|
|
27
28
|
* Method subfolders are discovered dynamically via disk scanning.
|
|
@@ -34,6 +35,9 @@ const IDE_FOLDERS = {
|
|
|
34
35
|
codex: {
|
|
35
36
|
root: '.codex',
|
|
36
37
|
},
|
|
38
|
+
devin: {
|
|
39
|
+
root: '.devin',
|
|
40
|
+
},
|
|
37
41
|
windsurf: {
|
|
38
42
|
root: '.windsurf',
|
|
39
43
|
settingsFile: 'hooks.json',
|
|
@@ -441,6 +445,22 @@ export default class ClearCommand extends BaseCommand {
|
|
|
441
445
|
}
|
|
442
446
|
// Execute deletion and cleanup
|
|
443
447
|
const deleteCounts = await this.executeFolderDeletion(methodRuntimeFolders, outputMethodFolders, ideMethodFolders, coreRuntimeFolders);
|
|
448
|
+
// Audit log for aiw clear operations (only if _output/ will survive — don't create orphan files)
|
|
449
|
+
try {
|
|
450
|
+
const outputDir = join(targetDir, OUTPUT_FOLDER_NAME);
|
|
451
|
+
if (await pathExists(outputDir) && !await isDirectoryEmpty(outputDir)) {
|
|
452
|
+
const hookLogPath = join(outputDir, 'hook-log.jsonl');
|
|
453
|
+
const logEntry = JSON.stringify({
|
|
454
|
+
ts: new Date().toISOString(),
|
|
455
|
+
level: 'warn',
|
|
456
|
+
hook: 'aiw_clear',
|
|
457
|
+
msg: `aiw clear: deleted ${deleteCounts.deletedMethodRuntime + deleteCounts.deletedOutput + deleteCounts.deletedIde + deleteCounts.deletedCoreRuntime} folder(s)`,
|
|
458
|
+
data: { methodRuntime: deleteCounts.deletedMethodRuntime, output: deleteCounts.deletedOutput, ide: deleteCounts.deletedIde, coreRuntime: deleteCounts.deletedCoreRuntime }
|
|
459
|
+
});
|
|
460
|
+
await fs.appendFile(hookLogPath, logEntry + '\n');
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
catch { /* non-critical */ }
|
|
444
464
|
const cleanupResult = await this.performPostDeleteCleanup(targetDir, methodsToRemove, !isTemplateScoped);
|
|
445
465
|
this.reportClearResults(deleteCounts, cleanupResult);
|
|
446
466
|
}
|
|
@@ -753,9 +773,10 @@ export default class ClearCommand extends BaseCommand {
|
|
|
753
773
|
this.log('');
|
|
754
774
|
}
|
|
755
775
|
// Check if IDE folders might be removed after clearing
|
|
756
|
-
const [willClaudeFolderBeEmpty, willCodexFolderBeEmpty, willWindsurfFolderBeEmpty] = await Promise.all([
|
|
776
|
+
const [willClaudeFolderBeEmpty, willCodexFolderBeEmpty, willDevinFolderBeEmpty, willWindsurfFolderBeEmpty] = await Promise.all([
|
|
757
777
|
checkIdeRemovalEligibility(targetDir, IDE_FOLDERS.claude, ideMethodFolders),
|
|
758
778
|
checkIdeRemovalEligibility(targetDir, IDE_FOLDERS.codex, ideMethodFolders),
|
|
779
|
+
checkIdeRemovalEligibility(targetDir, IDE_FOLDERS.devin, ideMethodFolders),
|
|
759
780
|
checkIdeRemovalEligibility(targetDir, IDE_FOLDERS.windsurf, ideMethodFolders),
|
|
760
781
|
]);
|
|
761
782
|
if (willClaudeFolderBeEmpty) {
|
|
@@ -766,6 +787,10 @@ export default class ClearCommand extends BaseCommand {
|
|
|
766
787
|
this.logInfo(`${IDE_FOLDERS.codex.root}/ folder will be removed (will be empty)`);
|
|
767
788
|
this.log('');
|
|
768
789
|
}
|
|
790
|
+
if (willDevinFolderBeEmpty) {
|
|
791
|
+
this.logInfo(`${IDE_FOLDERS.devin.root}/ folder will be removed (will be empty)`);
|
|
792
|
+
this.log('');
|
|
793
|
+
}
|
|
769
794
|
if (willWindsurfFolderBeEmpty) {
|
|
770
795
|
this.logInfo(`${IDE_FOLDERS.windsurf.root}/ folder will be removed (will be empty)`);
|
|
771
796
|
this.log('');
|
|
@@ -958,7 +983,7 @@ export default class ClearCommand extends BaseCommand {
|
|
|
958
983
|
try {
|
|
959
984
|
const entries = await fs.readdir(outputDir, { withFileTypes: true });
|
|
960
985
|
for (const entry of entries) {
|
|
961
|
-
if (entry.isDirectory()) {
|
|
986
|
+
if (entry.isDirectory() && !PROTECTED_OUTPUT_DIRS.has(entry.name)) {
|
|
962
987
|
foundFolders.push(join(outputDir, entry.name));
|
|
963
988
|
}
|
|
964
989
|
}
|
|
@@ -1024,6 +1049,7 @@ export default class ClearCommand extends BaseCommand {
|
|
|
1024
1049
|
if (removedClaudeDir)
|
|
1025
1050
|
updatedClaudeSettings = false;
|
|
1026
1051
|
const removedCodexDir = await this.tryRemoveIdeFolder(targetDir, IDE_FOLDERS.codex);
|
|
1052
|
+
const removedDevinDir = await this.tryRemoveIdeFolder(targetDir, IDE_FOLDERS.devin);
|
|
1027
1053
|
const removedWindsurfDir = await this.tryRemoveIdeFolder(targetDir, IDE_FOLDERS.windsurf);
|
|
1028
1054
|
if (removedWindsurfDir)
|
|
1029
1055
|
updatedWindsurfSettings = false;
|
|
@@ -1031,7 +1057,7 @@ export default class ClearCommand extends BaseCommand {
|
|
|
1031
1057
|
const gitExcludeUpdated = await this.cleanupGitExclude(targetDir, isFullClear);
|
|
1032
1058
|
return {
|
|
1033
1059
|
removedCoreIdeFiles,
|
|
1034
|
-
removedOutputDir, removedAiwcliContainer, removedClaudeDir, removedCodexDir, removedWindsurfDir,
|
|
1060
|
+
removedOutputDir, removedAiwcliContainer, removedClaudeDir, removedCodexDir, removedDevinDir, removedWindsurfDir,
|
|
1035
1061
|
updatedClaudeSettings, updatedWindsurfSettings, gitExcludeUpdated,
|
|
1036
1062
|
};
|
|
1037
1063
|
}
|
|
@@ -1109,6 +1135,7 @@ export default class ClearCommand extends BaseCommand {
|
|
|
1109
1135
|
* @param cleanup.removedAiwcliContainer - Whether .aiwcli dir was removed
|
|
1110
1136
|
* @param cleanup.removedClaudeDir - Whether .claude dir was removed
|
|
1111
1137
|
* @param cleanup.removedCodexDir - Whether .codex dir was removed
|
|
1138
|
+
* @param cleanup.removedDevinDir - Whether .devin dir was removed
|
|
1112
1139
|
* @param cleanup.removedWindsurfDir - Whether .windsurf dir was removed
|
|
1113
1140
|
* @param cleanup.removedCoreIdeFiles - Number of core IDE files removed
|
|
1114
1141
|
* @param cleanup.updatedClaudeSettings - Whether Claude settings were updated
|
|
@@ -1135,6 +1162,8 @@ export default class ClearCommand extends BaseCommand {
|
|
|
1135
1162
|
parts.push(`${IDE_FOLDERS.claude.root}/ folder`);
|
|
1136
1163
|
if (cleanup.removedCodexDir)
|
|
1137
1164
|
parts.push(`${IDE_FOLDERS.codex.root}/ folder`);
|
|
1165
|
+
if (cleanup.removedDevinDir)
|
|
1166
|
+
parts.push(`${IDE_FOLDERS.devin.root}/ folder`);
|
|
1138
1167
|
if (cleanup.removedWindsurfDir)
|
|
1139
1168
|
parts.push(`${IDE_FOLDERS.windsurf.root}/ folder`);
|
|
1140
1169
|
this.logSuccess(`Cleared: ${parts.join(', ')}.`);
|
|
@@ -21,7 +21,7 @@ import { EXIT_CODES } from '../../../types/exit-codes.js';
|
|
|
21
21
|
const KNOWN_IDES = [
|
|
22
22
|
{ value: 'claude', name: 'Claude Code', description: 'Anthropic Claude Code CLI' },
|
|
23
23
|
{ value: 'codex', name: 'Codex CLI', description: 'OpenAI Codex CLI skills' },
|
|
24
|
-
{ value: '
|
|
24
|
+
{ value: 'devin', name: 'Devin', description: 'Devin CLI' },
|
|
25
25
|
{ value: 'windsurf', name: 'Windsurf', description: 'Codeium Windsurf IDE' },
|
|
26
26
|
];
|
|
27
27
|
// detectGitRepository replaced by resolveGitDir from git-exclude-manager
|
|
@@ -237,7 +237,7 @@ export default class Init extends BaseCommand {
|
|
|
237
237
|
*/
|
|
238
238
|
async installGlobalResolver() {
|
|
239
239
|
try {
|
|
240
|
-
const resolverSrc = getCoreResolverSourcePath();
|
|
240
|
+
const resolverSrc = await getCoreResolverSourcePath();
|
|
241
241
|
const globalBinDir = join(homedir(), '.aiwcli', 'bin');
|
|
242
242
|
const resolverDest = join(globalBinDir, 'resolve-run.ts');
|
|
243
243
|
await fs.mkdir(globalBinDir, { recursive: true });
|
|
@@ -1,4 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
export type ToolMode = 'claude' | 'codex' | 'devin';
|
|
2
|
+
export interface ToolConfig {
|
|
3
|
+
cliCommand: string;
|
|
4
|
+
cliArgs: string[];
|
|
5
|
+
launchFlag: string;
|
|
6
|
+
toolMode: ToolMode;
|
|
7
|
+
retryOnQuickExit: boolean;
|
|
8
|
+
needsLspPatch: boolean;
|
|
9
|
+
skipVersionCheck: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface InlineFallbackContext {
|
|
12
|
+
disableMux: boolean;
|
|
13
|
+
hasMux: boolean;
|
|
14
|
+
interactiveTty: boolean;
|
|
15
|
+
platform: NodeJS.Platform;
|
|
16
|
+
resolvedReason?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SplitRequestParams {
|
|
19
|
+
toolArgs: string[];
|
|
20
|
+
splitPromptPath: string | undefined;
|
|
21
|
+
env: Record<string, string>;
|
|
22
|
+
cwd: string;
|
|
23
|
+
mode: 'repl';
|
|
24
|
+
split: 'auto' | 'horizontal' | 'vertical';
|
|
25
|
+
sentinelPath: string;
|
|
26
|
+
holdPane: boolean;
|
|
27
|
+
retryOnQuickExit: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface SessionRequestParams {
|
|
30
|
+
sessionName: string;
|
|
31
|
+
reattach: boolean;
|
|
32
|
+
toolArgs: string[];
|
|
33
|
+
promptText: string | undefined;
|
|
34
|
+
}
|
|
2
35
|
export interface LaunchFlags {
|
|
3
36
|
codex: boolean;
|
|
4
37
|
devin: boolean;
|
|
@@ -10,7 +43,7 @@ export interface LaunchFlags {
|
|
|
10
43
|
'prompt-file'?: string | undefined;
|
|
11
44
|
'prompt-path'?: string | undefined;
|
|
12
45
|
'spawned-window': boolean;
|
|
13
|
-
split?: 'auto' | '
|
|
46
|
+
split?: 'auto' | 'horizontal' | 'vertical' | undefined;
|
|
14
47
|
'tmux-session'?: string | undefined;
|
|
15
48
|
wait: boolean;
|
|
16
49
|
}
|
|
@@ -40,12 +73,14 @@ export interface LaunchDependencies {
|
|
|
40
73
|
pid: number;
|
|
41
74
|
tempDir: string;
|
|
42
75
|
writePromptFile(filePath: string, content: string): void;
|
|
76
|
+
isCalledFromRepl?: () => boolean;
|
|
77
|
+
clearNestingVars?: () => void;
|
|
43
78
|
}
|
|
44
79
|
export interface JsonLaunchResult {
|
|
45
|
-
backend:
|
|
80
|
+
backend: string;
|
|
46
81
|
exitCode: null | number;
|
|
82
|
+
handle: null | string;
|
|
47
83
|
launched: boolean;
|
|
48
|
-
paneId: null | string;
|
|
49
84
|
reason: null | string;
|
|
50
85
|
sentinelPath: null | string;
|
|
51
86
|
}
|
|
@@ -1,40 +1,46 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { checkVersionCompatibility,
|
|
2
|
+
import { checkVersionCompatibility, detectMultiplexer, ensureLspPatch, findExecutable, findToolPath, getClaudeCodeVersion, launchTerminal, ProcessSpawnError, quoteForSh, spawnProcess, } from '../../../platform/launch.js';
|
|
3
3
|
import { EXIT_CODES } from '../../../types/index.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
sentinelPath: result.sentinelPath ?? null,
|
|
19
|
-
exitCode,
|
|
20
|
-
reason: result.reason ?? null,
|
|
21
|
-
};
|
|
4
|
+
import { clearProcessNestingVars, isCalledFromRepl } from '../../../lib/env-sanitizer.js';
|
|
5
|
+
import { PromptFileManager } from '../../../lib/prompt-file-manager.js';
|
|
6
|
+
import { SentinelManager } from '../../../lib/sentinel-manager.js';
|
|
7
|
+
import { formatPathWarning } from '../../../lib/spawn-errors.js';
|
|
8
|
+
import { buildSpawnedWindowArgs, parseExtraEnv, resolvePromptText, } from '../runtime-core/launch-options.js';
|
|
9
|
+
import { buildInlineArgs, buildSessionRequest, buildSplitRequest, formatSessionLaunchMessage, formatSplitSuccessMessage, formatVersionCheckMessages, QUICK_EXIT_THRESHOLD_MS, resolveInlineFallbackMessage, resolveSessionFallbackWarning, resolveToolConfig, resolveToolModeDebugMessage, shouldRetry, toJsonLaunchResult, } from '../runtime-core/launch-decisions.js';
|
|
10
|
+
async function runPreflightWarmup(command, host) {
|
|
11
|
+
try {
|
|
12
|
+
const result = await spawnProcess(command, ['--version'], { stdio: 'pipe' });
|
|
13
|
+
host.debug(`${command} preflight: exit=${result}`);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
host.debug(`${command} preflight failed (non-fatal)`);
|
|
17
|
+
}
|
|
22
18
|
}
|
|
23
|
-
async function
|
|
24
|
-
if (
|
|
25
|
-
|
|
19
|
+
async function spawnInlineWithRetry(command, args, retryOnQuickExit, host) {
|
|
20
|
+
if (retryOnQuickExit) {
|
|
21
|
+
await runPreflightWarmup(command, host);
|
|
26
22
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
23
|
+
const start = Date.now();
|
|
24
|
+
let exitCode = await spawnProcess(command, args);
|
|
25
|
+
if (retryOnQuickExit && shouldRetry(Date.now() - start)) {
|
|
26
|
+
host.debug(`${command} exited in <${QUICK_EXIT_THRESHOLD_MS}ms — retrying (first-run init behavior)`);
|
|
27
|
+
exitCode = await spawnProcess(command, args);
|
|
28
|
+
}
|
|
29
|
+
return exitCode;
|
|
29
30
|
}
|
|
30
31
|
export async function executeLaunch(request, dependencies) {
|
|
31
32
|
const { cwd, flags, interactiveTty, platform, readPromptFile } = request;
|
|
32
33
|
const { host, now, pid, tempDir, writePromptFile } = dependencies;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
// 1. Capture REPL context BEFORE clearing env vars (injectable for testing)
|
|
35
|
+
const calledFromRepl = (dependencies.isCalledFromRepl ?? isCalledFromRepl)();
|
|
36
|
+
(dependencies.clearNestingVars ?? clearProcessNestingVars)();
|
|
37
|
+
// Pure decision: resolve tool config
|
|
38
|
+
const toolConfig = resolveToolConfig(flags, platform);
|
|
39
|
+
const { cliCommand, cliArgs, launchFlag, toolMode } = toolConfig;
|
|
40
|
+
const disableMux = flags['no-tmux'];
|
|
41
|
+
const wantJson = flags.json;
|
|
42
|
+
const wantWait = flags.wait;
|
|
43
|
+
if (toolConfig.needsLspPatch) {
|
|
38
44
|
await ensureLspPatch({
|
|
39
45
|
debugLog: (message) => host.debug(message),
|
|
40
46
|
warn(message) {
|
|
@@ -42,12 +48,6 @@ export async function executeLaunch(request, dependencies) {
|
|
|
42
48
|
},
|
|
43
49
|
});
|
|
44
50
|
}
|
|
45
|
-
const cliCommand = useDevin ? 'devin' : useCodex ? 'codex' : 'claude';
|
|
46
|
-
const cliArgs = useDevin ? buildDevinArgs() : useCodex ? buildCodexArgs(platform) : ['--dangerously-skip-permissions'];
|
|
47
|
-
const launchFlag = useDevin ? '--devin' : useCodex ? '--codex' : '';
|
|
48
|
-
const disableTmux = flags['no-tmux'];
|
|
49
|
-
const wantJson = flags.json;
|
|
50
|
-
const wantWait = flags.wait;
|
|
51
51
|
let extraEnv = {};
|
|
52
52
|
try {
|
|
53
53
|
extraEnv = parseExtraEnv(flags.env);
|
|
@@ -59,6 +59,7 @@ export async function executeLaunch(request, dependencies) {
|
|
|
59
59
|
}
|
|
60
60
|
const promptPath = flags['prompt-path']?.trim() || undefined;
|
|
61
61
|
const promptText = resolvePromptText(flags.prompt, flags['prompt-file'], readPromptFile);
|
|
62
|
+
// 2. Handle --new (terminal window)
|
|
62
63
|
if (flags.new) {
|
|
63
64
|
host.debug(`Launching new terminal in: ${cwd}`);
|
|
64
65
|
let promptFilePath;
|
|
@@ -67,9 +68,9 @@ export async function executeLaunch(request, dependencies) {
|
|
|
67
68
|
writePromptFile(promptFilePath, promptText);
|
|
68
69
|
}
|
|
69
70
|
const launchArgs = buildSpawnedWindowArgs({
|
|
70
|
-
useCodex,
|
|
71
|
-
useDevin,
|
|
72
|
-
disableTmux,
|
|
71
|
+
useCodex: flags.codex,
|
|
72
|
+
useDevin: flags.devin,
|
|
73
|
+
disableTmux: disableMux,
|
|
73
74
|
...(promptPath ? { promptPath } : {}),
|
|
74
75
|
...(promptFilePath ? { promptFilePath } : {}),
|
|
75
76
|
...(flags.env ? { rawEnvJson: flags.env } : {}),
|
|
@@ -88,127 +89,159 @@ export async function executeLaunch(request, dependencies) {
|
|
|
88
89
|
host.log(`New terminal launched with aiw launch${launchFlag ? ` ${launchFlag}` : ''}`);
|
|
89
90
|
return;
|
|
90
91
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
host.debug('Launching Devin with --permission-mode dangerous');
|
|
96
|
-
}
|
|
92
|
+
const toolDebugMsg = resolveToolModeDebugMessage(toolMode);
|
|
93
|
+
if (toolDebugMsg)
|
|
94
|
+
host.debug(toolDebugMsg);
|
|
95
|
+
// 3. Detect multiplexer + version check
|
|
97
96
|
const [versionCheck, mux] = await Promise.all([
|
|
98
|
-
|
|
97
|
+
toolConfig.skipVersionCheck
|
|
99
98
|
? null
|
|
100
99
|
: getClaudeCodeVersion().then((v) => checkVersionCompatibility(v)),
|
|
101
|
-
|
|
100
|
+
disableMux ? null : detectMultiplexer(platform),
|
|
102
101
|
]);
|
|
103
102
|
if (versionCheck) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
const msgs = formatVersionCheckMessages(versionCheck);
|
|
104
|
+
for (const line of msgs.debugLines)
|
|
105
|
+
host.debug(line);
|
|
106
|
+
if (msgs.warning)
|
|
107
|
+
host.warn(msgs.warning);
|
|
108
|
+
}
|
|
109
|
+
// 4. Resolve strategy — backend decides
|
|
110
|
+
const resolved = mux?.resolveStrategy({ calledFromRepl, platform, disableMux })
|
|
111
|
+
?? { strategy: 'inline', reason: 'No multiplexer available' };
|
|
112
|
+
if (!mux || resolved.strategy === 'inline' || resolved.strategy === 'unavailable') {
|
|
113
|
+
// Pure decision: resolve fallback message
|
|
114
|
+
host.logInfo(resolveInlineFallbackMessage({
|
|
115
|
+
disableMux,
|
|
116
|
+
hasMux: Boolean(mux),
|
|
117
|
+
interactiveTty,
|
|
118
|
+
platform,
|
|
119
|
+
resolvedReason: resolved.reason,
|
|
120
|
+
}));
|
|
121
|
+
try {
|
|
122
|
+
// Pure decision: build inline args
|
|
123
|
+
const inlineArgs = buildInlineArgs(cliArgs, toolMode, promptText, promptPath);
|
|
124
|
+
const exitCode = await spawnInlineWithRetry(cliCommand, inlineArgs, toolConfig.retryOnQuickExit, host);
|
|
125
|
+
host.exit(exitCode);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (error instanceof ProcessSpawnError) {
|
|
129
|
+
host.error(error.message, { exit: EXIT_CODES.ENVIRONMENT_ERROR });
|
|
130
|
+
}
|
|
131
|
+
host.error('Unexpected launch failure.', { exit: EXIT_CODES.GENERAL_ERROR });
|
|
108
132
|
}
|
|
133
|
+
return;
|
|
109
134
|
}
|
|
135
|
+
// Lifecycle managers
|
|
136
|
+
const sentinelMgr = new SentinelManager();
|
|
137
|
+
const promptMgr = new PromptFileManager({ tempDir, now, pid });
|
|
138
|
+
// When --json is used without --wait, sentinel ownership transfers to the
|
|
139
|
+
// JSON caller (e.g. skill scripts). The CLI must NOT clean up the sentinel
|
|
140
|
+
// directory because the caller polls for sentinel.txt to detect pane close.
|
|
141
|
+
let sentinelOwnershipTransferred = false;
|
|
110
142
|
let exitCode = 0;
|
|
111
143
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
else if (!interactiveTty) {
|
|
117
|
-
host.logInfo('Non-interactive terminal — launching inline');
|
|
118
|
-
}
|
|
119
|
-
else if (platform === 'win32') {
|
|
120
|
-
host.logInfo('No multiplexer found — launching inline. Install psmux for session management: winget install psmux');
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
host.logInfo('No multiplexer found — launching inline. Install tmux for session management.');
|
|
124
|
-
}
|
|
125
|
-
exitCode = await spawnProcess(cliCommand, promptText ? [...cliArgs, promptText] : cliArgs);
|
|
126
|
-
}
|
|
127
|
-
else if (mux.isInsideSession()) {
|
|
144
|
+
const strategy = resolved.strategy;
|
|
145
|
+
if (strategy === 'split') {
|
|
146
|
+
// 5a. Split pane
|
|
128
147
|
host.logInfo(`Inside ${mux.backend} session — splitting new pane`);
|
|
129
|
-
|
|
130
|
-
configureTmuxSession();
|
|
131
|
-
}
|
|
148
|
+
const sentinelPath = sentinelMgr.create(cliCommand);
|
|
132
149
|
let effectivePromptPath = promptPath;
|
|
133
150
|
if (!effectivePromptPath && promptText) {
|
|
134
|
-
effectivePromptPath =
|
|
135
|
-
writePromptFile(effectivePromptPath, promptText);
|
|
151
|
+
effectivePromptPath = promptMgr.materialize(promptText);
|
|
136
152
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
153
|
+
// Pure decision: build split request (fixes cliArgs mutation bug)
|
|
154
|
+
const splitParams = buildSplitRequest({
|
|
155
|
+
cliArgs,
|
|
156
|
+
toolMode,
|
|
157
|
+
effectivePromptPath,
|
|
158
|
+
extraEnv,
|
|
141
159
|
cwd,
|
|
142
160
|
split: flags.split ?? 'auto',
|
|
143
|
-
|
|
144
|
-
|
|
161
|
+
sentinelPath,
|
|
162
|
+
retryOnQuickExit: toolConfig.retryOnQuickExit,
|
|
163
|
+
});
|
|
164
|
+
const splitResult = await mux.split({
|
|
165
|
+
toolName: cliCommand,
|
|
166
|
+
args: splitParams.toolArgs,
|
|
167
|
+
env: splitParams.env,
|
|
168
|
+
cwd: splitParams.cwd,
|
|
169
|
+
mode: splitParams.mode,
|
|
170
|
+
split: splitParams.split,
|
|
171
|
+
promptPath: splitParams.splitPromptPath,
|
|
172
|
+
sentinelPath: splitParams.sentinelPath,
|
|
173
|
+
holdPane: splitParams.holdPane,
|
|
174
|
+
retryOnQuickExit: splitParams.retryOnQuickExit,
|
|
145
175
|
});
|
|
146
176
|
if (wantJson) {
|
|
147
|
-
const jsonExitCode =
|
|
177
|
+
const jsonExitCode = wantWait && splitResult.launched && splitResult.sentinelPath
|
|
178
|
+
? await sentinelMgr.waitForExit(splitResult.sentinelPath)
|
|
179
|
+
: splitResult.exitCode ?? null;
|
|
180
|
+
// When returning sentinel path to caller without waiting, transfer
|
|
181
|
+
// ownership so the finally block does not delete the directory.
|
|
182
|
+
if (!wantWait && splitResult.launched && splitResult.sentinelPath) {
|
|
183
|
+
sentinelOwnershipTransferred = true;
|
|
184
|
+
}
|
|
148
185
|
host.log(JSON.stringify(toJsonLaunchResult(splitResult, jsonExitCode)));
|
|
149
186
|
host.exit(jsonExitCode ?? 0);
|
|
150
187
|
}
|
|
151
188
|
if (splitResult.launched) {
|
|
152
|
-
|
|
153
|
-
host.logInfo(`Launched in ${mux.backend} pane: ${splitResult.paneId}`);
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
host.logInfo(`Launched in ${mux.backend}`);
|
|
157
|
-
}
|
|
189
|
+
host.logInfo(formatSplitSuccessMessage(mux.backend, splitResult.handle));
|
|
158
190
|
if (wantWait && splitResult.sentinelPath) {
|
|
159
|
-
const waitedExitCode = await
|
|
191
|
+
const waitedExitCode = await sentinelMgr.waitForExit(splitResult.sentinelPath);
|
|
160
192
|
host.exit(waitedExitCode ?? 1);
|
|
161
193
|
}
|
|
162
194
|
return;
|
|
163
195
|
}
|
|
164
196
|
host.logWarning(`Pane split failed (${splitResult.reason}), launching directly`);
|
|
165
|
-
|
|
197
|
+
// Pure decision: build inline args for fallback
|
|
198
|
+
const fallbackArgs = buildInlineArgs(cliArgs, toolMode, promptText, promptPath);
|
|
199
|
+
exitCode = await spawnInlineWithRetry(cliCommand, fallbackArgs, toolConfig.retryOnQuickExit, host);
|
|
166
200
|
}
|
|
167
201
|
else {
|
|
168
|
-
|
|
202
|
+
// 5b. Create session
|
|
203
|
+
const resolvedPath = findToolPath(cliCommand) ?? findExecutable(cliCommand);
|
|
169
204
|
if (resolvedPath) {
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
205
|
+
// Pure decision: build session request
|
|
206
|
+
const sessionParams = buildSessionRequest({
|
|
207
|
+
cliArgs,
|
|
208
|
+
toolMode,
|
|
209
|
+
promptPath,
|
|
210
|
+
promptText,
|
|
211
|
+
tmuxSessionFlag: flags['tmux-session'],
|
|
212
|
+
cwd,
|
|
213
|
+
now: now(),
|
|
214
|
+
pid,
|
|
215
|
+
});
|
|
216
|
+
host.logInfo(formatSessionLaunchMessage(mux.backend, sessionParams.sessionName, sessionParams.reattach));
|
|
181
217
|
const result = await mux.createSession({
|
|
182
|
-
sessionName,
|
|
183
|
-
reattach,
|
|
218
|
+
sessionName: sessionParams.sessionName,
|
|
219
|
+
reattach: sessionParams.reattach,
|
|
184
220
|
toolPath: resolvedPath,
|
|
185
|
-
toolArgs:
|
|
186
|
-
|
|
221
|
+
toolArgs: sessionParams.toolArgs,
|
|
222
|
+
cwd,
|
|
223
|
+
promptText: sessionParams.promptText,
|
|
187
224
|
});
|
|
188
|
-
if (result.
|
|
189
|
-
exitCode = result.exitCode;
|
|
225
|
+
if (result.launched) {
|
|
226
|
+
exitCode = result.exitCode ?? 0;
|
|
227
|
+
if (wantJson) {
|
|
228
|
+
host.log(JSON.stringify(toJsonLaunchResult(result, exitCode)));
|
|
229
|
+
host.exit(exitCode);
|
|
230
|
+
}
|
|
190
231
|
}
|
|
191
232
|
else {
|
|
233
|
+
// Pure decision: resolve fallback warning
|
|
192
234
|
if (result.reason) {
|
|
193
|
-
|
|
194
|
-
host.logWarning(`${mux.backend} unavailable — launching inline. ${mux.backend === 'psmux' ? 'Install with: winget install psmux' : ''}`);
|
|
195
|
-
}
|
|
196
|
-
else if (result.reason.includes('too old')) {
|
|
197
|
-
host.logWarning(`${result.reason} — launching inline. ${mux.backend === 'psmux' ? 'Update with: winget upgrade psmux' : ''}`);
|
|
198
|
-
}
|
|
199
|
-
else if (mux.backend === 'psmux' && result.reason.includes('attach failed')) {
|
|
200
|
-
host.logWarning(`${result.reason} — launching inline. Recovery: run "psmux kill-server" and relaunch if this persists.`);
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
host.logWarning(`${result.reason} — launching inline`);
|
|
204
|
-
}
|
|
235
|
+
host.logWarning(resolveSessionFallbackWarning(mux.backend, result.reason));
|
|
205
236
|
}
|
|
206
|
-
|
|
237
|
+
const fallbackArgs = buildInlineArgs(cliArgs, toolMode, promptText, promptPath);
|
|
238
|
+
exitCode = await spawnInlineWithRetry(cliCommand, fallbackArgs, toolConfig.retryOnQuickExit, host);
|
|
207
239
|
}
|
|
208
240
|
}
|
|
209
241
|
else {
|
|
210
|
-
host.logWarning(
|
|
211
|
-
|
|
242
|
+
host.logWarning(formatPathWarning(cliCommand));
|
|
243
|
+
const fallbackArgs = buildInlineArgs(cliArgs, toolMode, promptText, promptPath);
|
|
244
|
+
exitCode = await spawnInlineWithRetry(cliCommand, fallbackArgs, toolConfig.retryOnQuickExit, host);
|
|
212
245
|
}
|
|
213
246
|
}
|
|
214
247
|
}
|
|
@@ -218,5 +251,11 @@ export async function executeLaunch(request, dependencies) {
|
|
|
218
251
|
}
|
|
219
252
|
host.error('Unexpected launch failure.', { exit: EXIT_CODES.GENERAL_ERROR });
|
|
220
253
|
}
|
|
254
|
+
finally {
|
|
255
|
+
if (!sentinelOwnershipTransferred) {
|
|
256
|
+
sentinelMgr.cleanupAll();
|
|
257
|
+
}
|
|
258
|
+
promptMgr.cleanup();
|
|
259
|
+
}
|
|
221
260
|
host.exit(exitCode);
|
|
222
261
|
}
|